| import { Client, handle_file } from "https://cdn.jsdelivr.net/npm/@gradio/client@2.2.1"; |
|
|
| const $ = (id) => document.getElementById(id); |
|
|
| |
| 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; |
| } |
|
|
| |
| |
| 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"); |
| } |
| |
| $("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"); |
| |
| $("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 = '<div class="idle-m">Awaiting resupply manifest…</div>'; |
| 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; |
| if (manifest && manifest !== "") { |
| finalReceived = true; |
| report.classList.remove("pulse"); |
| report.textContent = text; |
| $("manifest").innerHTML = manifest; |
| |
| |
| |
| if (/<li/.test(manifest)) collapseReport(); |
| } else { |
| report.textContent = text; |
| } |
| } |
| if (!finalReceived) { |
| report.classList.remove("pulse"); |
| report.classList.add("alert"); |
| report.textContent = "Analysis ended without a result — field unit may be offline."; |
| } |
| } catch (err) { |
| report.classList.remove("pulse"); |
| report.classList.add("alert"); |
| report.textContent = "Field unit offline — " + (err && err.message ? err.message : err); |
| } finally { |
| scan.classList.remove("on"); |
| $("analyze").disabled = false; |
| } |
| } |
|
|
| |
| |
| function collapseReport() { |
| $("report").style.display = "none"; |
| const tog = $("reportToggle"); |
| tog.style.display = ""; |
| tog.setAttribute("aria-expanded", "false"); |
| $("reportCaret").textContent = "▸"; |
| } |
|
|
| $("reportToggle").addEventListener("click", () => { |
| 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); |
|
|