From 7331fc5936a637da283e2db9b66516277c364fb3 Mon Sep 17 00:00:00 2001 From: Alex-Gilbert Date: Fri, 20 Feb 2026 12:43:09 -0600 Subject: [PATCH] feat: add OCR-on-upload and Detect Redactions button Co-Authored-By: Claude Opus 4.6 --- unredact/static/dom.js | 1 + unredact/static/index.html | 1 + unredact/static/main.js | 45 +++++++++++++++++++++++++++++++++++--- unredact/static/state.js | 1 + unredact/static/style.css | 19 ++++++++++++++++ 5 files changed, 64 insertions(+), 3 deletions(-) diff --git a/unredact/static/dom.js b/unredact/static/dom.js index 7f26a2f..9c7383d 100644 --- a/unredact/static/dom.js +++ b/unredact/static/dom.js @@ -12,6 +12,7 @@ export const pageInfo = document.getElementById("page-info"); export const prevBtn = /** @type {HTMLButtonElement} */ (document.getElementById("prev-page")); export const nextBtn = /** @type {HTMLButtonElement} */ (document.getElementById("next-page")); export const redactionListEl = document.getElementById("redaction-list"); +export const detectBtn = /** @type {HTMLButtonElement} */ (document.getElementById("detect-btn")); export const zoomInBtn = document.getElementById("zoom-in"); export const zoomOutBtn = document.getElementById("zoom-out"); export const zoomFitBtn = document.getElementById("zoom-fit"); diff --git a/unredact/static/index.html b/unredact/static/index.html index 634f0c4..70aa01a 100644 --- a/unredact/static/index.html +++ b/unredact/static/index.html @@ -34,6 +34,7 @@
+
diff --git a/unredact/static/main.js b/unredact/static/main.js index 4a72fc1..6027f0c 100644 --- a/unredact/static/main.js +++ b/unredact/static/main.js @@ -4,7 +4,7 @@ import { state } from './state.js'; import { dropZone, fileInput, uploadSection, viewerSection, docImage, - canvas, pageInfo, prevBtn, nextBtn, redactionListEl, + canvas, pageInfo, prevBtn, nextBtn, redactionListEl, detectBtn, rightPanel, fontSelect, solveAccept, gapValue, showToast, } from './dom.js'; @@ -96,8 +96,8 @@ async function uploadFile(file) { // Load the first page image and controls immediately await loadPage(1); - // Start background analysis via SSE - startAnalysisSSE(); + // Start background OCR via SSE + startOcrSSE(); } /** @@ -120,12 +120,51 @@ function startAnalysisSSE() { } else if (data.event === "done") { es.close(); showToast("Analysis complete"); + if (detectBtn) { + detectBtn.disabled = false; + detectBtn.textContent = "Detect Redactions"; + } } }); es.addEventListener("error", () => { es.close(); showToast("Analysis connection lost", "error"); + if (detectBtn) { + detectBtn.disabled = false; + detectBtn.textContent = "Detect Redactions"; + } + }); +} + +function startOcrSSE() { + const es = new EventSource(`/api/doc/${state.docId}/ocr`); + showToast("Running OCR...", "info"); + + es.onmessage = (e) => { + const data = JSON.parse(e.data); + if (data.event === "page_ocr_complete") { + // OCR cached for this page on the backend + } else if (data.event === "ocr_complete") { + es.close(); + state.ocrReady = true; + showToast("OCR complete — ready to detect redactions", "success"); + if (detectBtn) detectBtn.disabled = false; + } else if (data.event === "error") { + showToast(`OCR error on page ${data.page}: ${data.message}`, "error"); + } + }; + es.onerror = () => { + es.close(); + showToast("OCR connection lost", "error"); + }; +} + +if (detectBtn) { + detectBtn.addEventListener("click", () => { + detectBtn.disabled = true; + detectBtn.textContent = "Detecting..."; + startAnalysisSSE(); }); } diff --git a/unredact/static/state.js b/unredact/static/state.js index 312a031..48ca08b 100644 --- a/unredact/static/state.js +++ b/unredact/static/state.js @@ -10,6 +10,7 @@ export const state = { activeRedaction: null, fonts: [], fontsReady: false, + ocrReady: false, zoom: 1, panX: 0, panY: 0, diff --git a/unredact/static/style.css b/unredact/static/style.css index ee3d8aa..55f74dd 100644 --- a/unredact/static/style.css +++ b/unredact/static/style.css @@ -147,6 +147,25 @@ main { padding: 0.5rem 0; } +#detect-btn { + width: 100%; + padding: 8px 12px; + margin-bottom: 8px; + background: #2563eb; + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + font-size: 14px; +} +#detect-btn:hover:not(:disabled) { + background: #1d4ed8; +} +#detect-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + /* Redaction list items */ .redaction-item { padding: 0.5rem 0.75rem;