No tier on this ladder handles ${d.goals && d.goals.length > 1 ? "all of these together" : "it"} comfortably — this combination wants workstation hardware.
` : ""}
${d.speed ? `
Why this speed? real benchmark runs, and where you land
Every grey dot is a real benchmark run from the
LocalScore community database.
Generation speed tracks memory bandwidth — that's the one number that matters most for local AI
(why).
The dashed line is the theoretical ceiling for ${d.speed.model} at your setting;
your machine is the marked dot at ≈${d.speed.tps} tok/s
(${d.speed.method === "measured-model"
? `predicted by a model trained on these measurements, following IBM's LLM-Pilot methodology`
: `an analytical estimate; a learned predictor trained on these runs — LLM-Pilot methodology — takes over once trained`}).
` : ""}
${opts ? `
What you can run real models, biggest to smallest — names link to Hugging Face
${opts}
` : ""}
${tools ? `
How to actually run it
${tools}
` : ""}
${cmds ? `
Copy-paste to get started
${d.commands.intro || ""}
${cmds}
` : ""}
Ask a follow-up explained in plain words, from the numbers above
`;
if (multiCache) {
const back = document.createElement("button");
back.className = "back-link";
back.textContent = "← All goals";
back.addEventListener("click", () => renderMulti(multiCache.results));
$("#results").firstElementChild.prepend(back);
}
hydrate($("#results"));
if (d.speed) drawRoofline(d.speed);
$("#results").querySelectorAll(".copy-btn").forEach(b => b.addEventListener("click", () => {
navigator.clipboard.writeText(decodeURIComponent(b.dataset.code));
b.textContent = "Copied ✓"; b.classList.add("done");
setTimeout(() => { b.textContent = "Copy"; b.classList.remove("done"); }, 1500);
}));
wireAsk();
}
// ---- "Why this speed?" roofline scatter (real LocalScore runs) ------------
let _rooflinePts = null;
async function getRooflinePoints() {
if (_rooflinePts) return _rooflinePts;
try {
const r = await fetch("/static/roofline.json");
_rooflinePts = await r.json();
} catch (e) { _rooflinePts = { points: [] }; }
return _rooflinePts;
}
async function drawRoofline(speed) {
const host = $("#roofline-chart");
if (!host) return;
const data = await getRooflinePoints();
const pts = (data.points || []).filter(p => p.bw > 0 && p.tps > 0.5);
if (!pts.length && !speed) { host.innerHTML = ""; return; }
const W = 720, H = 320, L = 52, R = 16, T = 14, B = 40;
const xmin = 40, xmax = 2100, ymin = 0.8, ymax = 400;
const lx = v => L + (Math.log10(v) - Math.log10(xmin)) / (Math.log10(xmax) - Math.log10(xmin)) * (W - L - R);
const ly = v => H - B - (Math.log10(v) - Math.log10(ymin)) / (Math.log10(ymax) - Math.log10(ymin)) * (H - T - B);
let s = `
~1B model runs~8B runs~14B runstheoretical ceiling (your pick)your machine
`;
host.innerHTML = s;
}
// ---- Live progress ticker (gradio-style elapsed seconds) -------------------
function startTicker(el, base) {
const t0 = Date.now();
el.dataset.ticking = "1";
const tick = () => {
if (el.dataset.ticking !== "1") return;
const s = Math.round((Date.now() - t0) / 1000);
el.innerHTML = ` ${base} — ${s}s` +
(s > 8 ? " (cold start: the model is waking, up to ~1 min)" : "");
setTimeout(tick, 500);
};
tick();
return () => { el.dataset.ticking = "0"; };
}
// ---- Paste box: the fine-tuned spec parser fills the form -----------------
async function parsePaste() {
const text = $("#paste").value.trim();
const hint = $("#parse-hint");
const btn = $("#parse-btn");
if (!text) { hint.textContent = "Type or paste something first."; return; }
if (btn.disabled) return; // one in-flight call, ever — GPU time is real money
btn.disabled = true;
const stop = startTicker(hint, "Reading your description");
try {
const client = await getClient();
const r = await client.predict("/parse", { text });
const d = Array.isArray(r.data) ? r.data[0] : r.data;
stop();
if (d.error) { hint.textContent = `Failed: ${d.error}`; return; }
applyParsed(d, hint);
} catch (e) {
stop();
hint.textContent = `Failed: ${e && e.message ? e.message : e}`;
} finally {
btn.disabled = false;
}
}
function applyParsed(d, hint) {
const got = [];
if (d.computer) {
state.computer = d.computer;
setActive("#computer-seg", d.computer);
syncProviderForComputer();
got.push(d.computer);
}
if (d.provider) {
state.provider = d.provider;
setActive("#provider-seg", d.provider);
fillGpu();
got.push(d.provider.toUpperCase());
}
if (d.gpu) {
const sel = $("#gpu");
const want = String(d.gpu).toLowerCase().replace(/\b(nvidia|geforce|amd|radeon|intel)\b/g, "").trim();
const match = [...sel.options].find(o => o.value.toLowerCase().includes(want));
if (match) { sel.value = match.value; got.push(match.value); }
else if (d.vram_gb) { $("#vram").value = d.vram_gb; got.push(`${d.gpu} (${d.vram_gb} GB)`); }
else got.push(d.gpu);
} else if (d.vram_gb) {
$("#vram").value = d.vram_gb;
got.push(`${d.vram_gb} GB VRAM`);
}
if (d.ram_gb) {
const ram = $("#ram");
const opt = [...ram.options].map(o => parseFloat(o.value))
.reduce((a, b) => Math.abs(b - d.ram_gb) < Math.abs(a - d.ram_gb) ? b : a);
ram.value = `${opt} GB`;
got.push(`${d.ram_gb} GB RAM`);
}
hint.textContent = got.length
? `Understood: ${got.join(", ")}. Anything you didn't mention stayed blank — confirm and press Check.`
: "Couldn't find any specs in that text — nothing was filled in (the parser doesn't guess).";
maybeLiveUpdate();
}
// ---- Follow-up: the model brick (grounded explainer) ---------------------
function wireAsk() {
const input = $("#ask-input"), send = $("#ask-send");
if (!input || !send) return;
const go = () => askQuestion(input.value);
send.addEventListener("click", go);
input.addEventListener("keydown", e => { if (e.key === "Enter") go(); });
$("#results").querySelectorAll(".ask-chip").forEach(c =>
c.addEventListener("click", () => { input.value = c.textContent; askQuestion(c.textContent); }));
}
let askBusy = false;
async function askQuestion(question) {
question = (question || "").trim();
const box = $("#ask-answer");
if (!question || !box || askBusy) return;
askBusy = true;
box.hidden = false;
box.innerHTML = ``;
const stop = startTicker($("#ask-tick"), "Thinking it through");
try {
const a = await callAsk(question, JSON.stringify(lastAdvice || {}));
stop();
renderAnswer(box, a);
} catch (e) {
stop();
// Surface the real error, never a generic stand-in.
box.innerHTML = `
The explainer hit an error
${e && e.message ? e.message : e}
`;
} finally {
askBusy = false;
}
}
function renderAnswer(box, a) {
a = a || {};
if (a.error) { // surface the real error from the model brick, not filler
box.innerHTML = `
The explainer hit an error
${a.error}
`;
return;
}
box.innerHTML = `
${a.headline ? `
${a.headline}
` : ""}
${a.why ? `
${a.why}
` : ""}
${a.next_step ? `
${a.next_step}
` : ""}
`;
hydrate(box);
}
// On a ZeroGPU Space the JS client is REQUIRED (it forwards the HF iframe auth
// headers ZeroGPU needs). Locally / non-ZeroGPU we fall back to the raw
// two-step call so the chat still works with no internet to a CDN.
let _gradioClient = null;
async function getClient() {
if (_gradioClient) return _gradioClient;
const mod = await import("https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js");
const Client = mod.Client || mod.client;
_gradioClient = await Client.connect(window.location.origin);
return _gradioClient;
}
async function callAsk(question, facts) {
try {
const client = await getClient();
const r = await client.predict("/ask", { question, facts });
return Array.isArray(r.data) ? r.data[0] : r.data;
} catch (e) {
return await callAskRaw(question, facts);
}
}
async function callAskRaw(question, facts) {
const post = await fetch("/gradio_api/call/ask", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ data: [question, facts] }),
});
const { event_id } = await post.json();
const res = await fetch(`/gradio_api/call/ask/${event_id}`);
const text = await res.text();
const lines = [...text.matchAll(/data:\s*(.+)/g)]; // SSE data frames
if (!lines.length) throw new Error("no data in stream");
const arr = JSON.parse(lines[lines.length - 1][1]); // last frame = result
return Array.isArray(arr) ? arr[0] : arr;
}
// ---- Init -----------------------------------------------------------------
function init() {
hydrate(document);
buildPicker();
wireSegmented("#mode-seg", "mode", applyMode);
wireSegmented("#computer-seg", "computer", () => { syncProviderForComputer(); $("#find-specs-body").innerHTML = findSpecsText(); });
wireSegmented("#provider-seg", "provider", fillGpu);
wireSegmented("#priority-seg", "priority");
["#ram","#gpu","#vram","#custom-uc","#repo-check"].forEach(s => { const el = $(s); if (el) el.addEventListener("change", maybeLiveUpdate); });
$("#paste").addEventListener("input", maybeLiveUpdate);
$("#check-btn").addEventListener("click", check);
const pb = $("#parse-btn"); if (pb) pb.addEventListener("click", parsePaste);
syncProviderForComputer();
$("#find-specs-body").innerHTML = findSpecsText();
detectHardware();
// Pre-filled share/preview links: ?go renders immediately; optional
// ?gpu=NVIDIA|RTX 3060 (12 GB)&ram=16&uc=chat pre-select a profile.
const q = new URLSearchParams(location.search);
if (q.has("gpu")) {
const [vendor, label] = (q.get("gpu") || "").split("|");
if (vendor) { state.provider = vendor.toLowerCase(); setActive("#provider-seg", state.provider); fillGpu(); }
if (label) { const sel = $("#gpu"); [...sel.options].forEach(o => { if (o.value === label) sel.value = label; }); }
}
if (q.has("ram")) $("#ram").value = `${q.get("ram")} GB`;
if (q.has("uc")) {
state.usecases = [q.get("uc")];
document.querySelectorAll(".uc-pill").forEach(p =>
p.classList.toggle("active", p.dataset.uc === q.get("uc")));
}
if (q.has("go")) check();
}
init();