"use strict"; const $ = id => document.getElementById(id); const sUpload = $("s-upload"); const sProcessing = $("s-processing"); const sResults = $("s-results"); const dropZone = $("drop-zone"); const fileInput = $("file-input"); const browseBtn = $("browse-btn"); const stepsList = $("steps-list"); const roomsTbody = $("rooms-tbody"); const resultsMeta = $("results-meta"); const exportBtn = $("export-btn"); const resetBtn = $("reset-btn"); const examplesList = $("examples-list"); const examplesForm = $("examples-form"); const exampleInput = $("example-input"); let jobId = null; let rooms = []; let examples = []; // ── Examples management ─────────────────────────── async function loadDefaults() { try { const resp = await fetch("/api/defaults"); const data = await resp.json(); examples = Array.isArray(data.examples) ? data.examples : []; renderExamples(); } catch (e) { console.warn("Could not load defaults:", e); } } function renderExamples() { examplesList.innerHTML = ""; examples.forEach((ex, i) => { const chip = document.createElement("span"); chip.className = "example-chip"; chip.innerHTML = ` ${esc(ex)} `; examplesList.appendChild(chip); }); examplesList.querySelectorAll(".example-chip-remove").forEach(btn => { btn.addEventListener("click", () => { examples.splice(parseInt(btn.dataset.i, 10), 1); renderExamples(); }); }); } examplesForm.addEventListener("submit", e => { e.preventDefault(); const v = exampleInput.value.trim(); if (!v) return; if (!/\d/.test(v)) { exampleInput.focus(); exampleInput.select(); return; } if (!examples.includes(v)) examples.push(v); exampleInput.value = ""; renderExamples(); exampleInput.focus(); }); // ── Drag & drop ─────────────────────────────────── dropZone.addEventListener("dragover", e => { e.preventDefault(); dropZone.classList.add("drag-over"); }); dropZone.addEventListener("dragleave", () => dropZone.classList.remove("drag-over")); dropZone.addEventListener("drop", e => { e.preventDefault(); dropZone.classList.remove("drag-over"); const f = e.dataTransfer.files[0]; if (f) handleFile(f); }); dropZone.addEventListener("click", () => fileInput.click()); browseBtn.addEventListener("click", e => { e.stopPropagation(); fileInput.click(); }); fileInput.addEventListener("change", e => { if (e.target.files[0]) handleFile(e.target.files[0]); }); // ── Upload & process ────────────────────────────── async function handleFile(file) { const ext = file.name.split(".").pop().toLowerCase(); if (!["dwg", "dxf"].includes(ext)) { alert("Podporované formáty jsou .dwg a .dxf"); return; } show(sProcessing); hide(sUpload); hide(sResults); stepsList.innerHTML = ""; addStep("Nahrávání souboru…", "active"); const fd = new FormData(); fd.append("file", file); fd.append("examples", JSON.stringify(examples)); try { const resp = await fetch("/api/upload", { method: "POST", body: fd }); if (!resp.ok) { const err = await resp.json().catch(() => ({})); throw new Error(err.detail || `HTTP ${resp.status}`); } const data = await resp.json(); jobId = data.job_id; stepsList.innerHTML = ""; for (const step of data.steps) addStep(step, "done"); const rResp = await fetch(`/api/rooms/${jobId}`); rooms = await rResp.json(); renderResults(); } catch (err) { stepsList.innerHTML = ""; addStep(`Chyba: ${err.message}`, "error"); setTimeout(() => { show(sUpload); hide(sProcessing); }, 4000); } } function addStep(label, state) { const el = document.createElement("div"); el.className = `step-item ${state}`; el.innerHTML = `${esc(label)}`; stepsList.appendChild(el); } // ── Render table ────────────────────────────────── function renderResults() { hide(sProcessing); show(sResults); const total = rooms.length; const llmCount = rooms.filter(r => r.source === "llm").length; resultsMeta.textContent = `${total} místností nalezeno${llmCount ? ` (${llmCount} z AI)` : ""}`; roomsTbody.innerHTML = ""; const sorted = [...rooms].sort((a, b) => String(a.room).localeCompare(String(b.room))); sorted.forEach((room, i) => { const tr = document.createElement("tr"); const pct = Math.round((room.confidence ?? 1) * 100); const badgeCls = room.source === "llm" ? "badge-llm" : "badge-rule"; const badgeTxt = room.source === "llm" ? "AI" : "Pravidla"; tr.innerHTML = `