import { Client, handle_file } from "https://cdn.jsdelivr.net/npm/@gradio/client@2.2.1"; const $ = (id) => document.getElementById(id); // Match Field Report panel height to Document Classification panel (one-shot after fonts load) window.addEventListener("load", () => { const classifyPanel = document.querySelector(".col:first-child > .panel"); const reportPanel = document.querySelector(".col:last-child > .panel"); if (classifyPanel && reportPanel) reportPanel.style.minHeight = classifyPanel.offsetHeight + "px"; }); const SAMPLES = [ { src: "/examples/paper-2.jpg", fmt: "airfix_instruction", lbl: "Instructions A" }, { src: "/examples/paper-3.JPG", fmt: "airfix_instruction", lbl: "Instructions B" }, { src: "/examples/shop-2.png", fmt: "airfix_shop", lbl: "Shop listing" }, { src: "/examples/shop-3.png", fmt: "airfix_shop", lbl: "Colour chart" }, ]; let samplesLoaded = 0; let samplesSettled = 0; const smpBtns = document.querySelectorAll(".smp"); smpBtns.forEach((btn, i) => { const s = SAMPLES[i]; btn.addEventListener("click", () => loadSample(s.src, s.fmt)); const probe = new Image(); probe.onload = () => { btn.style.backgroundImage = `url('${s.src}')`; btn.title = s.lbl; samplesLoaded++; if (++samplesSettled === smpBtns.length && samplesLoaded === 0) document.querySelector(".samples").style.display = "none"; }; probe.onerror = () => { btn.style.display = "none"; if (++samplesSettled === smpBtns.length && samplesLoaded === 0) document.querySelector(".samples").style.display = "none"; }; probe.src = s.src; }); async function loadSample(src, fmt) { const resp = await fetch(src); const blob = await resp.blob(); const filename = src.split("/").pop(); const file = new File([blob], filename, { type: blob.type }); const dt = new DataTransfer(); dt.items.add(file); $("file").files = dt.files; $("file").dispatchEvent(new Event("change")); $("format").value = fmt; } // On file select: swap the dropzone for the EXHIBIT A evidence frame // (dark frame + clip + RECEIVED stamp wrapping the user's uploaded image). let previewUrl = null; $("file").addEventListener("change", () => { const f = $("file").files[0]; const preview = $("preview"); const dropzone = $("dropzone"); const evidence = $("evidence"); if (previewUrl) { URL.revokeObjectURL(previewUrl); previewUrl = null; } if (f) { previewUrl = URL.createObjectURL(f); preview.src = previewUrl; $("src-name").textContent = "SRC: " + f.name; dropzone.style.display = "none"; evidence.classList.add("on"); } else { preview.removeAttribute("src"); $("src-name").textContent = "SRC: —"; dropzone.style.display = ""; evidence.classList.remove("on"); } // Reset the right side to STANDBY (radar) before the next analysis. $("reportIdle").style.display = ""; $("report").style.display = "none"; $("reportToggle").style.display = "none"; }); async function run() { const file = $("file").files[0]; const report = $("report"); const scan = $("scan"); // Always swap radar idle for the report text element before reporting anything. $("reportIdle").style.display = "none"; report.style.display = ""; $("reportToggle").style.display = "none"; if (!file) { report.classList.remove("pulse"); report.classList.add("alert"); report.textContent = "No image provided."; return; } const format_id = $("format").value; $("analyze").disabled = true; $("manifest").innerHTML = '
Awaiting resupply manifest…
'; scan.classList.add("on"); report.classList.remove("alert"); report.classList.add("pulse"); report.textContent = "▸ Establishing uplink to field unit…"; try { const client = await Client.connect(window.location.origin); const job = client.submit("/analyze", { image: handle_file(file), format_id }); let finalReceived = false; for await (const msg of job) { if (msg.type !== "data") continue; const [text, manifest] = msg.data; // tuple yielded by the backend if (manifest && manifest !== "") { // final event: manifest non-empty finalReceived = true; report.classList.remove("pulse"); report.textContent = text; $("manifest").innerHTML = manifest; // Collapse only when real codes were found. The empty/timeout/error // returns from _run_analysis are

with no
  • , so the raw // report stays expanded (it's then the only useful output). if (/
  • { const report = $("report"); const expanded = report.style.display !== "none"; report.style.display = expanded ? "none" : ""; $("reportToggle").setAttribute("aria-expanded", String(!expanded)); $("reportCaret").textContent = expanded ? "▸" : "▾"; }); $("analyze").addEventListener("click", run);