diff --git a/admin-lehrer/app/(admin)/ai/ocr-kombi/page.tsx b/admin-lehrer/app/(admin)/ai/ocr-kombi/page.tsx index a7e7b8d..45d587e 100644 --- a/admin-lehrer/app/(admin)/ai/ocr-kombi/page.tsx +++ b/admin-lehrer/app/(admin)/ai/ocr-kombi/page.tsx @@ -2,7 +2,6 @@ import { Suspense } from 'react' import { PagePurpose } from '@/components/common/PagePurpose' -import { BoxSessionTabs } from '@/components/ocr-pipeline/BoxSessionTabs' import { KombiStepper } from '@/components/ocr-kombi/KombiStepper' import { SessionList } from '@/components/ocr-kombi/SessionList' import { SessionHeader } from '@/components/ocr-kombi/SessionHeader' @@ -27,8 +26,6 @@ function OcrKombiContent() { loadingSessions, activeCategory, isGroundTruth, - subSessions, - parentSessionId, steps, gridSaveRef, groupedSessions, @@ -40,11 +37,8 @@ function OcrKombiContent() { deleteSession, renameSession, updateCategory, - handleSessionChange, setSessionId, setSessionName, - setSubSessions, - setParentSessionId, setIsGroundTruth, } = useKombiPipeline() @@ -75,17 +69,11 @@ function OcrKombiContent() { { - // If sub-sessions were created, switch to the first one - if (subSessions.length > 0) { - setSessionId(subSessions[0].id) - setSessionName(subSessions[0].name) - } - handleNext() - }} - onSubSessionsCreated={(subs) => { - setSubSessions(subs) - if (sessionId) setParentSessionId(sessionId) + onNext={handleNext} + onSplitComplete={(childId, childName) => { + // Switch to the first child session and refresh the list + setSessionId(childId) + setSessionName(childName) loadSessions() }} /> @@ -161,15 +149,6 @@ function OcrKombiContent() { onStepClick={handleStepClick} /> - {subSessions.length > 0 && parentSessionId && sessionId && ( - - )} -
{renderStep()}
) diff --git a/admin-lehrer/app/(admin)/ai/ocr-kombi/types.ts b/admin-lehrer/app/(admin)/ai/ocr-kombi/types.ts index 69b13dc..ab949e9 100644 --- a/admin-lehrer/app/(admin)/ai/ocr-kombi/types.ts +++ b/admin-lehrer/app/(admin)/ai/ocr-kombi/types.ts @@ -8,7 +8,6 @@ export { DOCUMENT_CATEGORIES } from '../ocr-pipeline/types' export type { SessionListItem, SessionInfo, - SubSession, OrientationResult, CropResult, DeskewResult, diff --git a/admin-lehrer/app/(admin)/ai/ocr-kombi/useKombiPipeline.ts b/admin-lehrer/app/(admin)/ai/ocr-kombi/useKombiPipeline.ts index 2bea943..3f5c5fa 100644 --- a/admin-lehrer/app/(admin)/ai/ocr-kombi/useKombiPipeline.ts +++ b/admin-lehrer/app/(admin)/ai/ocr-kombi/useKombiPipeline.ts @@ -4,7 +4,7 @@ import { useCallback, useEffect, useState, useRef } from 'react' import { useSearchParams } from 'next/navigation' import type { PipelineStep, DocumentCategory } from './types' import { KOMBI_V2_STEPS, dbStepToKombiV2Ui } from './types' -import type { SubSession, SessionListItem } from '../ocr-pipeline/types' +import type { SessionListItem } from '../ocr-pipeline/types' export type { SessionListItem } @@ -33,8 +33,6 @@ export function useKombiPipeline() { const [loadingSessions, setLoadingSessions] = useState(true) const [activeCategory, setActiveCategory] = useState(undefined) const [isGroundTruth, setIsGroundTruth] = useState(false) - const [subSessions, setSubSessions] = useState([]) - const [parentSessionId, setParentSessionId] = useState(null) const [steps, setSteps] = useState(initSteps()) const searchParams = useSearchParams() @@ -115,7 +113,7 @@ export function useKombiPipeline() { // ---- Open session ---- - const openSession = useCallback(async (sid: string, keepSubSessions?: boolean) => { + const openSession = useCallback(async (sid: string) => { try { const res = await fetch(`${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sid}`) if (!res.ok) return @@ -126,17 +124,6 @@ export function useKombiPipeline() { setActiveCategory(data.document_category || undefined) setIsGroundTruth(!!data.ground_truth?.build_grid_reference) - // Sub-session handling - if (data.sub_sessions?.length > 0) { - setSubSessions(data.sub_sessions) - setParentSessionId(sid) - } else if (data.parent_session_id) { - setParentSessionId(data.parent_session_id) - } else if (!keepSubSessions) { - setSubSessions([]) - setParentSessionId(null) - } - // Determine UI step from DB state const dbStep = data.current_step || 1 const hasGrid = !!data.grid_editor_result @@ -159,22 +146,10 @@ export function useKombiPipeline() { uiStep = 1 } - const skipIds: string[] = [] - const isSubSession = !!data.parent_session_id - if (isSubSession && dbStep >= 5) { - skipIds.push('upload', 'orientation', 'page-split', 'deskew', 'dewarp', 'content-crop') - if (uiStep < 6) uiStep = 6 - } else if (isSubSession && dbStep >= 2) { - skipIds.push('upload', 'orientation') - if (uiStep < 2) uiStep = 2 - } - setSteps( KOMBI_V2_STEPS.map((s, i) => ({ ...s, - status: skipIds.includes(s.id) - ? 'skipped' - : i < uiStep ? 'completed' : i === uiStep ? 'active' : 'pending', + status: i < uiStep ? 'completed' : i === uiStep ? 'active' : 'pending', })), ) setCurrentStep(uiStep) @@ -226,8 +201,6 @@ export function useKombiPipeline() { setSteps(initSteps()) setCurrentStep(0) setSessionId(null) - setSubSessions([]) - setParentSessionId(null) loadSessions() return } @@ -249,8 +222,6 @@ export function useKombiPipeline() { setSessionId(null) setSessionName('') setCurrentStep(0) - setSubSessions([]) - setParentSessionId(null) setSteps(initSteps()) }, []) @@ -292,40 +263,6 @@ export function useKombiPipeline() { } }, [sessionId]) - // ---- Orientation completion (checks for page-split sub-sessions) ---- - - const handleOrientationComplete = useCallback(async (sid: string) => { - setSessionId(sid) - loadSessions() - - try { - const res = await fetch(`${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sid}`) - if (res.ok) { - const data = await res.json() - if (data.sub_sessions?.length > 0) { - const subs: SubSession[] = data.sub_sessions.map((s: SubSession) => ({ - id: s.id, - name: s.name, - box_index: s.box_index, - current_step: s.current_step, - })) - setSubSessions(subs) - setParentSessionId(sid) - openSession(subs[0].id, true) - return - } - } - } catch (e) { - console.error('Failed to check for sub-sessions:', e) - } - - handleNext() - }, [loadSessions, openSession, handleNext]) - - const handleSessionChange = useCallback((newSessionId: string) => { - openSession(newSessionId, true) - }, [openSession]) - return { // State currentStep, @@ -335,8 +272,6 @@ export function useKombiPipeline() { loadingSessions, activeCategory, isGroundTruth, - subSessions, - parentSessionId, steps, gridSaveRef, // Computed @@ -351,11 +286,7 @@ export function useKombiPipeline() { deleteSession, renameSession, updateCategory, - handleOrientationComplete, - handleSessionChange, setSessionId, - setSubSessions, - setParentSessionId, setSessionName, setIsGroundTruth, } diff --git a/admin-lehrer/components/ocr-kombi/StepPageSplit.tsx b/admin-lehrer/components/ocr-kombi/StepPageSplit.tsx index 7899c7b..b891e8f 100644 --- a/admin-lehrer/components/ocr-kombi/StepPageSplit.tsx +++ b/admin-lehrer/components/ocr-kombi/StepPageSplit.tsx @@ -1,8 +1,6 @@ 'use client' import { useState, useEffect, useRef } from 'react' -import type { SubSession } from '@/app/(admin)/ai/ocr-pipeline/types' - const KLAUSUR_API = '/klausur-api' interface PageSplitResult { @@ -18,10 +16,10 @@ interface StepPageSplitProps { sessionId: string | null sessionName: string onNext: () => void - onSubSessionsCreated: (subs: SubSession[]) => void + onSplitComplete: (firstChildId: string, firstChildName: string) => void } -export function StepPageSplit({ sessionId, sessionName, onNext, onSubSessionsCreated }: StepPageSplitProps) { +export function StepPageSplit({ sessionId, sessionName, onNext, onSplitComplete }: StepPageSplitProps) { const [detecting, setDetecting] = useState(false) const [splitResult, setSplitResult] = useState(null) const [error, setError] = useState('') @@ -40,30 +38,33 @@ export function StepPageSplit({ sessionId, sessionName, onNext, onSubSessionsCre setDetecting(true) setError('') try { - // First check if sub-sessions already exist + // First check if this session was already split (status='split') const sessionRes = await fetch(`${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}`) if (sessionRes.ok) { const sessionData = await sessionRes.json() - if (sessionData.sub_sessions?.length > 0) { - // Already split — show existing sub-sessions - const subs = sessionData.sub_sessions as { id: string; name: string; page_index?: number; box_index?: number; current_step?: number }[] - setSplitResult({ - multi_page: true, - page_count: subs.length, - sub_sessions: subs.map((s: { id: string; name: string; page_index?: number; box_index?: number }) => ({ - id: s.id, - name: s.name, - page_index: s.page_index ?? s.box_index ?? 0, - })), - }) - onSubSessionsCreated(subs.map((s: { id: string; name: string; page_index?: number; box_index?: number; current_step?: number }) => ({ - id: s.id, - name: s.name, - box_index: s.page_index ?? s.box_index ?? 0, - current_step: s.current_step ?? 2, - }))) - setDetecting(false) - return + if (sessionData.status === 'split' && sessionData.crop_result?.multi_page) { + // Already split — find the child sessions in the session list + const listRes = await fetch(`${KLAUSUR_API}/api/v1/ocr-pipeline/sessions`) + if (listRes.ok) { + const listData = await listRes.json() + // Child sessions have names like "ParentName — Seite N" + const baseName = sessionName || sessionData.name || '' + const children = (listData.sessions || []) + .filter((s: { name?: string }) => s.name?.startsWith(baseName + ' — ')) + .sort((a: { name: string }, b: { name: string }) => a.name.localeCompare(b.name)) + if (children.length > 0) { + setSplitResult({ + multi_page: true, + page_count: children.length, + sub_sessions: children.map((s: { id: string; name: string }, i: number) => ({ + id: s.id, name: s.name, page_index: i, + })), + }) + onSplitComplete(children[0].id, children[0].name) + setDetecting(false) + return + } + } } } @@ -92,12 +93,8 @@ export function StepPageSplit({ sessionId, sessionName, onNext, onSubSessionsCre sub.name = newName } - onSubSessionsCreated(data.sub_sessions.map(s => ({ - id: s.id, - name: s.name, - box_index: s.page_index, - current_step: 2, - }))) + // Signal parent to switch to the first child session + onSplitComplete(data.sub_sessions[0].id, data.sub_sessions[0].name) } } catch (e) { setError(e instanceof Error ? e.message : String(e))