"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 queue = []; let enabled = true; function send(beacon) { if (!queue.length || optedOut || !enabled) { queue = []; return; } const batch = queue.splice(0, 50); const body = JSON.stringify({ events: batch }); 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(() => {}); } if (queue.length) send(beacon); } setInterval(() => send(false), 10000); document.addEventListener("visibilitychange", () => { if (document.visibilityState === "hidden") send(true); }); window.addEventListener("pagehide", () => send(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) {} if (optedOut) queue = []; }, setEnabled(v) { enabled = v; }, track(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; queue.push(ev); if (queue.length >= 20) send(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)); } 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) { Telemetry.track(reason, { model_family: q.family, parameter_bucket: q.size, quantization: q.quant, target_context: q.context, priority: q.priority, sort: q.sort, result_count: data.total, ...hwFields(), }); } } 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 shown(r) { return r ? { recommendation_score: Math.round(r.score * 10) / 10, fit_class: r.memory && r.memory.fit } : {}; } function trackClick(id, rank, r) { const q = state.lastQuery || readQuery(); Telemetry.track("model_click", { selected_model: id, selected_model_rank: rank, target_context: q.context, priority: q.priority, ...shown(r), ...hwFields() }); } // ------------------------------------------------------------------ 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); const q = state.lastQuery || readQuery(); Telemetry.track("model_select", { selected_model: r.model.id, selected_model_rank: rank, target_context: q.context, priority: q.priority, ...shown(r), ...hwFields() }); } 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(); Telemetry.track("compare", { compare_models: items.map((x) => x.model.id), target_context: q.context, priority: q.priority, ...hwFields() }); 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)], ["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" }, "Quality is relative within the same base model: more bits usually keep more quality, by an amount that varies. Speed appears only 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(); Telemetry.track("model_view", { selected_model: id, selected_model_rank: rank ?? null, target_context: q.context, priority: q.priority, ...shown(r), ...hwFields() }); 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", "Downloads"].map((h, i) => el("th", { class: i === 4 ? "num" : null }, h)))), el("tbody", {}, d.siblings.map((s) => el("tr", {}, el("td", {}, 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" }, fmtNum(s.model.downloads)))))))] : []; 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.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() }; 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; Telemetry.track("hardware_test", { ...hwFields(), hardware_source: "detected", webgpu_score: hw.quick_score, benchmark_type: hw.quick_score != null ? "webgpu_quick" : null, benchmark_version: hw.quick_score != null ? window.HW.BENCH_VERSION : null, benchmark_duration_ms: hw.duration_ms, }); 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.track("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}`, `# 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"]; 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_submission", 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. const hasFilters = /[?&](family|size|quant|priority)=/.test(location.search); if (window.matchMedia("(max-width: 900px)").matches && !hasFilters) $("#more-filters").open = false; 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(); })();