diff --git a/apps/client/src/widgets/type_widgets/options/media.tsx b/apps/client/src/widgets/type_widgets/options/media.tsx index 098e71176f..ebdb179289 100644 --- a/apps/client/src/widgets/type_widgets/options/media.tsx +++ b/apps/client/src/widgets/type_widgets/options/media.tsx @@ -1,4 +1,8 @@ +import { useCallback, useEffect, useRef, useState } from "preact/hooks"; + import { t } from "../../../services/i18n"; +import server from "../../../services/server"; +import toast from "../../../services/toast"; import { FormTextBoxWithUnit } from "../../react/FormTextBox"; import FormToggle from "../../react/FormToggle"; import { useTriliumOption, useTriliumOptionBool } from "../../react/hooks"; @@ -92,6 +96,83 @@ function OcrSettings() { onChange={setOcrMinConfidence} /> + + ); } + +interface BatchProgress { + inProgress: boolean; + total: number; + processed: number; + percentage?: number; +} + +function BatchProcessing() { + const [ progress, setProgress ] = useState(null); + const pollingRef = useRef>(null); + + const pollProgress = useCallback(() => { + server.get("ocr/batch-progress").then((data) => { + setProgress(data); + if (!data.inProgress && pollingRef.current) { + clearInterval(pollingRef.current); + pollingRef.current = null; + toast.showMessage(t("images.batch_ocr_completed", { processed: data.processed })); + } + }); + }, []); + + // Clean up polling on unmount. + useEffect(() => { + return () => { + if (pollingRef.current) { + clearInterval(pollingRef.current); + } + }; + }, []); + + async function startBatch() { + try { + const result = await server.post<{ success: boolean; message?: string }>("ocr/batch-process"); + if (result.success) { + toast.showMessage(t("images.batch_ocr_starting")); + pollingRef.current = setInterval(pollProgress, 2000); + pollProgress(); + } else { + toast.showError(result.message || t("images.batch_ocr_error", { error: "Unknown" })); + } + } catch { + // Server errors are already shown as toasts by server.ts. + } + } + + const isRunning = progress?.inProgress ?? false; + + return ( + + {isRunning ? ( +
+
+
+ {t("images.batch_ocr_progress", { processed: progress?.processed ?? 0, total: progress?.total ?? 0 })} +
+
+
+ ) : ( + + )} +
+ ); +}