Python (6 files in klausur-service): - rbac.py (1,132 → 4), admin_api.py (1,012 → 4) - routes/eh.py (1,111 → 4), ocr_pipeline_geometry.py (1,105 → 5) Python (2 files in backend-lehrer): - unit_api.py (1,226 → 6), game_api.py (1,129 → 5) Website (6 page files): - 4x klausur-korrektur pages (1,249-1,328 LOC each) → shared components in website/components/klausur-korrektur/ (17 shared files) - companion (1,057 → 10), magic-help (1,017 → 8) All re-export barrels preserve backward compatibility. Zero import errors verified. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
105 lines
4.7 KiB
TypeScript
105 lines
4.7 KiB
TypeScript
'use client'
|
|
|
|
import type { OCRResult } from './types'
|
|
|
|
interface OcrTestTabProps {
|
|
ocrResult: OCRResult | null
|
|
ocrLoading: boolean
|
|
handleFileUpload: (file: File) => void
|
|
}
|
|
|
|
export default function OcrTestTab({ ocrResult, ocrLoading, handleFileUpload }: OcrTestTabProps) {
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* OCR Test */}
|
|
<div className="bg-gray-800/50 border border-gray-700 rounded-xl p-6">
|
|
<h2 className="text-lg font-semibold text-white mb-4">OCR Test</h2>
|
|
<p className="text-sm text-gray-400 mb-4">
|
|
Teste die Handschrifterkennung mit einem eigenen Bild. Das Ergebnis zeigt
|
|
den erkannten Text, Konfidenz und Verarbeitungszeit.
|
|
</p>
|
|
|
|
<div
|
|
className="border-2 border-dashed border-gray-600 rounded-lg p-8 text-center cursor-pointer hover:border-blue-500 transition-colors"
|
|
onClick={() => document.getElementById('ocr-file-input')?.click()}
|
|
onDragOver={(e) => { e.preventDefault(); e.currentTarget.classList.add('border-blue-500') }}
|
|
onDragLeave={(e) => { e.currentTarget.classList.remove('border-blue-500') }}
|
|
onDrop={(e) => {
|
|
e.preventDefault()
|
|
e.currentTarget.classList.remove('border-blue-500')
|
|
const file = e.dataTransfer.files[0]
|
|
if (file?.type.startsWith('image/')) handleFileUpload(file)
|
|
}}
|
|
>
|
|
<div className="text-4xl mb-2">📄</div>
|
|
<div className="text-gray-300">Bild hierher ziehen oder klicken zum Hochladen</div>
|
|
<div className="text-xs text-gray-500 mt-1">PNG, JPG - Handgeschriebener Text</div>
|
|
</div>
|
|
<input
|
|
type="file"
|
|
id="ocr-file-input"
|
|
accept="image/*"
|
|
className="hidden"
|
|
onChange={(e) => {
|
|
const file = e.target.files?.[0]
|
|
if (file) handleFileUpload(file)
|
|
}}
|
|
/>
|
|
|
|
{ocrLoading && (
|
|
<div className="mt-4 flex items-center gap-2 text-gray-400">
|
|
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-white"></div>
|
|
Analysiere Bild...
|
|
</div>
|
|
)}
|
|
|
|
{ocrResult && (
|
|
<div className="mt-4 bg-gray-900/50 rounded-lg p-4">
|
|
<h3 className="text-sm font-medium text-gray-300 mb-2">Erkannter Text:</h3>
|
|
<pre className="bg-gray-950 p-3 rounded text-sm text-white whitespace-pre-wrap max-h-48 overflow-y-auto">
|
|
{ocrResult.text || '(Kein Text erkannt)'}
|
|
</pre>
|
|
<div className="mt-3 grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
|
|
<div className="bg-gray-800 rounded p-2">
|
|
<div className="text-gray-400 text-xs">Konfidenz</div>
|
|
<div className="text-white font-medium">{(ocrResult.confidence * 100).toFixed(1)}%</div>
|
|
</div>
|
|
<div className="bg-gray-800 rounded p-2">
|
|
<div className="text-gray-400 text-xs">Verarbeitungszeit</div>
|
|
<div className="text-white font-medium">{ocrResult.processing_time_ms}ms</div>
|
|
</div>
|
|
<div className="bg-gray-800 rounded p-2">
|
|
<div className="text-gray-400 text-xs">Modell</div>
|
|
<div className="text-white font-medium">{ocrResult.model || 'TrOCR'}</div>
|
|
</div>
|
|
<div className="bg-gray-800 rounded p-2">
|
|
<div className="text-gray-400 text-xs">LoRA Adapter</div>
|
|
<div className="text-white font-medium">{ocrResult.has_lora_adapter ? 'Ja' : 'Nein'}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Confidence Interpretation */}
|
|
<div className="bg-gray-800/50 border border-gray-700 rounded-xl p-6">
|
|
<h2 className="text-lg font-semibold text-white mb-4">Konfidenz-Interpretation</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
|
<div className="bg-green-900/20 border border-green-800 rounded-lg p-4">
|
|
<div className="text-green-400 font-medium">90-100%</div>
|
|
<div className="text-sm text-gray-300 mt-1">Sehr hohe Sicherheit - Text kann direkt übernommen werden</div>
|
|
</div>
|
|
<div className="bg-yellow-900/20 border border-yellow-800 rounded-lg p-4">
|
|
<div className="text-yellow-400 font-medium">70-90%</div>
|
|
<div className="text-sm text-gray-300 mt-1">Gute Sicherheit - manuelle Überprüfung empfohlen</div>
|
|
</div>
|
|
<div className="bg-red-900/20 border border-red-800 rounded-lg p-4">
|
|
<div className="text-red-400 font-medium">< 70%</div>
|
|
<div className="text-sm text-gray-300 mt-1">Niedrige Sicherheit - manuelle Eingabe erforderlich</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|