codelion's picture
Record one summary per visit instead of every click; hourly writes to data/incoming; monthly compaction
a866fc9 verified
Raw History Blame Contribute Delete
43.9 kB
"use strict";
(function () {
const $ = (s, r = document) => r.querySelector(s);
const $$ = (s, r = document) => [...r.querySelectorAll(s)];
// Build DOM safely: all text goes through text nodes, never innerHTML.
function el(tag, attrs, ...kids) {
const n = document.createElement(tag);
for (const [k, v] of Object.entries(attrs || {})) {
if (v == null || v === false) continue;
if (k === "class") n.className = v;
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 === false) continue;
n.append(kid instanceof Node ? kid : document.createTextNode(String(kid)));
}
return n;
}
const TOP_FAMILIES = 9;
const RAM_CHIPS = [8, 16, 18, 24, 32, 36, 48, 64, 96, 128, 192];
const SIZE_LABEL = { "<3B": "Under 3B", "3-8B": "3–8B", "8-15B": "8–15B", "15-35B": "15–35B", "35-70B": "35–70B", "70B+": "70B+", MoE: "MoE" };
const PRIORITY_LABEL = { balanced: "Balanced", quality: "Quality", speed: "Speed", memory: "Least memory", long_context: "Long context" };
const CHIPS = [];
for (const g of [1, 2, 3, 4, 5]) for (const t of ["", " Pro", " Max", " Ultra"]) CHIPS.push(`Apple M${g}${t}`);
const state = {
meta: null,
sort: "recommended",
offset: 0,
results: [],
total: 0,
lastQuery: null,
hw: null,
ramSource: null, // "confirmed" | "estimated" | null
compare: new Map(),
pinned: null,
requestId: 0,
};
// ------------------------------------------------------------------ formatting
const fmtCtx = (n) => (n >= 262144 ? "256k" : n >= 1024 ? `${Math.round(n / 1024)}k` : String(n));
const fmtNum = (n) => (n == null ? "unknown" : n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : n >= 1e3 ? `${Math.round(n / 1e3)}k` : String(n));
const fmtParams = (p) => (p == null ? "size unknown" : p >= 1e9 ? `${(p / 1e9).toFixed(p >= 1e10 ? 0 : 1)}B` : `${Math.round(p / 1e6)}M`);
const fmtGB = (g) => (g == null ? "unknown" : `${g < 10 ? g.toFixed(1) : Math.round(g)}\u00a0GB`);
function fmtAgo(iso) {
if (!iso) return "unknown";
const days = (Date.now() - Date.parse(iso)) / 864e5;
if (!isFinite(days)) return "unknown";
if (days < 1) return "today";
const plural = (n, unit) => `${n} ${unit}${n === 1 ? "" : "s"} ago`;
if (days < 31) return plural(Math.round(days), "day");
if (days < 365) return plural(Math.max(1, Math.round(days / 30.4)), "month");
const y = days / 365;
return `${y < 1.95 ? y.toFixed(1) : Math.round(y)} years ago`;
}
const fitText = (fit) => ({ Comfortable: "comfortable fit", Likely: "likely fits", Borderline: "borderline", Unlikely: "unlikely to fit" }[fit] || "");
// ------------------------------------------------------------------ telemetry
const Telemetry = (() => {
// A browser privacy signal (GPC / Do Not Track) means "off" unless the user explicitly opts in here.
const gpc = navigator.globalPrivacyControl === true || navigator.doNotTrack === "1";
let optedOut = gpc;
try {
if (localStorage.getItem("mme-optout") === "1") optedOut = true;
else if (gpc && localStorage.getItem("mme-optin") === "1") optedOut = false;
} catch (e) {}
let sid = null;
try { sid = sessionStorage.getItem("mme-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("mme-sid", sid); } catch (e) {}
}
let enabled = true;
let buildSession = () => null; // set by the app: returns the visit's current summary or null
let lastSent = "";
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(() => {});
}
}
// One row per visit: re-sent only when the summary changed since the last send.
function sendSession(beacon) {
if (optedOut || !enabled) return;
const summary = buildSession();
if (!summary) return;
const ev = { event_type: "session", session_id: sid };
for (const [k, v] of Object.entries(summary)) {
if (v !== undefined && v !== null && v !== "" && !(Array.isArray(v) && !v.length)) ev[k] = v;
}
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("mme-optout", "1"); localStorage.removeItem("mme-optin"); }
else { localStorage.removeItem("mme-optout"); if (gpc) localStorage.setItem("mme-optin", "1"); }
} catch (e) {}
},
setEnabled(v) { enabled = v; },
setSessionBuilder(fn) { buildSession = fn; },
sendSession,
// A contribution the page makes on the user's behalf (the GPU test): one row, sent now.
contribute(type, fields) {
if (optedOut || !enabled) return;
const ev = { event_type: type, session_id: sid };
for (const [k, v] of Object.entries(fields || {})) if (v !== undefined && v !== null && v !== "") ev[k] = v;
post([ev], false);
},
// Submissions the user explicitly asked to send go out immediately, with a result.
async submit(type, fields) {
if (optedOut) return { ok: false, message: "Sending is turned off in Privacy settings on this page." };
const ev = { event_type: type, session_id: sid, ...fields };
Object.keys(ev).forEach((k) => (ev[k] === undefined || ev[k] === null || ev[k] === "") && delete ev[k]);
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, flags: (j.flags || [])[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." };
}
},
};
})();
// ------------------------------------------------------------------ controls
function chip(name, value, label, small, checked) {
const input = el("input", { type: "radio", name, value });
input.checked = !!checked;
return el("label", { class: "chip" }, input, el("span", {}, label, small ? el("small", {}, small) : null));
}
function radioValue(name) {
const r = $(`#query input[name="${name}"]:checked`);
return r ? r.value : "";
}
function setRadio(name, value) {
const r = $$(`#query input[name="${name}"]`).find((x) => x.value === String(value));
if (r) { r.checked = true; return true; }
return false;
}
function uncheck(name) {
$$(`#query input[name="${name}"]`).forEach((x) => (x.checked = false));
}
// ------------------------------------------------------------------ visit summary (the only analytics row)
const visit = { families: [], quants: [], queries: new Set(), query: null, top: null,
viewed: [], compared: [], clicked: [], engagedSent: false };
const pushCapped = (arr, v, cap) => { if (v && !arr.includes(v)) { arr.push(v); if (arr.length > cap) arr.shift(); } };
function noteQuery(q, data) {
visit.query = { ...q, result_count: data.total };
if (q.family) pushCapped(visit.families, q.family, 5);
if (q.quant) pushCapped(visit.quants, q.quant, 5);
visit.queries.add([q.family, q.size, q.quant, q.context, q.priority, q.ram_gb].join("|"));
const top = data.results && data.results[0];
if (top && q.sort === "recommended") {
visit.top = { id: top.model.id, score: Math.round(top.score * 10) / 10, fit: top.memory && top.memory.fit };
}
}
function noteModel(kind, id) {
pushCapped(visit[kind], id, kind === "viewed" ? 10 : 5);
if (!visit.engagedSent) { // the first real interaction sends the summary right away
visit.engagedSent = true;
Telemetry.sendSession(false);
}
}
Telemetry.setSessionBuilder(() => {
const q = visit.query;
if (!q) return null;
return {
model_family: q.family, parameter_bucket: q.size, quantization: q.quant, target_context: q.context,
priority: q.priority, sort: q.sort, result_count: q.result_count,
families_searched: visit.families, quants_searched: visit.quants, distinct_queries: visit.queries.size,
...hwFields(), webgpu_score: state.hw ? state.hw.quick_score : null,
top_model: visit.top && visit.top.id, top_model_score: visit.top && visit.top.score, top_model_fit: visit.top && visit.top.fit,
models_viewed: visit.viewed, models_compared: visit.compared, models_clicked: visit.clicked,
};
});
function currentRam() {
const v = parseInt(radioValue("ram"), 10);
return Number.isFinite(v) ? v : null;
}
function currentFamily() {
return radioValue("family") || $("#family-more").value || "";
}
function buildControls(m) {
const ramOpts = RAM_CHIPS.filter((g) => m.ram_classes.includes(g));
$("#ram-chips").replaceChildren(chip("ram", "", "Not sure", null, true), ...ramOpts.map((g) => chip("ram", g, `${g} GB`)));
$("#context-chips").replaceChildren(...m.contexts.map((c) => chip("context", c, fmtCtx(c), null, c === 8192)));
const fams = m.families.filter((f) => f.family !== "Other");
$("#family-chips").replaceChildren(chip("family", "", "Any", null, true),
...fams.slice(0, TOP_FAMILIES).map((f) => chip("family", f.family, f.family, String(f.count))));
const more = $("#family-more");
more.length = 1;
fams.slice(TOP_FAMILIES).forEach((f) => more.append(el("option", { value: f.family }, `${f.family} (${f.count})`)));
const other = m.families.find((f) => f.family === "Other");
if (other) more.append(el("option", { value: "Other" }, `Other (${other.count})`));
$("#size-chips").replaceChildren(chip("size", "", "Any", null, true), ...m.sizes.map((s) => chip("size", s, SIZE_LABEL[s] || s)));
const quants = m.quantizations.filter((q) => q !== "unknown");
$("#quant-chips").replaceChildren(chip("quant", "", "Any", null, true),
...quants.map((q) => chip("quant", q, q.replace("-bit", " bit"))), chip("quant", "unknown", "Unknown"));
$("#priority-chips").replaceChildren(...m.priorities.map((p) => chip("priority", p, PRIORITY_LABEL[p] || p, null, p === "balanced")));
}
function hwFields() {
const f = {};
const ram = currentRam();
if (ram) f.hardware_memory_class = ram;
f.hardware_source = state.ramSource === "confirmed" ? "confirmed" : state.hw ? "detected" : "none";
if (state.hw) {
f.webgpu_available = state.hw.webgpu_available;
f.gpu_capability_class = state.hw.capability;
f.gpu_vendor = state.hw.gpu_vendor;
f.gpu_arch = state.hw.gpu_arch;
f.cpu_cores = state.hw.cpu_cores;
f.browser_family = state.hw.browser_family;
f.os_family = state.hw.os_family;
}
return f;
}
async function loadMeta() {
const r = await fetch("/api/meta");
if (!r.ok) throw new Error("meta");
const m = await r.json();
state.meta = m;
buildControls(m);
$("#app-version").textContent = m.version;
$("#engine-version").textContent = m.engine;
const c = m.catalogue;
$("#cat-status").textContent = `${c.models.toLocaleString()} models indexed${c.degraded ? " from a cached copy" : ""}`;
if (!m.collection_enabled) Telemetry.setEnabled(false);
restoreFromUrl();
}
function restoreFromUrl() {
const p = new URLSearchParams(location.search);
const fam = p.get("family");
if (fam && !setRadio("family", fam) && [...$("#family-more").options].some((o) => o.value === fam)) {
$("#family-more").value = fam;
uncheck("family");
}
["size", "quant", "context", "priority"].forEach((k) => p.get(k) && setRadio(k, p.get(k)));
if (p.get("ram") && setRadio("ram", p.get("ram"))) state.ramSource = "confirmed";
updateRamHint();
}
function readQuery() {
const ram = currentRam();
return {
family: currentFamily() || null,
size: radioValue("size") || null,
quant: radioValue("quant") || null,
context: parseInt(radioValue("context"), 10) || 8192,
ram_gb: ram,
ram_source: ram ? (state.ramSource === "confirmed" ? "confirmed" : "estimated") : null,
priority: radioValue("priority") || "balanced",
sort: state.sort,
llm_only: !$("#non-llm").checked,
search: $("#search").value.trim() || null,
};
}
function syncUrl(q) {
const p = new URLSearchParams();
if (q.family) p.set("family", q.family);
if (q.size) p.set("size", q.size);
if (q.quant) p.set("quant", q.quant);
if (q.context !== 8192) p.set("context", q.context);
if (q.ram_gb && state.ramSource === "confirmed") p.set("ram", q.ram_gb);
if (q.priority !== "balanced") p.set("priority", q.priority);
history.replaceState(null, "", p.toString() ? `?${p}` : location.pathname);
}
function updateRamHint() {
if (!currentRam()) $("#ram-hint").textContent = "Or pick it above.";
else if (state.ramSource === "confirmed") $("#ram-hint").textContent = "Set by you.";
}
// ------------------------------------------------------------------ memory budget
function usableGB(ram) {
return ram ? ram * (ram <= 36 ? 0.67 : 0.75) : null;
}
// One scale per set of bars so they compare honestly. Very large models clip at
// twice the usable limit instead of squashing everything else.
function scaleFor(ram, totals) {
const usable = usableGB(ram);
const biggest = Math.max(0, ...totals.filter((t) => t != null));
if (usable) return Math.max(usable, Math.min(biggest, usable * 2)) * 1.06;
return Math.max(biggest, 4) * 1.1;
}
function paintBar(track, mem, scale, ram) {
const segs = track.querySelectorAll(".seg");
const limit = track.querySelector(".limit");
const w = mem && mem.weights_gb != null ? mem.weights_gb : 0;
const kv = mem && mem.kv_gb != null ? mem.kv_gb : 0;
const oh = mem && mem.overhead_gb != null ? mem.overhead_gb : 0;
const pct = (x) => `${Math.max(0, Math.min(100, (x / scale) * 100))}%`;
segs[0].style.width = pct(w);
segs[1].style.width = pct(Math.min(kv, Math.max(0, scale - w)));
segs[2].style.width = pct(Math.min(oh, Math.max(0, scale - w - kv)));
const usable = usableGB(ram);
limit.hidden = !usable;
if (usable) limit.style.left = pct(usable);
track.classList.toggle("over", !!(mem && usable && mem.total_gb > usable));
}
function miniBar(mem, scale, ram) {
const track = el("div", { class: "mini", "aria-hidden": "true" },
el("span", { class: "seg seg-w" }), el("span", { class: "seg seg-kv" }), el("span", { class: "seg seg-oh" }), el("span", { class: "limit" }));
paintBar(track, mem, scale, ram);
return track;
}
function renderBudget(r) {
const q = state.lastQuery || readQuery();
const ram = q.ram_gb;
const usable = usableGB(ram);
$("#budget-mac").textContent = ram ? `${ram} GB Mac${state.ramSource === "confirmed" ? "" : " (estimated)"}` : "Pick your Mac's memory to see what fits";
$("#budget-usable").textContent = usable ? `About ${Math.round(usable)} GB usable by the GPU` : "";
const mem = r && r.memory;
paintBar($("#budget-track"), mem, scaleFor(ram, [mem && mem.total_gb]), ram);
const line = $("#budget-model");
if (!r) {
line.textContent = state.lastQuery && state.total === 0 ? "No models match these filters." : "Loading models";
return;
}
const name = el("strong", {}, r.model.name);
if (!mem || mem.total_gb == null) {
line.replaceChildren(name, " has no size information, so its memory can't be estimated.");
return;
}
const parts = [name, ` at ${fmtCtx(q.context)} context needs about ${fmtGB(mem.total_gb)}`];
if (mem.fit) parts.push(": ", el("span", { class: `fit-${mem.fit}` }, fitText(mem.fit)), ".");
else parts.push(". Pick your Mac's memory to check the fit.");
parts.push(` ${fmtGB(mem.weights_gb)} of weights and ${fmtGB(mem.kv_gb)} of KV cache${mem.kv_rough ? " (rough)" : ""}.`);
line.replaceChildren(...parts);
$("#budget-track").setAttribute("aria-label",
`${r.model.name}: weights ${fmtGB(mem.weights_gb)}, KV cache ${fmtGB(mem.kv_gb)}, overhead ${fmtGB(mem.overhead_gb)}${usable ? `, GPU limit about ${Math.round(usable)} GB` : ""}`);
}
// ------------------------------------------------------------------ results
let debounce = null;
function scheduleExplore(reason) {
clearTimeout(debounce);
debounce = setTimeout(() => explore({ reason }), 220);
}
async function explore({ append = false, reason = "search" } = {}) {
const q = readQuery();
if (!append) state.offset = 0;
state.lastQuery = q;
const id = ++state.requestId;
$("#results").setAttribute("aria-busy", "true");
if (!append) $("#summary").textContent = "Finding models";
try {
const r = await fetch("/api/recommend", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ ...q, offset: state.offset, limit: 24 }),
});
if (!r.ok) throw new Error(`HTTP ${r.status}`);
const data = await r.json();
if (id !== state.requestId) return; // a newer query superseded this one
state.total = data.total;
state.results = append ? state.results.concat(data.results) : data.results;
renderResults(data, append);
syncUrl(q);
if (!append) noteQuery(q, data);
} catch (e) {
if (id !== state.requestId) return;
$("#summary").textContent = "";
$("#notices").replaceChildren(el("p", { class: "note" }, "Models couldn't be loaded. Check your connection, then change a filter to retry."));
} finally {
if (id === state.requestId) $("#results").removeAttribute("aria-busy");
}
}
function describeQuery(q) {
return [q.family || "all families", q.size ? SIZE_LABEL[q.size] || q.size : null, q.quant, `${fmtCtx(q.context)} context`]
.filter(Boolean).join(", ");
}
function renderResults(data, append) {
const q = state.lastQuery;
$("#summary").textContent = `${data.total.toLocaleString()} ${data.total === 1 ? "model" : "models"} for ${describeQuery(q)}`;
const notices = data.notices.map((n) => el("p", { class: "note" }, n));
if (!data.total) notices.push(el("p", { class: "note" }, "Nothing matches. Set Size or Quantization to Any, or clear the name filter."));
$("#notices").replaceChildren(...notices);
const list = $("#list");
if (!append) list.replaceChildren();
const scale = scaleFor(q.ram_gb, state.results.map((r) => r.memory.total_gb));
if (append) $$(".row .mini", list).forEach((bar, i) => state.results[i] && paintBar(bar, state.results[i].memory, scale, q.ram_gb));
data.results.forEach((r, i) => list.append(resultRow(r, data.offset + i, scale)));
state.offset = data.offset + data.results.length;
$("#more").hidden = state.offset >= data.total;
if (!append) {
state.pinned = state.results[0] || null;
renderBudget(state.pinned);
}
}
function resultRow(r, rank, scale) {
const m = r.model;
const mem = r.memory;
const q = state.lastQuery;
const quant = r.quant || m.quant;
const cmp = el("input", { type: "checkbox" });
cmp.checked = state.compare.has(m.id);
cmp.addEventListener("change", () => toggleCompare(r, cmp, rank));
const fitLabel = mem.fit
? el("span", { class: `fit-label fit-${mem.fit}` }, mem.fit)
: el("span", { class: "fit-label fit-none" }, mem.total_gb == null ? "size unknown" : q.ram_gb ? "unknown" : "set memory");
const moe = m.moe ? (m.active_params ? `, MoE with ${fmtParams(m.active_params)} active` : ", MoE") : "";
const row = el("li", { class: "row" },
el("div", { class: "row-main" },
el("div", { class: "row-title" },
el("button", { class: "row-name", type: "button", onclick: () => openDetail(m.id, rank, r) }, m.name)),
el("div", { class: "facts" },
el("span", { class: "tag" }, quant.label === "unknown" ? "quantization unknown" : quant.label),
el("span", {}, fmtParams(m.params) + moe),
m.pipeline === "image-text-to-text" ? el("span", {}, "vision") : null,
m.partial ? el("span", { class: "warn", title: "The repo holds far fewer weights than its name suggests" }, "partial or add-on") : null,
el("span", {}, `${fmtNum(m.downloads)} downloads`),
m.likes ? el("span", {}, `${fmtNum(m.likes)} likes`) : null,
el("span", {}, `updated ${fmtAgo(m.modified)}`),
r.community.benchmark_count ? el("span", {}, `${r.community.benchmark_count} MLX benchmark${r.community.benchmark_count > 1 ? "s" : ""}`) : null),
el("p", { class: "why" }, rowReason(r)),
el("div", { class: "row-actions" },
el("button", { type: "button", class: "linkish", onclick: () => openDetail(m.id, rank, r) }, "Details"),
el("label", { class: "check" }, cmp, "Compare"),
el("a", { href: m.url, target: "_blank", rel: "noopener", onclick: () => trackClick(m.id, rank, r) }, "View on Hugging Face"))),
el("div", { class: "row-fit" },
el("div", { class: "fit-line" }, el("span", { class: "fit-gb" }, mem.total_gb == null ? "?" : fmtGB(mem.total_gb)), fitLabel),
miniBar(mem, scale, q.ram_gb),
state.sort === "recommended" ? el("span", { class: "score", title: "Best-fit score from 0 to 100, explained under How it works" }, `Score ${Math.round(r.score)}`) : null));
const show = () => {
$$(".row.active").forEach((x) => x.classList.remove("active"));
row.classList.add("active");
renderBudget(r);
};
row.addEventListener("mouseenter", show);
row.addEventListener("focusin", show);
return row;
}
// The bar already shows fit and size, so lead with the reason that adds something.
function rowReason(r) {
const skip = /fit:|^Needs roughly|downloads\.$|^KV cache at/;
return r.reasons.find((t) => !skip.test(t)) || r.reasons[0] || "";
}
function trackClick(id) {
noteModel("clicked", id);
}
// ------------------------------------------------------------------ compare
function toggleCompare(r, box, rank) {
if (box.checked) {
if (state.compare.size >= 4) {
box.checked = false;
flashTray("Compare up to 4 models at a time.");
return;
}
state.compare.set(r.model.id, r);
noteModel("compared", r.model.id);
} else {
state.compare.delete(r.model.id);
}
renderTray();
}
function flashTray(msg) {
renderTray();
$("#compare-tray").hidden = false;
$("#compare-count").textContent = msg;
setTimeout(renderTray, 2200);
}
function renderTray() {
const n = state.compare.size;
$("#compare-tray").hidden = n === 0;
$("#compare-count").textContent = n === 1 ? "1 selected, pick another to compare" : `${n} models selected`;
$("#compare-open").disabled = n < 2;
}
function relQuality(bits) {
if (bits == null) return "unknown";
if (bits >= 16) return "reference (unquantized)";
if (bits >= 8) return "near reference";
if (bits >= 5) return "high";
if (bits >= 4) return "good";
if (bits >= 3) return "lower";
return "lowest";
}
function openCompare() {
const items = [...state.compare.values()];
const q = state.lastQuery || readQuery();
const scale = scaleFor(q.ram_gb, items.map((r) => r.memory.total_gb));
const qt = (r) => r.quant || r.model.quant;
const rows = [
["Quantization", (r) => qt(r).label],
["Parameters", (r) => fmtParams(r.model.params) + (r.model.moe ? ", MoE" : "")],
[`Memory at ${fmtCtx(q.context)}`, (r) => fmtGB(r.memory.total_gb)],
["Memory budget", (r) => miniBar(r.memory, scale, q.ram_gb), "compare-bar"],
["Weights", (r) => fmtGB(r.memory.weights_gb)],
["KV cache", (r) => (r.memory.kv_gb == null ? "unknown" : fmtGB(r.memory.kv_gb) + (r.memory.kv_rough ? " (rough)" : ""))],
["Fit", (r) => r.memory.fit || (q.ram_gb ? "unknown" : "set your memory")],
["Relative quality", (r) => relQuality(qt(r).bits)],
["Measured perplexity", (r) => (r.community.median_perplexity ? `${r.community.median_perplexity.toFixed(2)} on wikitext-2 (lower is better)` : "not measured yet")],
["Speed", (r) => (r.community.median_generation_tps ? `${r.community.median_generation_tps} tok/s median from community benchmarks` : "unknown, no community benchmarks yet")],
["Downloads", (r) => fmtNum(r.model.downloads)],
["Likes", (r) => fmtNum(r.model.likes)],
["Updated", (r) => fmtAgo(r.model.modified)],
["Community reports", (r) => (r.community.feedback_count ? `${r.community.feedback_count}${r.community.positive_share != null ? `, ${Math.round(r.community.positive_share * 100)}% positive` : ""}` : "none yet")],
];
const table = el("table", {},
el("thead", {}, el("tr", {}, el("th", {}, ""), items.map((r) => el("th", {}, el("a", { href: r.model.url, target: "_blank", rel: "noopener" }, r.model.name))))),
el("tbody", {}, rows.map(([label, f, cls]) => el("tr", { class: cls || null }, el("th", {}, label), items.map((r) => el("td", {}, f(r)))))));
$("#c-body").replaceChildren(
el("div", { class: "table-scroll" }, table),
el("p", { class: "scale-note" }, "Relative quality is a guess from bit width. Measured perplexity is comparable only between quantizations of the same base model (same tokenizer). Speed appears once people have benchmarked a model."));
$("#compare").showModal();
}
// ------------------------------------------------------------------ detail sheet
async function openDetail(id, rank, r) {
const q = state.lastQuery || readQuery();
const dlg = $("#detail");
$("#d-title").textContent = id.split("/")[1];
$("#d-body").replaceChildren(el("p", { class: "fine" }, "Loading model details"));
if (!dlg.open) dlg.showModal();
noteModel("viewed", id);
const params = new URLSearchParams({ context: q.context, priority: q.priority });
if (q.ram_gb) { params.set("ram_gb", q.ram_gb); if (q.ram_source) params.set("ram_source", q.ram_source); }
let d;
try {
const resp = await fetch(`/api/model/${id.split("/").map(encodeURIComponent).join("/")}?${params}`);
if (!resp.ok) throw new Error(String(resp.status));
d = await resp.json();
} catch (e) {
$("#d-body").replaceChildren(el("p", { class: "note" }, "Some model information isn't available right now. The Hugging Face page has the full details."),
el("p", {}, el("a", { href: `https://huggingface.co/${id}`, target: "_blank", rel: "noopener" }, "View on Hugging Face")));
return;
}
renderDetail(d, q, rank);
}
function renderDetail(d, q, rank) {
const m = d.model;
const quant = d.quant || m.quant;
const weights = d.files.filter((f) => /\.(safetensors|npz|gguf)$/.test(f.path));
const ctxRows = d.memory_by_context;
const scale = scaleFor(q.ram_gb, ctxRows.map((x) => x.total_gb));
const ctxBars = el("div", { class: "ctx-bars" }, ctxRows.flatMap((x) => [
el("span", { class: x.context === q.context ? "ctx cur" : "ctx" }, fmtCtx(x.context)),
miniBar(x, scale, q.ram_gb),
el("span", { class: "gb" }, fmtGB(x.total_gb)),
el("span", { class: `fitc fit-label ${x.exceeds_model_context || !x.fit ? "fit-none" : `fit-${x.fit}`}` },
x.exceeds_model_context ? "beyond max context" : x.fit || (q.ram_gb ? "unknown" : "set memory")),
]));
const sibs = d.siblings.length ? [
el("h3", {}, "Other quantizations of this base model"),
el("div", { class: "table-scroll" }, el("table", {},
el("thead", {}, el("tr", {}, ["Model", "Quantization", `Memory at ${fmtCtx(q.context)}`, "Fit", "Perplexity", "Downloads"].map((h, i) => el("th", { class: i >= 4 ? "num" : null }, h)))),
el("tbody", {}, [{ model: m, quant, memory: d.memory, community: d.community, self: true }, ...d.siblings].map((s) => el("tr", { class: s.self ? "current" : null },
el("td", {}, s.self ? el("span", {}, s.model.name) : el("button", { type: "button", class: "linkish", onclick: () => openDetail(s.model.id, null, s) }, s.model.name)),
el("td", {}, (s.quant || s.model.quant).label),
el("td", {}, fmtGB(s.memory.total_gb)),
el("td", { class: s.memory.fit ? `fit-${s.memory.fit}` : null }, s.memory.fit || "unknown"),
el("td", { class: "num" }, s.community && s.community.median_perplexity ? s.community.median_perplexity.toFixed(2) : "–"),
el("td", { class: "num" }, fmtNum(s.model.downloads))))))),
el("p", { class: "scale-note" }, "Perplexity on a fixed wikitext-2 slice, measured on Macs with the benchmark script. Lower is better, and it is only comparable within this table.")] : [];
const comm = d.community;
const moe = m.moe ? (m.active_params ? `, MoE with ${fmtParams(m.active_params)} active` : ", MoE") : "";
const body = [
el("p", { class: "sheet-lede" },
el("span", {}, quant.label + (quant.mode && !["affine", "float"].includes(quant.mode) ? ` (${quant.mode})` : "")),
el("span", {}, fmtParams(m.params) + moe),
d.memory.fit ? el("span", { class: `fit-label fit-${d.memory.fit}` }, `${d.memory.fit} at ${fmtCtx(q.context)}`) : null),
el("p", {}, el("a", { href: m.url, target: "_blank", rel: "noopener", onclick: () => trackClick(m.id, rank, null) }, `View ${m.id} on Hugging Face`)),
d.detail_error ? el("p", { class: "note" }, "Some model information isn't available: the config or file list couldn't be read, so estimates use parameter counts.") : null,
el("h3", {}, "Memory by context length"),
ctxBars,
el("p", { class: "scale-note" }, `Estimates, not measurements: weights + fp16 KV cache + about 1 GB overhead.${q.ram_gb ? ` The line marks about ${Math.round(usableGB(q.ram_gb))} GB usable by the GPU on a ${q.ram_gb} GB Mac.` : ""}`),
el("h3", {}, "Why it scores this way"),
el("ul", { class: "why-list" }, d.reasons.map((t) => el("li", {}, t))),
el("h3", {}, "About this repo"),
el("dl", { class: "kv" },
el("dt", {}, "Family"), el("dd", {}, m.family),
el("dt", {}, "Base model"), el("dd", {}, m.base_model || "unknown"),
el("dt", {}, "Pipeline"), el("dd", {}, m.pipeline || "unknown"),
el("dt", {}, "Downloads"), el("dd", {}, `${fmtNum(m.downloads)} in the last 30 days`),
el("dt", {}, "Likes"), el("dd", {}, fmtNum(m.likes)),
el("dt", {}, "Updated"), el("dd", {}, m.modified ? `${m.modified.slice(0, 10)}, ${fmtAgo(m.modified)}` : "unknown"),
el("dt", {}, "Files"), el("dd", {}, `${d.file_count} files, ${weights.length} weight ${weights.length === 1 ? "shard" : "shards"}`),
el("dt", {}, "Sources"), el("dd", {}, `quantization from ${quant.source}, size from ${m.params_source}, weights from ${d.memory.weights_source === "files" ? "exact file sizes" : "parameter count"}`)),
...sibs,
el("h3", {}, "Community data"),
el("p", {}, comm.benchmark_count || comm.feedback_count
? `${comm.benchmark_count} MLX benchmark${comm.benchmark_count === 1 ? "" : "s"}${comm.median_generation_tps ? `, median ${comm.median_generation_tps} tok/s generation` : ""}${comm.median_perplexity ? `, perplexity ${comm.median_perplexity.toFixed(2)} on wikitext-2` : ""}. ${comm.feedback_count} report${comm.feedback_count === 1 ? "" : "s"}${comm.positive_share != null ? `, ${Math.round(comm.positive_share * 100)}% positive` : ""}.`
: "No benchmarks or reports yet. Run this on your Mac to add the first:"),
el("pre", { class: "cmd" }, el("code", {}, benchCommand(m.id))),
feedbackForm(m, q),
];
$("#d-body").replaceChildren(...body.filter(Boolean));
}
function feedbackForm(m, q) {
const f = $("#feedback-tpl").content.firstElementChild.cloneNode(true);
const ram = $("select[name=ram]", f);
(state.meta ? state.meta.ram_classes : []).forEach((g) => ram.append(el("option", { value: g }, `${g} GB`)));
if (currentRam() && state.ramSource === "confirmed") ram.value = String(currentRam());
const chipSel = $("select[name=chip]", f);
CHIPS.forEach((c) => chipSel.append(el("option", { value: c }, c.replace("Apple ", ""))));
chipSel.append(el("option", { value: "other" }, "Other"));
const ctx = $("select[name=ctx]", f);
(state.meta ? state.meta.contexts : []).forEach((c) => ctx.append(el("option", { value: c }, fmtCtx(c))));
$$("input[name=tried]", f).forEach((r) => r.addEventListener("change", () => { $(".fb-yes", f).hidden = !(r.checked && r.value === "yes"); }));
f.addEventListener("submit", async (e) => {
e.preventDefault();
const out = $(".fb-out", f);
const tried = ($("input[name=tried]:checked", f) || {}).value;
if (!tried) { out.textContent = "Choose Yes, No or Planning to."; return; }
const fields = { selected_model: m.id, tried, target_context: q.context, priority: q.priority, ...hwFields() };
delete fields.cpu_cores;
if (tried === "yes") {
const oc = ($("input[name=outcome]:checked", f) || {}).value;
if (oc && oc.startsWith("q:")) fields.quality_rating = oc.slice(2);
if (oc && oc.startsWith("f:")) fields.failure_reason = oc.slice(2);
fields.reported_ram_gb = parseInt(ram.value, 10) || null;
fields.reported_mac_model = chipSel.value || null;
const tps = parseFloat($("input[name=tps]", f).value);
fields.reported_tokens_per_second = Number.isFinite(tps) && tps > 0 ? tps : null;
fields.reported_context = parseInt(ctx.value, 10) || null;
fields.notes = $("textarea[name=notes]", f).value.trim() || null;
}
const btn = $("button[type=submit]", f);
btn.disabled = true;
const res = await Telemetry.submit("feedback", fields);
btn.disabled = false;
out.textContent = res.ok ? "Report sent anonymously. Thank you." : res.message;
if (res.ok) $$("input, select, textarea, button", f).forEach((x) => (x.disabled = true));
});
return f;
}
// ------------------------------------------------------------------ hardware
async function detectHardware() {
const btn = $("#detect");
btn.disabled = true;
btn.textContent = "Detecting";
$("#hw-error").hidden = true;
let hw;
try {
hw = await window.HW.detect();
} catch (e) {
hw = { webgpu_available: false, error: "failed", capability: "unknown", memory_prior: null, browser_family: "other", os_family: "other" };
}
state.hw = hw;
btn.disabled = false;
btn.textContent = "Detect again";
const row = (k, v) => [el("dt", {}, k), el("dd", {}, v)];
$("#hw-facts").replaceChildren(
...row("GPU", hw.gpu_vendor ? `${hw.gpu_vendor}${hw.gpu_arch ? `, ${hw.gpu_arch}` : ""}` : hw.webgpu_available ? "not exposed" : "WebGPU unavailable"),
...row("Compute", hw.quick_score != null ? `${hw.quick_score.toLocaleString()}, ${hw.capability_label.toLowerCase()}` : "not measured"),
...row("CPU threads", hw.cpu_cores || "unknown"));
$("#hw-out").hidden = false;
const msgs = [];
if (!hw.webgpu_available) msgs.push("WebGPU isn't available in this browser. You can enter your memory manually.");
if (hw.os_family && !["macos", "other"].includes(hw.os_family)) msgs.push("This doesn't look like a Mac. MLX runs on Apple Silicon, so pick the memory of the Mac you'll use.");
const prior = hw.memory_prior;
if (prior) {
$("#hw-estimate").textContent = `Estimated capability: ${prior.label}. Is that right? Pick your exact memory above.`;
if (!currentRam() || state.ramSource !== "confirmed") {
setRadio("ram", prior.ram);
state.ramSource = "estimated";
$("#ram-hint").textContent = `Estimated: ${prior.note}.`;
}
} else {
$("#hw-estimate").textContent = "We couldn't reliably detect your memory configuration. Pick it above.";
}
if (msgs.length) { $("#hw-error").textContent = msgs.join(" "); $("#hw-error").hidden = false; }
$("#full-bench").disabled = !hw.webgpu_available;
explore({ reason: "filter" });
}
async function runFullBench() {
const btn = $("#full-bench");
const prog = $("#bench-progress");
btn.disabled = true;
prog.hidden = false;
prog.value = 0;
$("#bench-out").textContent = "Running. Keep this tab in front for 20 seconds.";
try {
const res = await window.HW.fullBenchmark((p) => { prog.value = p; });
$("#bench-out").textContent = `WebGPU compute score: ${res.score.toLocaleString()}. A relative browser GPU score for grouping hardware, not MLX speed or tokens per second.`;
Telemetry.contribute("browser_benchmark", {
...hwFields(), webgpu_score: res.score, benchmark_type: "webgpu_full", benchmark_version: res.version,
benchmark_duration_ms: res.duration_ms, gpu_capability_class: window.HW.capabilityClass(state.hw && state.hw.quick_score),
});
} catch (e) {
$("#bench-out").textContent = "The GPU test couldn't run in this browser.";
} finally {
btn.disabled = false;
prog.hidden = true;
}
}
// ------------------------------------------------------------------ MLX benchmark section
function benchCommand(model) {
const origin = location.origin;
return [
"pip install -U mlx-lm",
`curl -fsSLO ${origin}/bench/mlx_explorer_bench.py`,
`python mlx_explorer_bench.py --model ${model} --quality`,
`# to contribute the result, add: --submit ${origin}`,
].join("\n");
}
function updateBenchCmd() {
const v = $("#bench-model").value.trim();
const model = /^[A-Za-z0-9][A-Za-z0-9._-]*\/[A-Za-z0-9][A-Za-z0-9._-]*$/.test(v) ? v : "mlx-community/MODEL";
$("#bench-cmd").textContent = benchCommand(model);
}
const BENCH_KEYS = ["selected_model", "benchmark_type", "benchmark_version", "prompt_tokens", "generation_tokens", "prompt_tps",
"generation_tps", "ttft_ms", "peak_memory_gb", "chip", "reported_ram_gb", "mlx_version", "mlx_lm_version", "macos_major", "target_context",
"perplexity", "perplexity_stderr", "eval_dataset", "eval_tokens"];
async function submitBenchJson() {
const out = $("#bench-submit-out");
let obj;
try {
obj = JSON.parse($("#bench-json").value);
} catch (e) {
out.textContent = "That isn't valid JSON. Paste the block the script printed.";
return;
}
if (!obj || typeof obj !== "object" || Array.isArray(obj)) { out.textContent = "Paste a single JSON object, the block the script printed."; return; }
const fields = {};
for (const k of BENCH_KEYS) if (k in obj) fields[k] = obj[k];
const res = await Telemetry.submit("mlx_benchmark", fields);
out.textContent = res.ok
? res.flags.length ? `Result recorded and flagged for review: ${res.flags.join(", ")}.` : "Result recorded anonymously. Thank you."
: res.message;
}
// ------------------------------------------------------------------ wiring
function init() {
const form = $("#query");
form.addEventListener("submit", (e) => e.preventDefault());
form.addEventListener("change", (e) => {
const t = e.target;
if (t.id === "search") return;
if (t.name === "ram") {
state.ramSource = t.value ? "confirmed" : null;
updateRamHint();
scheduleExplore("filter");
return;
}
if (t.name === "family") $("#family-more").value = "";
if (t.id === "family-more") { if (t.value) uncheck("family"); else setRadio("family", ""); }
scheduleExplore("search");
});
let typing = null;
$("#search").addEventListener("input", () => { clearTimeout(typing); typing = setTimeout(() => explore({ reason: "search" }), 350); });
$$("#sort button").forEach((b) => b.addEventListener("click", () => {
state.sort = b.dataset.sort;
$$("#sort button").forEach((x) => x.setAttribute("aria-selected", String(x === b)));
explore({ reason: "filter" });
}));
$("#list").addEventListener("mouseleave", () => {
$$(".row.active").forEach((x) => x.classList.remove("active"));
renderBudget(state.pinned);
});
$("#more").addEventListener("click", () => explore({ append: true }));
$("#detect").addEventListener("click", detectHardware);
$("#full-bench").addEventListener("click", runFullBench);
$("#compare-open").addEventListener("click", openCompare);
$("#compare-clear").addEventListener("click", () => {
state.compare.clear();
$$("#list .row-actions input[type=checkbox]").forEach((x) => (x.checked = false));
renderTray();
});
$$("dialog [data-close]").forEach((b) => b.addEventListener("click", () => b.closest("dialog").close()));
$$("dialog").forEach((d) => d.addEventListener("click", (e) => { if (e.target === d) d.close(); }));
$("#bench-model").addEventListener("input", updateBenchCmd);
$("#copy-cmd").addEventListener("click", async () => {
const b = $("#copy-cmd");
try { await navigator.clipboard.writeText($("#bench-cmd").textContent); b.textContent = "Copied"; }
catch (e) { b.textContent = "Select the text to copy"; }
setTimeout(() => (b.textContent = "Copy command"), 1600);
});
$("#bench-submit").addEventListener("click", submitBenchJson);
const opt = $("#optout");
opt.checked = Telemetry.optedOut;
if (Telemetry.gpc) $("#gpc-note").hidden = false;
opt.addEventListener("change", () => Telemetry.setOptOut(opt.checked));
// On phones the rail sits above the results: keep only memory and context open.
// Wide layouts hide the toggle, so the section must always be open there
// (embedded iframes can start narrow and widen a moment later).
const narrow = window.matchMedia("(max-width: 900px)");
const hasFilters = /[?&](family|size|quant|priority)=/.test(location.search);
const syncFilters = () => { if (!narrow.matches) $("#more-filters").open = true; };
if (narrow.matches && window.innerWidth > 0 && !hasFilters) $("#more-filters").open = false;
narrow.addEventListener("change", syncFilters);
window.addEventListener("resize", syncFilters);
updateBenchCmd();
loadMeta()
.then(() => explore())
.catch(() => {
$("#notices").replaceChildren(el("p", { class: "note" }, "The model catalogue couldn't be loaded. Refresh the page in a moment."));
$("#budget-model").textContent = "The model catalogue couldn't be loaded.";
});
}
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init);
else init();
})();