Some checks failed
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-school (push) Successful in 29s
CI / test-go-edu-search (push) Successful in 28s
CI / test-python-klausur (push) Failing after 2m24s
CI / test-python-agent-core (push) Successful in 22s
CI / test-nodejs-website (push) Successful in 20s
Phase 1 of the clean architecture refactor: Replaces the 751-line ocr-overlay monolith with a modular pipeline. Each step gets its own component file. Frontend: /ai/ocr-kombi route with 11 steps (Upload, Orientation, PageSplit, Deskew, Dewarp, ContentCrop, OCR, Structure, GridBuild, GridReview, GroundTruth). Session list supports document grouping for multi-page uploads. Backend: New ocr_kombi/ module with multi-page PDF upload (splits PDF into N sessions with shared document_group_id). DB migration adds document_group_id and page_number columns. Old /ai/ocr-overlay remains fully functional for A/B testing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
'use client'
|
|
|
|
import { useState } from 'react'
|
|
|
|
const KLAUSUR_API = '/klausur-api'
|
|
|
|
interface StepGroundTruthProps {
|
|
sessionId: string | null
|
|
isGroundTruth: boolean
|
|
onMarked: () => void
|
|
gridSaveRef: React.MutableRefObject<(() => Promise<void>) | null>
|
|
}
|
|
|
|
/**
|
|
* Step 11: Ground Truth marking.
|
|
* Saves the current grid as reference data for regression tests.
|
|
*/
|
|
export function StepGroundTruth({ sessionId, isGroundTruth, onMarked, gridSaveRef }: StepGroundTruthProps) {
|
|
const [saving, setSaving] = useState(false)
|
|
const [message, setMessage] = useState('')
|
|
|
|
const handleMark = async () => {
|
|
if (!sessionId) return
|
|
setSaving(true)
|
|
setMessage('')
|
|
try {
|
|
// Auto-save grid editor before marking
|
|
if (gridSaveRef.current) {
|
|
await gridSaveRef.current()
|
|
}
|
|
const res = await fetch(
|
|
`${KLAUSUR_API}/api/v1/ocr-pipeline/sessions/${sessionId}/mark-ground-truth?pipeline=kombi`,
|
|
{ method: 'POST' },
|
|
)
|
|
if (!res.ok) {
|
|
const body = await res.text().catch(() => '')
|
|
throw new Error(`Ground Truth fehlgeschlagen (${res.status}): ${body}`)
|
|
}
|
|
const data = await res.json()
|
|
setMessage(`Ground Truth gespeichert (${data.cells_saved} Zellen)`)
|
|
onMarked()
|
|
} catch (e) {
|
|
setMessage(e instanceof Error ? e.message : String(e))
|
|
} finally {
|
|
setSaving(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4 p-6 bg-amber-50 dark:bg-amber-900/10 rounded-xl border border-amber-200 dark:border-amber-800">
|
|
<h3 className="text-sm font-medium text-amber-700 dark:text-amber-300">
|
|
Ground Truth
|
|
</h3>
|
|
<p className="text-sm text-amber-600 dark:text-amber-400">
|
|
Markiert die aktuelle Grid-Ausgabe als Referenz fuer Regressionstests.
|
|
{isGroundTruth && ' Diese Session ist bereits als Ground Truth markiert.'}
|
|
</p>
|
|
|
|
<button
|
|
onClick={handleMark}
|
|
disabled={saving}
|
|
className="px-4 py-2 text-sm bg-amber-600 text-white rounded-lg hover:bg-amber-700 disabled:opacity-50"
|
|
>
|
|
{saving ? 'Speichere...' : isGroundTruth ? 'Ground Truth aktualisieren' : 'Als Ground Truth markieren'}
|
|
</button>
|
|
|
|
{message && (
|
|
<div className={`text-sm ${message.includes('fehlgeschlagen') ? 'text-red-500' : 'text-amber-600 dark:text-amber-400'}`}>
|
|
{message}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|