cmf-decision / app.js
infosave's picture
Launch CMF Decision live demo: three skills, resonance errors and abstention
43128c9 verified
Raw History Blame Contribute Delete
5.02 kB
"use strict";
const $ = id => document.getElementById(id);
const examples = {
banking77: [["Missing card", "I still have not received my new card"], ["Lost card", "I lost my debit card. How can I freeze it?"], ["Change PIN", "How do I change my card PIN?"]],
clinc150: [["Weather", "What is the weather forecast for tomorrow?"], ["Set an alarm", "Set an alarm for seven tomorrow morning"], ["Book a flight", "I want to book a flight to Boston"]],
massive: [["Play music", "Play some jazz music"], ["Set a timer", "Set a timer for ten minutes"], ["Lights off", "Turn off the living room lights"]]
};
const run = $("decide");
const text = $("text");
let busy = false;
function count() { $("count").textContent = `${text.value.length} / 2000`; }
function clearResult() { $("result").hidden = true; $("empty").hidden = false; $("error").hidden = true; }
function loadExamples() {
$("examples").replaceChildren();
for (const [title, value] of examples[$("skill").value]) {
const button = document.createElement("button");
button.className = "example"; button.type = "button"; button.textContent = title;
button.addEventListener("click", () => { if (busy) return; text.value = value; count(); clearResult(); });
$("examples").append(button);
}
}
function render(value) {
const decision = value.decision;
const accepted = decision.confident && !decision.is_novel;
$("verdict").textContent = accepted ? "Accepted · local decision" : "Abstained · needs review";
$("verdict").className = accepted ? "verdict" : "verdict abstained";
$("label").textContent = accepted ? decision.task_label : "Not confident enough";
$("explanation").textContent = accepted
? "The winning topology passed the model’s confidence gate."
: "No decision accepted. Candidates below are suggestions, not an accepted answer.";
$("confidence").textContent = `${(decision.confidence * 100).toFixed(2)}%`;
const encoding = Number(value.meta.embedding_latency_ms);
const resonance = Number(value.meta.latency_ms);
$("time").textContent = `${(encoding + resonance).toFixed(2)} ms`;
$("timings").textContent = `Encoder ${encoding.toFixed(2)} ms + resonance ${resonance.toFixed(2)} ms · shared HF CPU`;
$("candidates").replaceChildren();
const candidates = value.scores.slice(0, 3).sort((a,b) => a.reconstruction_error - b.reconstruction_error);
const max = Math.max(...candidates.map(c => c.reconstruction_error), 0.000001);
for (const candidate of candidates) {
const row = document.createElement("div"); row.className = "candidate";
const names = document.createElement("div"); names.className = "candidate-name";
const label = document.createElement("span"); label.textContent = candidate.task_label;
const error = document.createElement("span"); error.textContent = Number(candidate.reconstruction_error).toFixed(4);
names.append(label, error);
const bar = document.createElement("progress"); bar.max = max; bar.value = candidate.reconstruction_error;
bar.setAttribute("aria-label", `${candidate.task_label}: reconstruction error ${error.textContent}`);
row.append(names, bar); $("candidates").append(row);
}
$("json").textContent = JSON.stringify(value, null, 2);
$("empty").hidden = true; $("result").hidden = false;
}
async function decide() {
if (busy) return;
const prompt = text.value.trim();
if (!prompt) { $("error").textContent = "Enter a request first."; $("error").hidden = false; text.focus(); return; }
clearResult(); busy = true; run.disabled = true; text.disabled = true;
$("skill").disabled = true; $("profile").disabled = true;
run.textContent = "Computing reconstruction errors…";
const abort = new AbortController(); const timeout = setTimeout(() => abort.abort(), 40000);
try {
const response = await fetch("/api/decide", {method:"POST", headers:{"Content-Type":"application/json"},
body:JSON.stringify({skill:$("skill").value, text:prompt, profile:$("profile").value}), signal:abort.signal});
const result = await response.json();
if (!response.ok) throw new Error(result.error || "The demo is unavailable. Please retry.");
render(result);
} catch (error) {
$("error").textContent = error.name === "AbortError" ? "The request timed out. Please try again." : error.message;
$("error").hidden = false;
} finally {
clearTimeout(timeout); busy = false; run.disabled = false; text.disabled = false;
$("skill").disabled = false; $("profile").disabled = false; run.textContent = "Make a decision →";
}
}
$("skill").addEventListener("change", () => { loadExamples(); text.value = examples[$("skill").value][0][1]; count(); clearResult(); });
$("profile").addEventListener("change", clearResult);
text.addEventListener("input", () => { count(); clearResult(); });
text.addEventListener("keydown", event => { if ((event.ctrlKey || event.metaKey) && event.key === "Enter") { event.preventDefault(); decide(); } });
run.addEventListener("click", decide);
loadExamples(); count();