// Browser webcam capture -> POST frames to /api/face -> draw boxes + tally signals. (function () { const video = document.getElementById("video"); const overlay = document.getElementById("overlay"); const ctx = overlay.getContext("2d"); const startBtn = document.getElementById("startBtn"); const stopBtn = document.getElementById("stopBtn"); const statusEl = document.getElementById("status"); const resultEl = document.getElementById("result"); const chip = { Anxious: document.getElementById("c-anx"), Depressed: document.getElementById("c-dep"), Normal: document.getElementById("c-nor") }; const capture = document.createElement("canvas"); const counts = { Anxious: 0, Depressed: 0, Normal: 0 }; let stream = null, timer = null, busy = false; function renderChips() { Object.keys(counts).forEach((k) => { if (chip[k]) chip[k].textContent = counts[k]; }); } startBtn.onclick = async () => { try { stream = await navigator.mediaDevices.getUserMedia({ video: true }); video.srcObject = stream; Object.keys(counts).forEach((k) => (counts[k] = 0)); renderChips(); resultEl.textContent = ""; startBtn.disabled = true; stopBtn.disabled = false; statusEl.textContent = "Detecting… keep your face in view."; timer = setInterval(tick, 500); } catch (e) { statusEl.textContent = "Could not access webcam: " + e.message; } }; stopBtn.onclick = () => { if (timer) clearInterval(timer); timer = null; if (stream) stream.getTracks().forEach((t) => t.stop()); startBtn.disabled = false; stopBtn.disabled = true; ctx.clearRect(0, 0, overlay.width, overlay.height); const total = counts.Anxious + counts.Depressed + counts.Normal; const verdict = Object.keys(counts).reduce((a, b) => (counts[a] >= counts[b] ? a : b)); resultEl.textContent = total ? "Result: " + verdict : "No face detected — try again."; statusEl.textContent = "Stopped."; }; async function tick() { if (busy || video.readyState < 2) return; busy = true; capture.width = video.videoWidth; capture.height = video.videoHeight; capture.getContext("2d").drawImage(video, 0, 0); try { const blob = await new Promise((r) => capture.toBlob(r, "image/jpeg", 0.7)); const fd = new FormData(); fd.append("frame", blob, "frame.jpg"); const res = await fetch("/api/face", { method: "POST", body: fd }); const data = await res.json(); draw(data.faces || []); } catch (e) { /* drop the occasional failed frame */ } busy = false; } function draw(faces) { const sx = overlay.width / (video.videoWidth || overlay.width); const sy = overlay.height / (video.videoHeight || overlay.height); ctx.clearRect(0, 0, overlay.width, overlay.height); ctx.lineWidth = 2; ctx.strokeStyle = "#00b3ff"; ctx.fillStyle = "#00b3ff"; ctx.font = "18px sans-serif"; faces.forEach((f) => { const [x, y, w, h] = f.box; ctx.strokeRect(x * sx, y * sy, w * sx, h * sy); const label = f.emotion + " (" + f.signal + ")"; ctx.fillText(label, x * sx, y * sy > 20 ? y * sy - 6 : y * sy + 16); if (counts[f.signal] !== undefined) counts[f.signal]++; }); renderChips(); } })();