diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 39ca412..6d08cc1 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -39,6 +39,9 @@ function App() { // Job metadata const [metadata, setMetadata] = useState({ author: '', book: '', chapter: '', page: '' }) + // Editable OCR text (for plain_ocr mode, editable before commit) + const [editedOcrText, setEditedOcrText] = useState('') + // Job commit state const [commitLoading, setCommitLoading] = useState(false) const [commitResult, setCommitResult] = useState(null) @@ -64,6 +67,7 @@ function App() { setImagePreview(fileType === 'image' ? URL.createObjectURL(file) : file) setError(null) setResult(null) + setEditedOcrText('') setCommitResult(null) } }, [imagePreview, fileType]) @@ -95,6 +99,8 @@ function App() { headers: { 'Content-Type': 'multipart/form-data' }, }) setResult(response.data) + setEditedOcrText(response.data.text || '') + setCommitResult(null) } catch (err) { setError(err.response?.data?.detail || err.message || 'An error occurred') } finally { @@ -103,7 +109,7 @@ function App() { } const handleCommitJob = useCallback(async () => { - if (!image || !result?.text) return + if (!image) return setCommitLoading(true) setCommitResult(null) try { @@ -113,7 +119,7 @@ function App() { formData.append('book', metadata.book) formData.append('chapter', metadata.chapter) formData.append('page', metadata.page) - formData.append('ocr_text', result.text) + formData.append('ocr_text', editedOcrText) formData.append('mode', mode) const response = await axios.post(`${API_BASE}/jobs`, formData, { @@ -125,16 +131,18 @@ function App() { } finally { setCommitLoading(false) } - }, [image, result, metadata, mode]) + }, [image, editedOcrText, metadata, mode]) const handleCopy = useCallback(() => { - if (result?.text) navigator.clipboard.writeText(result.text) - }, [result]) + const text = editedOcrText || result?.text + if (text) navigator.clipboard.writeText(text) + }, [editedOcrText, result]) const handleDownload = useCallback(() => { - if (!result?.text) return + const text = editedOcrText || result?.text + if (!text) return const ext = { plain_ocr: 'txt', describe: 'txt', find_ref: 'txt', freeform: 'txt' }[mode] || 'txt' - const blob = new Blob([result.text], { type: 'text/plain' }) + const blob = new Blob([text], { type: 'text/plain' }) const url = URL.createObjectURL(blob) const a = document.createElement('a') a.href = url @@ -391,6 +399,8 @@ function App() { onCommitJob={mode === 'plain_ocr' && result ? handleCommitJob : null} commitLoading={commitLoading} commitResult={commitResult} + editedOcrText={editedOcrText} + onOcrTextChange={setEditedOcrText} /> diff --git a/frontend/src/components/ResultPanel.jsx b/frontend/src/components/ResultPanel.jsx index 0867e7c..b415e6a 100644 --- a/frontend/src/components/ResultPanel.jsx +++ b/frontend/src/components/ResultPanel.jsx @@ -4,7 +4,7 @@ import { Copy, Download, Sparkles, Loader2, CheckCircle2, ChevronDown, Database import ReactMarkdown from 'react-markdown' import DOMPurify from 'dompurify' -export default function ResultPanel({ result, loading, imagePreview, onCopy, onDownload, onCommitJob, commitLoading, commitResult }) { +export default function ResultPanel({ result, loading, imagePreview, onCopy, onDownload, onCommitJob, commitLoading, commitResult, editedOcrText, onOcrTextChange }) { const canvasRef = useRef(null) const imgRef = useRef(null) const [showAdvanced, setShowAdvanced] = useState(false) @@ -226,26 +226,37 @@ export default function ResultPanel({ result, loading, imagePreview, onCopy, onD )} - {/* Text result */} -
OCR Text (editable — correct before committing)
+
+ {result.text}
+
+ )}
+