"use strict"; (function () { const $ = (s, root = document) => root.querySelector(s); const $$ = (s, root = document) => [...root.querySelectorAll(s)]; function el(tag, attrs, ...kids) { const n = document.createElement(tag); for (const [k, v] of Object.entries(attrs || {})) { if (v === null || v === undefined || v === false) continue; if (k === "class") n.className = v; else if (k === "text") n.textContent = v; else if (k === "style") { // Property by property: the page's CSP forbids style attributes, not CSSOM writes. for (const decl of String(v).split(";")) { const i = decl.indexOf(":"); if (i > 0) n.style.setProperty(decl.slice(0, i).trim(), decl.slice(i + 1).trim()); } } else if (k.startsWith("on")) n.addEventListener(k.slice(2), v); else n.setAttribute(k, v === true ? "" : v); } for (const kid of kids.flat()) { if (kid === null || kid === undefined || kid === false) continue; n.append(kid instanceof Node ? kid : document.createTextNode(String(kid))); } return n; } const gb = (v, digits = 1) => (v === null || v === undefined ? "?" : `${Number(v).toFixed(digits)} GB`); const bytesGB = (b) => (b ? gb(b / 1e9) : "?"); const params = (p) => (p ? (p >= 1e9 ? `${+(p / 1e9).toFixed(p >= 1e10 ? 0 : 1)}B` : `${Math.round(p / 1e6)}M`) : ""); const compact = (n) => (n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n || 0)); const ctxLabel = (c) => (c >= 1024 ? `${Math.round(c / 1024)}k` : String(c)); const store = { get(k) { try { return JSON.parse(localStorage.getItem(k)); } catch (e) { return null; } }, set(k, v) { try { localStorage.setItem(k, JSON.stringify(v)); } catch (e) {} }, }; // ------------------------------------------------------------------ telemetry const Telemetry = (() => { const gpc = navigator.globalPrivacyControl === true || navigator.doNotTrack === "1"; let optedOut = gpc; try { if (localStorage.getItem("lme-optout") === "1") optedOut = true; else if (gpc && localStorage.getItem("lme-optin") === "1") optedOut = false; } catch (e) {} let sid = null; try { sid = sessionStorage.getItem("lme-sid"); } catch (e) {} if (!sid || !/^[a-f0-9]{16}$/.test(sid)) { const b = new Uint8Array(8); crypto.getRandomValues(b); sid = [...b].map((x) => x.toString(16).padStart(2, "0")).join(""); try { sessionStorage.setItem("lme-sid", sid); } catch (e) {} } let enabled = true; let build = () => null; let lastSent = ""; const clean = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined && v !== null && v !== "" && !(Array.isArray(v) && !v.length))); function post(events, beacon) { const body = JSON.stringify({ events }); if (beacon && navigator.sendBeacon) navigator.sendBeacon("/api/events", new Blob([body], { type: "application/json" })); else fetch("/api/events", { method: "POST", headers: { "content-type": "application/json" }, body, keepalive: true }).catch(() => {}); } function sendSession(beacon) { if (optedOut || !enabled) return; const summary = build(); if (!summary) return; const ev = clean({ event_type: "session", session_id: sid, ...summary }); const key = JSON.stringify(ev); if (key === lastSent) return; lastSent = key; post([ev], beacon); } document.addEventListener("visibilitychange", () => { if (document.visibilityState === "hidden") sendSession(true); }); window.addEventListener("pagehide", () => sendSession(true)); return { gpc, get optedOut() { return optedOut; }, setOptOut(v) { optedOut = v; try { if (v) { localStorage.setItem("lme-optout", "1"); localStorage.removeItem("lme-optin"); } else { localStorage.removeItem("lme-optout"); if (gpc) localStorage.setItem("lme-optin", "1"); } } catch (e) {} }, setEnabled(v) { enabled = v; }, setBuilder(fn) { build = fn; }, sendSession, async submit(type, fields) { if (optedOut) return { ok: false, message: "Sending is turned off in the privacy setting at the bottom of the page." }; const ev = clean({ event_type: type, session_id: sid, ...fields }); try { const r = await fetch("/api/events", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ events: [ev] }) }); const j = await r.json().catch(() => ({})); if (r.status === 202) return { ok: true, row: (j.rows || [])[0] || {} }; if (r.status === 429) return { ok: false, message: "Too many submissions from this network. Try again in a minute." }; const d = (j.details || []).map((x) => `${(x.loc || []).slice(-1)[0]}: ${x.msg}`).join("; "); return { ok: false, message: `Not accepted${d ? ` (${d})` : ""}.` }; } catch (e) { return { ok: false, message: "Couldn't reach the server. Check your connection and try again." }; } }, }; })(); // ------------------------------------------------------------------ state let META = null; const visit = { families: new Set(), queries: new Set(), viewed: [], clicked: [], copied: new Set(), searched: false, top: null }; const state = { offset: 0, total: 0, loading: 0, detailKey: null }; function rig() { const kind = $('input[name="kind"]:checked').value; const out = { kind, ram_gb: 32, gpus: [] }; if (kind === "gpu") { const cards = (sel, vram, count, fallback) => { const name = $(sel).value; const each = name === "custom" ? Math.max(1, Math.min(256, +$(vram).value || fallback)) : META.hardware.gpus[name]; return Array.from({ length: +$(count).value || 1 }, () => each); }; out.gpus = cards("#gpu", "#custom-vram", "#gpu-count", 24); if (mixedCards()) out.gpus = out.gpus.concat(cards("#gpu2", "#custom-vram2", "#gpu2-count", 8)).slice(0, 16); out.ram_gb = +$("#ram").value; out.gpu_model = $("#gpu").value; } else if (kind === "unified") { out.unified_system = $("#unified-system").value; out.ram_gb = +$("#unified-mem").value; } else { out.ram_gb = +$("#ram").value; } return out; } function mixedCards() { return !$("#gpu2-block").hidden; } function customCard() { return $("#gpu").value === "custom" || (mixedCards() && $("#gpu2").value === "custom"); } function hardwarePayload(r) { const h = { kind: r.kind, gpus: r.gpus, ram_gb: r.ram_gb }; if (r.unified_system) h.unified_system = r.unified_system; return h; } function usableVram(r) { if (r.kind === "unified") { const share = (META.hardware.unified_shares || {})[r.unified_system]; return r.ram_gb * (share || (r.ram_gb <= 36 ? 0.67 : 0.75)); } return r.gpus.reduce((a, v) => a + Math.max(v - 0.5, 0), 0); } function renderCapacity() { const r = rig(); const box = $("#capacity"); if (r.kind === "gpu") { const total = r.gpus.reduce((a, v) => a + v, 0); box.replaceChildren( el("div", { class: "pool gpu" }, el("b", {}, `${total} GB`), `VRAM${r.gpus.length > 1 ? ` on ${r.gpus.length} cards` : ""}`), el("div", { class: "pool ram" }, el("b", {}, `${r.ram_gb} GB`), "system RAM")); } else if (r.kind === "unified") { box.replaceChildren(el("div", { class: "pool gpu" }, el("b", {}, gb(usableVram(r), 0)), `of ${r.ram_gb} GB usable by the GPU by default`)); } else { box.replaceChildren(el("div", { class: "pool ram" }, el("b", {}, `${r.ram_gb} GB`), "system RAM")); } } function saveRig() { store.set("lme-rig", { kind: $('input[name="kind"]:checked').value, gpu: $("#gpu").value, vram: $("#custom-vram").value, count: $("#gpu-count").value, mixed: mixedCards(), gpu2: $("#gpu2").value, vram2: $("#custom-vram2").value, count2: $("#gpu2-count").value, ram: $("#ram").value, usys: $("#unified-system").value, umem: $("#unified-mem").value, context: $("#context").value, kv: $("#kv").value, priority: $('input[name="priority"]:checked').value, minBits: $("#min-bits").value, fits: $("#fits-only").checked, vramOnly: $("#vram-only").checked, mmproj: $("#mmproj").value, }); } function syncKind() { const kind = $('input[name="kind"]:checked').value; $$("[data-show]").forEach((n) => { n.hidden = !n.dataset.show.split(" ").includes(kind); }); $("#custom-vram-field").hidden = kind !== "gpu" || $("#gpu").value !== "custom"; $("#custom-vram2-field").hidden = $("#gpu2").value !== "custom"; $("#gpu2-toggle").textContent = mixedCards() ? "Remove the other card" : "Add a different card"; const note = (META.hardware.unified_notes || {})[$("#unified-system").value]; $("#unified-note").textContent = note || ""; $("#unified-note").hidden = !note; const mems = META.hardware.unified[$("#unified-system").value] || []; const cur = +$("#unified-mem").value; $("#unified-mem").replaceChildren(...mems.map((m) => el("option", { value: m, selected: m === cur }, `${m} GB`))); if (!mems.includes(cur) && mems.length) $("#unified-mem").value = mems.includes(64) ? 64 : mems[mems.length - 1]; renderCapacity(); } function query() { const r = rig(); return { hardware: hardwarePayload(r), context: +$("#context").value, kv_type: $("#kv").value, priority: $('input[name="priority"]:checked').value, min_bits: +$("#min-bits").value, sort: $("#sort").value, family: $("#family").value || null, size: $("#size").value || null, search: $("#search").value.trim() || null, moe_only: $("#moe-only").checked, vision_only: $("#vision-only").checked, fits_only: $("#fits-only").checked, vram_only: r.kind === "gpu" && $("#vram-only").checked, mmproj: $("#mmproj").value, }; } // ------------------------------------------------------------------ memory rail const SCORE_PARTS = [["fit", "Fit on your hardware"], ["capacity", "Model size you can run"], ["popularity", "Downloads"], ["recency", "How new"], ["community", "Community reports"]]; function scoreBreakdown(m) { const w = META.score_weights || {}; return SCORE_PARTS.map(([k, label]) => `${label}: ${Math.round((m.components[k] || 0) * w[k] * 100)} of ${Math.round(w[k] * 100)}`); } function rail(best, r) { const f = best && best.fit; if (!f) return null; const box = el("div", { class: "rail", role: "img" }); const pct = (v, cap) => `${Math.max(0, Math.min(100, (v / cap) * 100))}%`; if (r.kind === "unified") { const cap = usableVram(r); const pool = el("div", { class: "pool", style: `flex:1` }, el("i", { class: "gpu", style: `width:${pct(f.gpu_gb, cap)}` })); if (f.gpu_gb > cap) pool.append(el("i", { class: "over", style: `width:${pct(f.gpu_gb - cap, f.gpu_gb)}` })); box.append(pool); box.setAttribute("aria-label", `Needs ${gb(f.gpu_gb)} of ${gb(cap)} the GPU can use`); return box; } const vram = r.kind === "gpu" ? r.gpus.reduce((a, v) => a + v, 0) : 0; // GPU figures include each card's driver context const ram = r.ram_gb; const total = vram + ram; if (vram) { box.append(el("div", { class: "pool", style: `flex:${vram / total}` }, el("i", { class: "gpu", style: `width:${pct(f.gpu_gb, vram)}` }))); } const ramPool = el("div", { class: "pool", style: `flex:${ram / total}` }, el("i", { class: f.tier === "gpu_moe" ? "exp" : "ram", style: `width:${pct(f.ram_gb, ram)}` })); if (f.tier === "no" || f.tier === "no_vram") ramPool.append(el("i", { class: "over", style: "width:30%" })); box.append(ramPool); box.setAttribute("aria-label", `GPU ${gb(f.gpu_gb)} of ${gb(vram)}; RAM ${gb(f.ram_gb)} of ${ram} GB`); return box; } function fitBadge(best) { if (!best || !best.fit) return el("span", { class: "fit t-cpu" }, "Pick hardware"); return el("span", { class: `fit t-${best.fit.tier}${best.estimated ? " t-est" : ""}` }, best.fit.label + (best.estimated ? " (est.)" : "")); } // ------------------------------------------------------------------ results function card(m, r) { const b = m.best; const tags = [ m.params ? el("span", { class: "num" }, params(m.params) + (m.active_params ? ` (${params(m.active_params)} active)` : "")) : null, m.moe ? el("span", { class: "tag" }, "MoE") : null, m.vision ? el("span", { class: "tag" }, "vision") : null, el("span", {}, m.family), el("span", {}, `${m.repo_count} GGUF repo${m.repo_count === 1 ? "" : "s"}`), el("span", {}, `${compact(m.downloads)} downloads`), ]; const choice = b ? el("div", { class: "r-choice" }, el("span", { class: "num" }, b.quant), " from ", el("span", {}, b.repo.split("/")[0]), " — ", el("span", { class: "num" }, bytesGB(b.size)), b.fit && b.fit.tier !== "no" && b.fit.tier !== "no_vram" ? el("span", { class: "muted" }, `, ${gb(b.fit.gpu_gb)} on GPU, ${gb(b.fit.ram_gb)} in RAM`) : null) : el("div", { class: "r-choice muted" }, "File sizes not loaded yet."); return el("li", { class: "result" }, el("div", {}, el("div", { class: "r-name" }, el("button", { type: "button", onclick: () => openDetail(m.key) }, m.name)), el("div", { class: "r-meta" }, tags)), el("div", { class: "r-side" }, el("div", { class: "score", title: scoreBreakdown(m).join("\n") + "\nA ranking for your hardware, not a measure of model quality." }, Math.round(m.score)), el("div", {}, "score")), el("div", { class: "r-best" }, choice, fitBadge(b)), rail(b, r)); } let inflight = null; async function search(append) { const q = query(); if (!append) state.offset = 0; const payload = { ...q, offset: state.offset, limit: 24 }; const token = Symbol(); inflight = token; $("#count").textContent = append ? $("#count").textContent : "Finding models…"; let res; try { const r = await fetch("/api/recommend", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload) }); if (!r.ok) throw new Error(String(r.status)); res = await r.json(); } catch (e) { if (inflight === token) $("#count").textContent = "Couldn't load models. Refresh the page to try again."; return; } if (inflight !== token) return; const hw = rig(); const list = $("#results"); if (!append) list.replaceChildren(); if (!res.results.length && !append) { list.append(el("li", { class: "empty" }, q.vram_only ? `Nothing here fits entirely in VRAM. Untick “Keep the whole model in VRAM”, lower the context${q.min_bits ? ", allow lower quants" : ""}, or try a smaller size.` : q.fits_only ? `Nothing here runs on this hardware. Untick “Only models that run”, lower the context${q.min_bits ? ", allow lower quants" : ""}, or try a smaller size.` : "No models match. Clear the search or pick another family.")); } res.results.forEach((m) => list.append(card(m, hw))); state.total = res.total; state.offset += res.results.length; $("#count").textContent = `${res.total.toLocaleString()} model${res.total === 1 ? "" : "s"}`; $("#more").hidden = state.offset >= res.total; $("#notice").hidden = !res.notices.length; $("#notice").textContent = res.notices.join(" "); // Some results were estimated while their files were still being read; the server keeps // reading, so ask again for the exact numbers, a few times at most, if the user hasn't moved on. // (The notice is only set for reads still pending, not for files that can't be read.) const asked = JSON.stringify(q); if (state.refineFor !== asked) { state.refineFor = asked; state.refines = 0; } clearTimeout(state.refine); if (!append && res.notices.some((n) => n.includes("estimated")) && state.refines < 3) { state.refines += 1; state.refine = setTimeout(() => { if (JSON.stringify(query()) === asked && state.offset <= 24) search(false); }, 6000 * state.refines); } if (!append) { const first = res.results[0]; visit.top = first ? { key: first.key, quant: first.best && first.best.quant, fit: first.best && first.best.fit && first.best.fit.tier } : null; if (q.family) visit.families.add(q.family); if (q.search) visit.searched = true; visit.queries.add(JSON.stringify([q.family, q.size, q.search, q.context, q.priority, q.hardware])); visit.lastResults = res.total; } } let debounce; function schedule() { clearTimeout(debounce); debounce = setTimeout(() => search(false), 250); } // ------------------------------------------------------------------ detail async function openDetail(key) { const dlg = $("#detail"); state.detailKey = key; $("#d-title").textContent = key.split("/").pop(); $("#d-kicker").textContent = key.includes("/") ? key.split("/")[0] : "Model"; $("#d-facts").textContent = ""; $("#d-body").replaceChildren(el("p", { class: "muted" }, "Reading the model's files… a model nobody has opened yet takes a few seconds.")); if (!dlg.open) dlg.showModal(); if (!visit.viewed.includes(key)) visit.viewed.push(key); Telemetry.sendSession(false); const q = query(); let d; try { const r = await fetch("/api/model", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ key, hardware: q.hardware, context: q.context, kv_type: q.kv_type, priority: q.priority, min_bits: q.min_bits, vram_only: q.vram_only, mmproj: q.mmproj }) }); if (!r.ok) throw new Error(String(r.status)); d = await r.json(); } catch (e) { if (state.detailKey === key) $("#d-body").replaceChildren(el("p", { class: "status err" }, "Couldn't load this model. Close and try again.")); return; } if (state.detailKey !== key) return; renderDetail(d, q); } function renderDetail(d, q) { const hw = rig(); const g = d.geometry; $("#d-facts").textContent = [ d.params ? `${params(d.params)} parameters${d.active_params ? `, ${params(d.active_params)} active` : ""}` : null, g ? `${g.n_layers} layers` : null, g && g.moe ? `${g.expert_count} experts, ${g.expert_used} per token` : null, d.context_length ? `${ctxLabel(d.context_length)} native context` : null, g && g.notes.length ? g.notes.join(", ") : null, ].filter(Boolean).join(" • "); const body = $("#d-body"); body.replaceChildren(); if (d.components) { body.append(el("details", { class: "score-why" }, el("summary", {}, `Score ${Math.round(d.score)} of 100, and how it's worked out`), el("ul", {}, scoreBreakdown(d).map((line) => el("li", {}, line))), el("p", { class: "muted" }, "It ranks what suits your hardware among popular models. It doesn't measure how good a model is: a newer version with fewer downloads can score lower than an older one."))); } const opts = d.options || []; let selected = d.best ? opts.findIndex((o) => o.repo === d.best.repo && o.quant === d.best.quant) : 0; if (selected < 0) selected = 0; // command for the selected quant const cmdBox = el("pre", { class: "cmd" }); const tabs = el("div", { class: "tabs", role: "tablist" }); let runtime = "llama.cpp"; const selLabel = el("p", { class: "muted", style: "margin:4px 0 0;font-size:13px" }); function showCmd() { const o = opts[selected]; if (!o) { cmdBox.textContent = "No quant files could be read for this model."; return; } cmdBox.textContent = o.commands[runtime]; $$("button", tabs).forEach((b) => b.setAttribute("aria-selected", String(b.dataset.rt === runtime))); selLabel.textContent = runtime === "ollama" ? "Ollama picks GPU offload itself and defaults to a short context; set num_ctx to use more." : `${o.fit ? o.fit.label + ". " : ""}${o.estimated ? "Sizes are estimated from the parameter count. " : ""}` + (!o.projector_size ? "" : q.mmproj === "off" ? `The ${gb(o.projector_size / 1e9)} vision projector isn't loaded (--no-mmproj): text only.` : q.mmproj === "ram" ? `Includes the ${gb(o.projector_size / 1e9)} vision projector, kept in system RAM (--no-mmproj-offload); images encode slower.` : `Includes the ${gb(o.projector_size / 1e9)} vision projector that llama-server loads onto the GPU with -hf. Change "Vision projector" to keep it in RAM or skip it.`); } for (const rt of ["llama.cpp", "ollama"]) { tabs.append(el("button", { type: "button", role: "tab", "data-rt": rt, onclick: () => { runtime = rt; showCmd(); } }, rt)); } const copyBtn = el("button", { type: "button", class: "btn", onclick: async () => { try { await navigator.clipboard.writeText(cmdBox.textContent); copyBtn.textContent = "Copied"; visit.copied.add(runtime); setTimeout(() => (copyBtn.textContent = "Copy command"), 1500); } catch (e) { copyBtn.textContent = "Select and copy"; } } }, "Copy command"); body.append(el("h3", {}, "Run it"), el("div", { class: "cmd-row" }, tabs, copyBtn), cmdBox, selLabel); showCmd(); // every quant const rows = opts.map((o, i) => { const tr = el("tr", { tabindex: "0", "aria-selected": String(i === selected) }, el("td", {}, el("a", { href: o.url, target: "_blank", rel: "noopener", onclick: (ev) => { ev.stopPropagation(); if (!visit.clicked.includes(o.repo) && visit.clicked.length < 5) visit.clicked.push(o.repo); } }, o.repo.split("/")[0])), el("td", { class: "num" }, o.quant), el("td", { class: "num" }, bytesGB(o.size)), el("td", {}, fitBadge(o)), el("td", {}, rail(o, hw))); const pick = () => { selected = i; $$("tbody tr", body).forEach((row, j) => row.setAttribute("aria-selected", String(j === i))); showCmd(); }; tr.addEventListener("click", pick); tr.addEventListener("keydown", (ev) => { if (ev.key === "Enter" || ev.key === " ") { ev.preventDefault(); pick(); } }); return tr; }); body.append( el("h3", {}, `Every quant (${opts.length})`), d.hidden_below_min_bits ? el("p", { class: "muted" }, `${d.hidden_below_min_bits} quant(s) below ${q.min_bits}-bit hidden. Change "Lowest quant to consider" to see them.`) : "", opts.length ? el("div", { class: "tbl-wrap" }, el("table", {}, el("thead", {}, el("tr", {}, el("th", {}, "Uploader"), el("th", { class: "num" }, "Quant"), el("th", { class: "num" }, "Size"), el("th", {}, "On your hardware"), el("th", {}, "Memory"))), el("tbody", {}, rows))) : el("p", { class: "muted" }, "None of this model's GGUF files could be listed. The repos may be gated.")); if (d.kv_cache_gb) { body.append(el("h3", {}, `KV cache at ${q.kv_type}`), el("div", { class: "kv-strip" }, Object.entries(d.kv_cache_gb).map(([c, v]) => el("span", {}, `${ctxLabel(+c)} `, el("b", {}, gb(v, v < 10 ? 2 : 1)))))); } // other formats const fm = d.other_formats || {}; const formats = []; const lists = (ids) => el("ul", {}, ids.slice(0, 6).map((id) => el("li", {}, el("a", { href: `https://huggingface.co/${id}`, target: "_blank", rel: "noopener" }, id)))); if (fm.mlx) formats.push(el("div", { class: "format" }, el("h4", {}, `MLX (${fm.mlx.length})`), el("p", { style: "margin:0" }, "For Apple Silicon. ", el("a", { href: META.links.mlx, target: "_blank", rel: "noopener" }, "MLX Model Explorer"), " compares them."), lists(fm.mlx))); if (fm.onnx) formats.push(el("div", { class: "format" }, el("h4", {}, `ONNX (${fm.onnx.length})`), el("p", { style: "margin:0" }, el("a", { href: META.links.onnx, target: "_blank", rel: "noopener" }, "ONNX Community model explorer")), lists(fm.onnx))); for (const [k, label] of [["awq", "AWQ"], ["gptq", "GPTQ"], ["fp8", "FP8"], ["exl3", "EXL3"], ["exl2", "EXL2"]]) { if (fm[k]) formats.push(el("div", { class: "format" }, el("h4", {}, `${label} (${fm[k].length})`), el("p", { class: "muted", style: "margin:0" }, k.startsWith("exl") ? "For ExLlama / TabbyAPI." : "For vLLM, SGLang and other GPU servers."), lists(fm[k]))); } if (formats.length) body.append(el("h3", {}, "Other formats"), el("div", { class: "formats" }, formats)); // community body.append(el("h3", {}, "Community")); const c = d.community; if (c && c.bench_rows && c.bench_rows.length) { body.append(el("div", { class: "tbl-wrap" }, el("table", {}, el("thead", {}, el("tr", {}, el("th", {}, "Quant"), el("th", {}, "Hardware"), el("th", {}, "Backend"), el("th", { class: "num" }, "GPU layers"), el("th", { class: "num" }, "Prompt t/s"), el("th", { class: "num" }, "Generation t/s"))), el("tbody", {}, c.bench_rows.map((b) => el("tr", {}, el("td", { class: "num" }, b.quant || "?"), el("td", {}, b.gpu_name || b.gpu_model || (b.vram_class ? `${b.vram_class} GB GPU` : "CPU")), el("td", {}, b.backend || "?"), el("td", { class: "num" }, b.n_gpu_layers ?? "?"), el("td", { class: "num" }, b.prompt_tps ? Math.round(b.prompt_tps) : "—"), el("td", { class: "num" }, b.generation_tps ? b.generation_tps.toFixed(1) : "—"))))))); } else { body.append(el("p", { class: "muted" }, "No benchmarks for this model yet. Run llama-bench and paste the result below: it is the only speed data this page shows.")); } if (c && c.feedback) { body.append(el("p", {}, `${c.feedback} report${c.feedback === 1 ? "" : "s"}` + (c.positive_share !== null ? `, ${Math.round(c.positive_share * 100)}% worked well.` : "."))); } body.append(el("div", { class: "two" }, benchForm(d, opts, () => opts[selected]), feedbackForm(d, () => opts[selected]))); } function hardwareFields() { const r = rig(); return { hardware_kind: r.kind, gpu_model: r.kind === "gpu" ? r.gpu_model : null, gpu_count: r.kind === "gpu" ? r.gpus.length : null, vram_gb: r.kind === "gpu" ? r.gpus.reduce((a, v) => a + v, 0) : null, ram_gb: r.ram_gb, unified_system: r.kind === "unified" ? r.unified_system : null, hardware_source: customCard() ? "custom" : "preset", }; } function quantSelect(opts, current) { const s = el("select", {}); opts.forEach((o, i) => s.append(el("option", { value: i, selected: o === current() }, `${o.quant} — ${o.repo}`))); return s; } function benchForm(d, opts, current) { const sel = quantSelect(opts, current); const ta = el("textarea", { rows: "6", placeholder: "| model | size | params | backend | ngl | test | t/s |\n| ... | pp512 | ... |\n| ... | tg128 | ... |", maxlength: "40000" }); const status = el("p", { class: "status", role: "status" }); const btn = el("button", { type: "button", class: "btn primary" }, "Share benchmark"); btn.addEventListener("click", async () => { const o = opts[+sel.value]; if (!o || !ta.value.trim()) { status.className = "status err"; status.textContent = "Pick the quant you ran and paste llama-bench's output."; return; } btn.disabled = true; const res = await Telemetry.submit("llama_bench", { selected_model: d.key, repo: o.repo, quant: o.quant, bench_output: ta.value, ...hardwareFields() }); btn.disabled = false; if (!res.ok) { status.className = "status err"; status.textContent = res.message; return; } const row = res.row || {}; if ((row.flags || []).includes("unparseable_benchmark")) { status.className = "status err"; status.textContent = "Saved, but no llama-bench table was found in it. Paste the whole table, or run llama-bench with -o json."; } else { status.className = "status ok"; status.textContent = `Thanks. Recorded ${row.generation_tps ? `${row.generation_tps.toFixed(1)} t/s generation` : ""}${row.prompt_tps ? `, ${Math.round(row.prompt_tps)} t/s prompt` : ""} on ${row.backend || "your backend"}.`; ta.value = ""; } }); return el("div", { class: "panel" }, el("h4", { style: "margin:0 0 6px" }, "Share a llama-bench result"), el("p", { class: "muted", style: "margin:0 0 8px;font-size:13px" }, "Run ", el("code", {}, "llama-bench -m model.gguf"), " and paste the output. Only the speeds and settings are kept; file paths are discarded. Your hardware settings on this page are sent with it."), el("div", { class: "field" }, el("label", {}, "Quant you ran"), sel), el("div", { class: "field" }, el("label", {}, "llama-bench output"), ta), btn, status); } function feedbackForm(d, current) { const opts = d.options || []; const sel = quantSelect(opts, current); const pick = (name, choices) => el("select", { name }, el("option", { value: "" }, "—"), choices.map(([v, l]) => el("option", { value: v }, l))); const tried = pick("tried", [["yes", "Yes"], ["planning", "Planning to"], ["no", "No"]]); const how = pick("how", [["excellent", "Worked great"], ["good", "Worked well"], ["acceptable", "Usable"], ["too_slow", "Too slow"], ["out_of_memory", "Ran out of memory"], ["low_quality", "Poor output"], ["didnt_load", "Didn't load"]]); const runtime = pick("runtime", [["llama.cpp", "llama.cpp"], ["ollama", "Ollama"], ["lm-studio", "LM Studio"], ["jan", "Jan"], ["koboldcpp", "KoboldCpp"], ["other", "Other"]]); const tps = el("input", { type: "number", min: "0", max: "5000", step: "0.1", placeholder: "optional" }); const notes = el("input", { type: "text", maxlength: "280", placeholder: "optional, 280 characters" }); const status = el("p", { class: "status", role: "status" }); const btn = el("button", { type: "button", class: "btn primary" }, "Send report"); btn.addEventListener("click", async () => { if (!tried.value) { status.className = "status err"; status.textContent = "Say whether you've tried it."; return; } const o = opts[+sel.value]; const good = ["excellent", "good", "acceptable"].includes(how.value); btn.disabled = true; const res = await Telemetry.submit("feedback", { selected_model: d.key, repo: o && o.repo, quant: o && o.quant, tried: tried.value, quality_rating: good ? how.value : null, failure_reason: how.value && !good ? how.value : null, runtime: runtime.value || null, reported_tps: tps.value ? +tps.value : null, reported_context: +$("#context").value, notes: notes.value || null, ...hardwareFields(), }); btn.disabled = false; status.className = `status ${res.ok ? "ok" : "err"}`; status.textContent = res.ok ? "Thanks, your report is in." : res.message; }); const f = (label, input) => el("div", { class: "field" }, el("label", {}, label), input); return el("div", { class: "panel" }, el("h4", { style: "margin:0 0 6px" }, "Have you run this model?"), f("Quant", sel), el("div", { class: "row2" }, f("Tried it?", tried), f("How did it go?", how)), el("div", { class: "row2" }, f("Runtime", runtime), f("Tokens/s", tps)), f("Notes", notes), btn, status); } // ------------------------------------------------------------------ boot async function boot() { try { const r = await fetch("/api/meta"); META = await r.json(); } catch (e) { $("#count").textContent = "Couldn't reach the server. Refresh the page to try again."; return; } if (!META.collection_enabled) Telemetry.setEnabled(false); const H = META.hardware; const gpuOptions = () => [ ...H.gpu_groups.map(([label, names]) => el("optgroup", { label }, ...names.map((n) => el("option", { value: n }, `${n.replace(/^(NVIDIA|AMD|Intel) /, "")} (${H.gpus[n]} GB)`)))), el("option", { value: "custom" }, "Other: enter VRAM")]; $("#gpu").replaceChildren(...gpuOptions()); $("#gpu").value = "NVIDIA RTX 3090"; $("#gpu2").replaceChildren(...gpuOptions()); $("#gpu2").value = "NVIDIA RTX 3060 12GB"; $("#gpu-count").replaceChildren(...[1, 2, 3, 4, 6, 8].map((n) => el("option", { value: n }, n))); $("#gpu2-count").replaceChildren(...[1, 2, 3, 4, 6, 8].map((n) => el("option", { value: n }, n))); $("#ram").replaceChildren(...H.ram.map((v) => el("option", { value: v }, `${v} GB`))); $("#ram").value = 64; $("#unified-system").replaceChildren(...Object.keys(H.unified).map((n) => el("option", { value: n }, n))); $("#context").replaceChildren(...H.contexts.map((c) => el("option", { value: c }, `${ctxLabel(c)} tokens`))); $("#context").value = 16384; $("#family").append(...META.families.map((f) => el("option", { value: f.family }, `${f.family} (${f.count})`))); $("#size").append(...META.sizes.map((s) => el("option", { value: s }, s))); const saved = store.get("lme-rig"); if (saved) { const set = (sel, v) => { if (v !== undefined && v !== null && [...$(sel).options].some((o) => o.value === String(v))) $(sel).value = v; }; const kindInput = $(`input[name="kind"][value="${saved.kind}"]`); if (kindInput) kindInput.checked = true; set("#gpu", saved.gpu); set("#gpu-count", saved.count); set("#ram", saved.ram); set("#unified-system", saved.usys); set("#context", saved.context); set("#kv", saved.kv); set("#min-bits", saved.minBits); set("#mmproj", saved.mmproj); if (saved.vram) $("#custom-vram").value = saved.vram; $("#gpu2-block").hidden = !saved.mixed; set("#gpu2", saved.gpu2); set("#gpu2-count", saved.count2); if (saved.vram2) $("#custom-vram2").value = saved.vram2; const pr = $(`input[name="priority"][value="${saved.priority}"]`); if (pr) pr.checked = true; $("#fits-only").checked = !!saved.fits; $("#vram-only").checked = !!saved.vramOnly; syncKind(); set("#unified-mem", saved.umem); } else { syncKind(); detectHint(); } renderCapacity(); $("#rig").addEventListener("change", () => { $("#detect-hint").hidden = true; syncKind(); saveRig(); schedule(); }); $("#custom-vram").addEventListener("input", () => { renderCapacity(); saveRig(); schedule(); }); $("#custom-vram2").addEventListener("input", () => { renderCapacity(); saveRig(); schedule(); }); $("#gpu2-toggle").addEventListener("click", () => { $("#gpu2-block").hidden = !$("#gpu2-block").hidden; syncKind(); saveRig(); schedule(); }); $("#filters").addEventListener("change", schedule); $("#filters").addEventListener("submit", (e) => { e.preventDefault(); search(false); }); $("#search").addEventListener("input", schedule); $("#more").addEventListener("click", () => search(true)); $("#d-close").addEventListener("click", () => $("#detail").close()); $("#detail").addEventListener("click", (e) => { if (e.target === $("#detail")) $("#detail").close(); }); $("#detail").addEventListener("close", () => { state.detailKey = null; }); const opt = $("#optout"); opt.checked = Telemetry.optedOut; if (Telemetry.gpc) $("#gpc-note").hidden = false; opt.addEventListener("change", () => Telemetry.setOptOut(opt.checked)); Telemetry.setBuilder(() => { if (!META) return null; const r = rig(); const q = query(); return { ...hardwareFields(), browser_family: browserFamily(), os_family: osFamily(), webgpu_vendor: DETECTED.vendor, model_family: q.family, size_bucket: q.size, context: q.context, kv_type: q.kv_type, priority: q.priority, min_bits: q.min_bits, sort: q.sort, fits_only: q.fits_only, result_count: visit.lastResults, families_searched: [...visit.families].slice(0, 5), distinct_queries: visit.queries.size, searched: visit.searched, top_model: visit.top && visit.top.key, top_quant: visit.top && visit.top.quant, top_fit: visit.top && visit.top.fit, models_viewed: visit.viewed.slice(0, 10), repos_clicked: visit.clicked.slice(0, 5), commands_copied: [...visit.copied], hardware_source: r.kind === "gpu" && customCard() ? "custom" : "preset", }; }); search(false); } const DETECTED = { vendor: null }; async function detectHint() { // Only a hint: browsers can't tell how much VRAM or memory there is. try { const plat = (navigator.userAgentData && navigator.userAgentData.platform) || navigator.platform || ""; if (/mac/i.test(plat)) { $('input[name="kind"][value="unified"]').checked = true; syncKind(); const h = $("#detect-hint"); h.hidden = false; h.textContent = "This looks like a Mac. Set your memory size: browsers can't read it."; } if (navigator.gpu) { const a = await navigator.gpu.requestAdapter(); const v = a && a.info && a.info.vendor; if (v && /^[a-z0-9 ._+-]{1,24}$/i.test(v)) DETECTED.vendor = v.toLowerCase(); } } catch (e) {} } function browserFamily() { const ua = navigator.userAgent; if (/Edg\//.test(ua)) return "edge"; if (/Firefox\//.test(ua)) return "firefox"; if (/Chrome\//.test(ua)) return "chrome"; if (/Safari\//.test(ua)) return "safari"; return "other"; } function osFamily() { const ua = navigator.userAgent; if (/iPhone|iPad/.test(ua)) return "ios"; if (/Android/.test(ua)) return "android"; if (/Mac OS X/.test(ua)) return "macos"; if (/Windows/.test(ua)) return "windows"; if (/Linux/.test(ua)) return "linux"; return "other"; } boot(); })();