feat(ocr): integrate progress bar and streaming progress into document page

Replace inline translateOcrProgress with the extracted module. Add
OcrProgressBar below the spinner during OCR. Parse page numbers from
ANALYZING_PAGE progress codes and feed them to the bar. On Done, fill
bar to 100% briefly before clearing the overlay.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-04-13 10:15:55 +02:00
parent 035f9768bd
commit bac67706b9

View File

@@ -8,6 +8,8 @@ import TranscriptionReadView from '$lib/components/TranscriptionReadView.svelte'
import TranscriptionPanelHeader from '$lib/components/TranscriptionPanelHeader.svelte';
import type { TranscriptionBlockData } from '$lib/types';
import { getErrorMessage } from '$lib/errors';
import { translateOcrProgress } from '$lib/ocr/translateOcrProgress';
import OcrProgressBar from '$lib/components/OcrProgressBar.svelte';
let { data } = $props();
@@ -132,27 +134,9 @@ let ocrRunning = $state(false);
let ocrProgressMessage = $state('');
let ocrErrorMessage = $state('');
let ocrPollTimer = $state<ReturnType<typeof setInterval> | null>(null);
function translateOcrProgress(code: string): string {
if (!code) return m.ocr_progress_heading();
const [key, param] = code.split(':');
switch (key) {
case 'PREPARING':
return m.ocr_status_preparing();
case 'LOADING':
return m.ocr_status_loading();
case 'ANALYZING':
return m.ocr_status_analyzing();
case 'CREATING_BLOCKS':
return m.ocr_status_creating_blocks({ count: param ?? '0' });
case 'DONE':
return m.ocr_status_done_blocks({ count: param ?? '0' });
case 'ERROR':
return m.ocr_status_error();
default:
return code;
}
}
let ocrCurrentPage = $state(0);
let ocrTotalPages = $state(0);
let ocrSkippedPages = $state(0);
async function triggerOcr(scriptType: string) {
ocrRunning = true;
@@ -186,12 +170,23 @@ function pollOcrJob(jobId: string) {
const res = await fetch(`/api/ocr/jobs/${jobId}`);
if (!res.ok) return;
const job = await res.json();
ocrProgressMessage = job.progressMessage ?? '';
const rawCode = job.progressMessage ?? '';
const progress = translateOcrProgress(rawCode);
ocrProgressMessage = progress.message;
if (progress.currentPage !== undefined) ocrCurrentPage = progress.currentPage;
if (progress.totalPages !== undefined) ocrTotalPages = progress.totalPages;
if (progress.skippedPages !== undefined) ocrSkippedPages = progress.skippedPages;
if (job.status === 'DONE' || job.status === 'FAILED') {
ocrCurrentPage = ocrTotalPages;
if (ocrPollTimer) clearInterval(ocrPollTimer);
ocrPollTimer = null;
ocrRunning = false;
ocrProgressMessage = '';
setTimeout(() => {
ocrRunning = false;
ocrProgressMessage = '';
ocrCurrentPage = 0;
ocrTotalPages = 0;
ocrSkippedPages = 0;
}, 1000);
if (job.status === 'FAILED') {
ocrErrorMessage = m.ocr_status_error();
}
@@ -439,8 +434,13 @@ onMount(() => {
{m.ocr_progress_heading()}
</p>
<p class="mt-2 text-sm text-ink-2">
{translateOcrProgress(ocrProgressMessage)}
{ocrProgressMessage}
</p>
<OcrProgressBar
currentPage={ocrCurrentPage}
totalPages={ocrTotalPages}
skippedPages={ocrSkippedPages}
/>
</div>
{:else if panelMode === 'read'}
<TranscriptionReadView