'use client' import { useState, useCallback } from 'react' import { useTheme } from '@/lib/ThemeContext' import { useWorksheet } from '@/lib/worksheet-editor/WorksheetContext' import { UploadStep, PreviewStep, ResultStep } from './CleanupSteps' interface CleanupPanelProps { isOpen: boolean onClose: () => void } interface CleanupCapabilities { opencv_available: boolean lama_available: boolean paddleocr_available: boolean } export interface PreviewResult { has_handwriting: boolean confidence: number handwriting_ratio: number image_width: number image_height: number estimated_times_ms: { detection: number inpainting: number reconstruction: number total: number } capabilities: { lama_available: boolean } } export interface PipelineResult { success: boolean handwriting_detected: boolean handwriting_removed: boolean layout_reconstructed: boolean cleaned_image_base64?: string fabric_json?: any metadata: any } export function CleanupPanel({ isOpen, onClose }: CleanupPanelProps) { const { isDark } = useTheme() const { canvas, saveToHistory } = useWorksheet() const [file, setFile] = useState(null) const [previewUrl, setPreviewUrl] = useState(null) const [cleanedUrl, setCleanedUrl] = useState(null) const [maskUrl, setMaskUrl] = useState(null) const [isPreviewing, setIsPreviewing] = useState(false) const [isProcessing, setIsProcessing] = useState(false) const [error, setError] = useState(null) const [previewResult, setPreviewResult] = useState(null) const [pipelineResult, setPipelineResult] = useState(null) const [capabilities, setCapabilities] = useState(null) // Options const [removeHandwriting, setRemoveHandwriting] = useState(true) const [reconstructLayout, setReconstructLayout] = useState(true) const [inpaintingMethod, setInpaintingMethod] = useState('auto') // Step tracking const [currentStep, setCurrentStep] = useState<'upload' | 'preview' | 'result'>('upload') const getApiUrl = useCallback(() => { if (typeof window === 'undefined') return 'http://localhost:8086' const { hostname, protocol } = window.location return hostname === 'localhost' ? 'http://localhost:8086' : `${protocol}//${hostname}:8086` }, []) const loadCapabilities = useCallback(async () => { try { const response = await fetch(`${getApiUrl()}/api/v1/worksheet/capabilities`) if (response.ok) { const data = await response.json() setCapabilities(data) } } catch (err) { console.error('Failed to load capabilities:', err) } }, [getApiUrl]) const handleFileSelect = useCallback((selectedFile: File) => { setFile(selectedFile) setError(null) setPreviewResult(null) setPipelineResult(null) setCleanedUrl(null) setMaskUrl(null) const url = URL.createObjectURL(selectedFile) setPreviewUrl(url) setCurrentStep('upload') }, []) const handleDrop = useCallback((e: React.DragEvent) => { e.preventDefault() const droppedFile = e.dataTransfer.files[0] if (droppedFile && droppedFile.type.startsWith('image/')) { handleFileSelect(droppedFile) } }, [handleFileSelect]) const handlePreview = useCallback(async () => { if (!file) return setIsPreviewing(true) setError(null) try { const formData = new FormData() formData.append('image', file) const response = await fetch(`${getApiUrl()}/api/v1/worksheet/preview-cleanup`, { method: 'POST', body: formData }) if (!response.ok) throw new Error(`HTTP ${response.status}`) const result = await response.json() setPreviewResult(result) setCurrentStep('preview') await loadCapabilities() } catch (err) { console.error('Preview failed:', err) setError(err instanceof Error ? err.message : 'Vorschau fehlgeschlagen') } finally { setIsPreviewing(false) } }, [file, getApiUrl, loadCapabilities]) const handleCleanup = useCallback(async () => { if (!file) return setIsProcessing(true) setError(null) try { const formData = new FormData() formData.append('image', file) formData.append('remove_handwriting', String(removeHandwriting)) formData.append('reconstruct', String(reconstructLayout)) formData.append('inpainting_method', inpaintingMethod) const response = await fetch(`${getApiUrl()}/api/v1/worksheet/cleanup-pipeline`, { method: 'POST', body: formData }) if (!response.ok) { const errorData = await response.json().catch(() => ({ detail: 'Unknown error' })) throw new Error(errorData.detail || `HTTP ${response.status}`) } const result: PipelineResult = await response.json() setPipelineResult(result) if (result.cleaned_image_base64) { const cleanedBlob = await fetch(`data:image/png;base64,${result.cleaned_image_base64}`).then(r => r.blob()) setCleanedUrl(URL.createObjectURL(cleanedBlob)) } setCurrentStep('result') } catch (err) { console.error('Cleanup failed:', err) setError(err instanceof Error ? err.message : 'Bereinigung fehlgeschlagen') } finally { setIsProcessing(false) } }, [file, removeHandwriting, reconstructLayout, inpaintingMethod, getApiUrl]) const handleImportToCanvas = useCallback(async () => { if (!pipelineResult?.fabric_json || !canvas) return try { canvas.clear() canvas.loadFromJSON(pipelineResult.fabric_json, () => { canvas.renderAll() saveToHistory('Imported: Cleaned worksheet') }) onClose() } catch (err) { console.error('Import failed:', err) setError('Import in Canvas fehlgeschlagen') } }, [pipelineResult, canvas, saveToHistory, onClose]) const handleGetMask = useCallback(async () => { if (!file) return try { const formData = new FormData() formData.append('image', file) const response = await fetch(`${getApiUrl()}/api/v1/worksheet/detect-handwriting/mask`, { method: 'POST', body: formData }) if (!response.ok) throw new Error(`HTTP ${response.status}`) const blob = await response.blob() setMaskUrl(URL.createObjectURL(blob)) } catch (err) { console.error('Mask fetch failed:', err) } }, [file, getApiUrl]) if (!isOpen) return null const overlayStyle = 'fixed inset-0 bg-black/50 backdrop-blur-sm z-50' const modalStyle = isDark ? 'backdrop-blur-xl bg-white/10 border border-white/20' : 'backdrop-blur-xl bg-white/90 border border-black/10 shadow-2xl' const labelStyle = isDark ? 'text-white/70' : 'text-slate-600' const cardStyle = isDark ? 'bg-white/5 border-white/10 hover:bg-white/10' : 'bg-white/50 border-slate-200 hover:bg-slate-50' const stepNames = ['upload', 'preview', 'result'] as const const stepIndex = stepNames.indexOf(currentStep) return (
e.stopPropagation()} > {/* Header */}

Arbeitsblatt bereinigen

Handschrift entfernen und Layout rekonstruieren

{/* Step Indicator */}
{stepNames.map((step, idx) => (
{idx < stepIndex ? '✓' : idx + 1}
{idx < 2 && (
)}
))}
{/* Content */}
{error && (
{error}
)} {currentStep === 'upload' && ( )} {currentStep === 'preview' && previewResult && ( )} {currentStep === 'result' && pipelineResult && ( )}
{/* Footer */}
{currentStep !== 'upload' && ( )}
{currentStep === 'upload' && file && ( )} {currentStep === 'preview' && ( )} {currentStep === 'result' && pipelineResult?.success && ( )}
) }