Spaces:
Running
Running
Vramwise: decision models (MATILDA-jev, JEV, Decider), linear-attention + packed FP4 support
afcfd33 verified Download fitcheck/app.js from CyberMax-tools/cybermax: direct link, hf CLI and curl.
- Browser
- Download file 18.1 kB
-
https://huggingface.co/spaces/CyberMax-tools/cybermax/resolve/main/fitcheck/app.js
- Command line
-
hf download hf://spaces/CyberMax-tools/cybermax/fitcheck/app.js
-
curl -L -o app.js https://huggingface.co/spaces/CyberMax-tools/cybermax/resolve/main/fitcheck/app.js
18.1 kB
| /* Vramwise UI. © 2026 CyberMax. All rights reserved. */ | |
| (function () { | |
| "use strict"; | |
| var F = window.Vramwise; | |
| var HF = "https://huggingface.co"; | |
| var $ = function (id) { return document.getElementById(id); }; | |
| var PRESETS = [ | |
| ["Qwen3 8B", "Qwen/Qwen3-8B"], ["Llama 3.1 8B", "meta-llama/Llama-3.1-8B-Instruct"], ["gpt-oss 20B", "openai/gpt-oss-20b"], | |
| ["Qwen3 30B-A3B", "Qwen/Qwen3-30B-A3B"], ["Gemma 3 27B", "google/gemma-3-27b-it"], ["Mistral Small 24B", "mistralai/Mistral-Small-3.2-24B-Instruct-2506"], | |
| ["Qwen3 32B", "Qwen/Qwen3-32B"], ["Llama 3.3 70B", "meta-llama/Llama-3.3-70B-Instruct"], ["gpt-oss 120B", "openai/gpt-oss-120b"], | |
| ["DeepSeek V3", "deepseek-ai/DeepSeek-V3"] | |
| ]; | |
| // One-pass decision / scoring models (no text generation). Ids checked on the Hugging Face API 15 Oct 2026; sizes are | |
| // always read live from each repo, never stored here. | |
| var DECISION_PRESETS = [ | |
| ["MATILDA-jev v1", "Maincode/matilda-jev-v1"], ["MATILDA-jev v1.5", "Maincode/matilda-jev-v1.5"], | |
| ["MATILDA-jev FP4", "Maincode/matilda-jev-fp4"], ["Matilda Decision v1", "Maincode/matilda-decision-v1"], | |
| ["JEV 9B", "autotrust/JEV-9B"], ["JEV 27B", "autotrust/JEV-27B"], ["JEV 35B (MoE)", "autotrust/JEV-35B"], | |
| ["JEV 35B NVFP4", "autotrust/JEV-35B-NVFP4"], ["pplx-decider 27B", "perplexity-ai/pplx-decider-v1.1-27b"], | |
| ["Decider 2B", "Mapika/decider-2b"], ["Decider 4B", "Mapika/decider-4b"] | |
| ]; | |
| var CTX = [2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144]; | |
| var model = null; // describe() output, possibly edited | |
| var kind = "gpu"; | |
| var lastRows = []; | |
| var loadSeq = 0; | |
| function toast(msg) { var t = $("toast"); t.textContent = msg; t.classList.add("show"); setTimeout(function () { t.classList.remove("show"); }, 1800); } | |
| function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { "&": "&", "<": "<", ">": ">", '"': """ }[c]; }); } | |
| function opt(v, t, sel) { var o = document.createElement("option"); o.value = v; o.textContent = t; if (sel) o.selected = true; return o; } | |
| function save() { try { localStorage.setItem("fitcheck", JSON.stringify(state())); } catch (e) {} } | |
| function load() { try { return JSON.parse(localStorage.getItem("fitcheck") || "{}"); } catch (e) { return {}; } } | |
| // ---------- hardware controls ---------- | |
| F.GPUS.forEach(function (g) { $("gpu").appendChild(opt(g.name, g.name, g.name === "RTX 4090 24GB")); }); | |
| F.APPLE.forEach(function (a) { $("chip").appendChild(opt(a.name, a.name, a.name === "M4 Pro")); }); | |
| F.UNIFIED.forEach(function (u) { $("unified").appendChild(opt(u.name, u.name)); }); | |
| CTX.forEach(function (c) { $("ctx").appendChild(opt(c, F.fmtCtx(c) + " tokens", c === 8192)); }); | |
| function fillMacMem(pref) { | |
| var chip = F.APPLE.filter(function (a) { return a.name === $("chip").value; })[0]; | |
| var sel = $("mac-mem"); sel.innerHTML = ""; | |
| chip.mem.forEach(function (m) { sel.appendChild(opt(m, m + " GB", String(m) === String(pref))); }); | |
| if (!sel.value || sel.selectedIndex < 0) sel.selectedIndex = sel.options.length - 1; | |
| } | |
| fillMacMem(48); | |
| function setKind(k) { | |
| kind = k; | |
| document.querySelectorAll(".seg button").forEach(function (b) { b.setAttribute("aria-checked", String(b.dataset.kind === k)); }); | |
| document.querySelectorAll("[data-hw]").forEach(function (d) { d.hidden = d.dataset.hw !== k; }); | |
| render(); | |
| } | |
| document.querySelectorAll(".seg button").forEach(function (b) { b.addEventListener("click", function () { setKind(b.dataset.kind); }); }); | |
| function hardware() { | |
| if (kind === "mac") return F.appleHardware($("chip").value, Number($("mac-mem").value), $("mac-raised").checked); | |
| if (kind === "unified") return F.unifiedHardware($("unified").value); | |
| if (kind === "custom") return { label: "Custom " + $("c-mem").value + " GB", usable: Number($("c-mem").value) || 0, bw: Number($("c-bw").value) || 1, ramGB: 0 }; | |
| return F.gpuHardware($("gpu").value, $("gpu-count").value, $("ram").value, $("ram-bw").value); | |
| } | |
| // ---------- model loading ---------- | |
| function getJSON(url, retried) { | |
| return fetch(url).then(function (r) { | |
| if (r.status === 429 && !retried) return new Promise(function (ok) { setTimeout(ok, 2500); }).then(function () { return getJSON(url, true); }); | |
| if (!r.ok) { var e = new Error("HTTP " + r.status); e.status = r.status; throw e; } | |
| return r.json(); | |
| }); | |
| } | |
| function configFor(ids) { | |
| // Try each repo's config.json in turn (gated repos return 401). | |
| var i = 0; | |
| function next() { | |
| if (i >= ids.length) return Promise.resolve(null); | |
| var id = ids[i++]; | |
| return getJSON(HF + "/" + id + "/resolve/main/config.json").then(function (c) { c.__from = id; return c; }, next); | |
| } | |
| return next(); | |
| } | |
| function baseModels(meta) { | |
| var b = meta.cardData && meta.cardData.base_model; | |
| return (Array.isArray(b) ? b : b ? [b] : []).filter(function (x) { return typeof x === "string" && x.indexOf("/") > 0; }); | |
| } | |
| function loadModel(raw) { | |
| var id = F.parseModelId(raw); | |
| if (!id) { info('<span class="err">Enter a model id like <b>Qwen/Qwen3-8B</b> or paste its Hugging Face URL.</span>'); return Promise.resolve(); } | |
| $("model").value = id; | |
| var seq = ++loadSeq; | |
| info("Reading <b>" + esc(id) + "</b> from Hugging Face…"); | |
| return getJSON(HF + "/api/models/" + id + "?expand[]=safetensors&expand[]=gguf&expand[]=config&expand[]=gated&expand[]=cardData&expand[]=pipeline_tag&expand[]=tags") | |
| .then(function (meta) { | |
| var name = id.split("/")[1], org = id.split("/")[0]; | |
| // Gated repos (Llama, Gemma) refuse config.json without a login: use a public mirror of the same weights. | |
| var tries = meta.gated ? [] : [id]; | |
| baseModels(meta).forEach(function (b) { if (!(meta.gated && b.split("/")[0] === org)) tries.push(b); }); | |
| if (meta.gated || !tries.length || !(meta.safetensors || meta.config)) tries.push("unsloth/" + name); | |
| return configFor(tries).then(function (cfg) { return { meta: meta, cfg: cfg }; }); | |
| }) | |
| .then(function (x) { | |
| if (seq !== loadSeq) return; | |
| if (!x.meta.id) x.meta.id = id; | |
| model = F.describe(x.meta, x.cfg); | |
| model.configFrom = x.cfg && x.cfg.__from; | |
| fillAdv(); | |
| showInfo(x.meta); | |
| render(); | |
| save(); | |
| }) | |
| .catch(function (e) { | |
| if (seq !== loadSeq) return; | |
| info('<span class="err">' + (e.status === 404 || e.status === 401 ? "Model not found (or private): <b>" + esc(id) + "</b>. Check the spelling, or fill in the model details below." : "Couldn't reach Hugging Face (" + esc(e.message) + "). Try again, or fill in the model details below.") + "</span>"); | |
| $("adv").open = true; | |
| }); | |
| } | |
| function info(html) { $("model-info").innerHTML = html; } | |
| function showInfo(meta) { | |
| var m = model, tags = []; | |
| tags.push(F.fmtParams(m.params) + " parameters"); | |
| if (m.decision) tags.push("one-pass model · no text generation"); | |
| if (m.moe) tags.push("MoE · " + F.fmtParams(m.activeParams) + " active" + (m.experts ? " · " + m.topK + " of " + m.experts + " experts" : "")); | |
| if (m.layers) tags.push(m.layers + " layers"); | |
| if (m.mla) tags.push("MLA cache"); else if (m.kvHeads) tags.push(m.kvHeads + " KV heads"); | |
| if (m.window) tags.push(m.slidingLayers + " sliding-window layers"); | |
| if (m.linearLayers) tags.push(m.linearLayers + " linear-attention layers (fixed state)"); | |
| if (m.maxContext) tags.push(F.fmtCtx(m.maxContext) + " max context"); | |
| if (m.nativeLabel) tags.push("files: " + m.nativeLabel); | |
| var note = ""; | |
| if (m.configFrom && m.configFrom !== m.id) note = '<div class="hint">Architecture read from <a href="' + HF + "/" + esc(m.configFrom) + '" target="_blank" rel="noopener">' + esc(m.configFrom) + "</a>" + (m.gated ? " because the original repo is gated." : ".") + "</div>"; | |
| if (!m.hasShape) note += '<div class="hint err">Couldn\'t read layers/KV heads, so the KV cache is not counted. Fill them in under Model details.</div>'; | |
| if (!m.params) note += '<div class="hint err">No parameter count published for this repo. Enter it under Model details.</div>'; | |
| info('<a href="' + HF + "/" + esc(m.id) + '" target="_blank" rel="noopener"><b>' + esc(m.id) + '</b></a><div class="tags">' + | |
| tags.map(function (t) { return '<span class="tag">' + esc(t) + "</span>"; }).join("") + "</div>" + note); | |
| } | |
| function fillAdv() { | |
| $("m-params").value = model.params ? +(model.params / 1e9).toFixed(2) : ""; | |
| $("m-active").value = model.activeParams ? +(model.activeParams / 1e9).toFixed(2) : ""; | |
| $("m-layers").value = model.layers || ""; | |
| $("m-kvheads").value = model.mla ? "" : model.kvHeads || ""; | |
| $("m-headdim").value = model.mla ? "" : model.headDim || ""; | |
| $("m-maxctx").value = model.maxContext || ""; | |
| $("m-kvheads").disabled = $("m-headdim").disabled = !!model.mla; | |
| } | |
| function readAdv() { | |
| if (!model) model = F.describe({ id: "custom" }, {}); | |
| var p = Number($("m-params").value) * 1e9, a = Number($("m-active").value) * 1e9; | |
| if (p) { if (model.nativeBytes && model.params) model.nativeBytes *= p / model.params; model.params = p; } | |
| model.activeParams = a && a <= model.params ? a : model.params; | |
| model.moe = model.activeParams < model.params * 0.97; | |
| model.layers = Number($("m-layers").value) || 0; | |
| if (!model.mla) { model.kvHeads = Number($("m-kvheads").value) || 0; model.headDim = Number($("m-headdim").value) || 0; } | |
| model.fullLayers = model.layers - (model.slidingLayers || 0); | |
| if (model.fullLayers < 0) { model.fullLayers = model.layers; model.slidingLayers = 0; } | |
| model.maxContext = Number($("m-maxctx").value) || 0; | |
| model.hasShape = !!(model.layers && (model.mla || (model.kvHeads && model.headDim))); | |
| render(); save(); | |
| } | |
| ["m-params", "m-active", "m-layers", "m-kvheads", "m-headdim", "m-maxctx"].forEach(function (id) { $(id).addEventListener("change", readAdv); }); | |
| // ---------- results ---------- | |
| function render() { | |
| var tb = document.querySelector("#table tbody"); | |
| if (!model || !model.params) { tb.innerHTML = ""; $("verdict").textContent = "Pick a model to see if it fits."; lastRows = []; return; } | |
| var hw = hardware(), ctx = Number($("ctx").value), kvBits = F.KV_TYPES[$("kv").value]; | |
| var rows = F.quantRows(model).map(function (q) { return { q: q, r: F.estimate(model, hw, q, ctx, kvBits) }; }); | |
| lastRows = rows; | |
| var best = rows.filter(function (x) { return x.r.fit === "yes"; })[0] || rows.filter(function (x) { return x.r.fit === "tight"; })[0]; | |
| var off = rows.filter(function (x) { return x.r.fit === "offload"; })[0]; | |
| var name = model.id.split("/").pop(); | |
| var dec = !!model.decision; | |
| var ms = function (r) { var x = r.minMs || 0; return x >= 10 ? x.toFixed(0) : x.toFixed(1); }; | |
| var v; | |
| if (best) v = "Yes: " + esc(name) + " runs on " + esc(hw.label) + " at <u>" + esc(best.q.label.split(" /")[0]) + "</u>" + | |
| "<small>" + F.fmtGB(best.r.total) + " GB of " + F.fmtGB(best.r.usable) + " GB usable at " + F.fmtCtx(ctx) + (dec ? " input tokens · one forward pass per call, at least " + ms(best.r) + " ms each (memory floor)" : " context · about " + Math.round(best.r.tpsLo) + "–" + Math.round(best.r.tpsHi) + " tokens/s") + "</small>"; | |
| else if (off) v = "Only with CPU offload: " + esc(name) + " at " + esc(off.q.label.split(" /")[0]) + " on " + esc(hw.label) + "<small>" + Math.round(off.r.gpuShare * 100) + "% of the weights fit on the GPU; the rest runs from system RAM" + (dec ? ", so every call is slow." : " at roughly " + off.r.tpsLo.toFixed(1) + "–" + off.r.tpsHi.toFixed(1) + " tokens/s.") + "</small>"; | |
| else v = "No: " + esc(name) + " doesn't fit " + esc(hw.label) + "<small>Even " + esc(rows[rows.length - 1].q.label) + " needs " + F.fmtGB(rows[rows.length - 1].r.total) + " GB and " + F.fmtGB(rows[rows.length - 1].r.usable) + " GB is usable. Try a shorter context, a smaller model or more memory.</small>"; | |
| $("verdict").innerHTML = v; | |
| tb.innerHTML = rows.map(function (x) { | |
| var r = x.r, pct = Math.min(100, r.total / r.usable * 100); | |
| var fitTxt = { yes: "Fits", tight: "Tight", offload: "Offload", no: "No" }[r.fit]; | |
| var speed = r.fit === "no" ? "—" : dec ? (r.minMs ? "≥ " + ms(r) + " ms" : "slow") : r.tpsHi >= 10 ? Math.round(r.tpsLo) + "–" + Math.round(r.tpsHi) : r.tpsLo.toFixed(1) + "–" + r.tpsHi.toFixed(1); | |
| return '<tr class="' + (best && x === best ? "best" : "") + '"><td><span class="q">' + esc(x.q.label) + '</span><span class="note">' + x.q.bits.toFixed(2).replace(/\.?0+$/, "") + " bits · " + esc(x.q.note) + "</span></td>" + | |
| '<td class="num">' + F.fmtGB(r.weights) + ' GB</td><td class="num">' + F.fmtGB(r.kv) + ' GB</td>' + | |
| '<td class="num">' + F.fmtGB(r.total) + ' GB<div class="meter"><i class="' + (r.total > r.usable ? "over" : "") + '" style="width:' + pct.toFixed(0) + '%"></i></div></td>' + | |
| '<td><span class="pill ' + r.fit + '">' + fitTxt + "</span></td>" + | |
| '<td class="num">' + (r.maxCtx ? F.fmtCtx(r.maxCtx) : "—") + '</td><td class="num">' + speed + "</td></tr>"; | |
| }).join(""); | |
| $("th-speed").textContent = dec ? "Per call" : "Speed (tok/s)"; | |
| $("th-ctx").textContent = dec ? "Max input" : "Max context"; | |
| $("decision-note").hidden = !dec; | |
| $("legend").textContent = hw.label + ": " + F.fmtGB(hw.usable * F.GB) + " GB usable" + (hw.unified ? " (unified memory)" : "") + ", " + hw.bw + " GB/s." + (kind === "gpu" && hw.ramGB ? " Offload uses up to " + Math.round(hw.ramGB * 0.85) + " GB of system RAM." : ""); | |
| syncUrl(); | |
| } | |
| ["gpu", "gpu-count", "ram", "ram-bw", "mac-mem", "mac-raised", "unified", "c-mem", "c-bw", "ctx", "kv"].forEach(function (id) { | |
| $(id).addEventListener("change", function () { render(); save(); }); | |
| $(id).addEventListener("input", function () { if ($(id).type === "number") render(); }); | |
| }); | |
| $("chip").addEventListener("change", function () { fillMacMem($("mac-mem").value); render(); save(); }); | |
| // ---------- state, share, CSV ---------- | |
| function state() { | |
| return { model: model ? model.id : $("model").value, kind: kind, gpu: $("gpu").value, n: $("gpu-count").value, ram: $("ram").value, rbw: $("ram-bw").value, | |
| chip: $("chip").value, mem: $("mac-mem").value, raised: $("mac-raised").checked ? 1 : 0, uni: $("unified").value, cm: $("c-mem").value, cbw: $("c-bw").value, | |
| ctx: $("ctx").value, kv: $("kv").value }; | |
| } | |
| function applyState(s) { | |
| if (s.kind) kind = s.kind; | |
| [["gpu", "gpu"], ["n", "gpu-count"], ["ram", "ram"], ["rbw", "ram-bw"], ["chip", "chip"], ["uni", "unified"], ["cm", "c-mem"], ["cbw", "c-bw"], ["ctx", "ctx"], ["kv", "kv"]].forEach(function (p) { | |
| if (s[p[0]] !== undefined && s[p[0]] !== null && s[p[0]] !== "") $(p[1]).value = s[p[0]]; | |
| }); | |
| fillMacMem(s.mem || 48); | |
| $("mac-raised").checked = String(s.raised) === "1"; | |
| } | |
| function syncUrl() { | |
| var s = state(), q = new URLSearchParams(); | |
| Object.keys(s).forEach(function (k) { if (s[k] !== "" && s[k] !== undefined) q.set(k, s[k]); }); | |
| history.replaceState(null, "", "?" + q.toString()); | |
| } | |
| $("btn-share").addEventListener("click", function () { | |
| var url = location.href; | |
| (navigator.clipboard ? navigator.clipboard.writeText(url) : Promise.reject()).then(function () { toast("Link copied"); }, function () { prompt("Copy this link", url); }); | |
| }); | |
| $("btn-csv").addEventListener("click", function () { | |
| if (!lastRows.length) return; | |
| var hw = hardware(); | |
| var lines = [["model", "hardware", "context", "quantization", "bits_per_weight", "weights_gb", "kv_cache_gb", "total_gb", "usable_gb", "fits", "max_context", "tok_s_low", "tok_s_high", "min_ms_per_call"].join(",")]; | |
| lastRows.forEach(function (x) { | |
| var r = x.r; | |
| lines.push([model.id, '"' + hw.label + '"', $("ctx").value, '"' + x.q.label + '"', x.q.bits.toFixed(2), F.fmtGB(r.weights), F.fmtGB(r.kv), F.fmtGB(r.total), F.fmtGB(r.usable), r.fit, r.maxCtx || 0, model.decision ? "" : r.tpsLo.toFixed(1), model.decision ? "" : r.tpsHi.toFixed(1), model.decision && r.minMs ? r.minMs.toFixed(1) : ""].join(",")); | |
| }); | |
| var a = document.createElement("a"); | |
| a.href = URL.createObjectURL(new Blob([lines.join("\n") + "\n"], { type: "text/csv" })); | |
| a.download = "vramwise-" + model.id.replace(/[^\w.-]+/g, "_") + ".csv"; | |
| document.body.appendChild(a); a.click(); a.remove(); | |
| }); | |
| // ---------- model input ---------- | |
| [[PRESETS, "presets"], [DECISION_PRESETS, "presets-decision"]].forEach(function (g) { | |
| g[0].forEach(function (p) { | |
| var b = document.createElement("button"); b.className = "chip"; b.textContent = p[0]; b.type = "button"; | |
| b.addEventListener("click", function () { loadModel(p[1]); }); | |
| $(g[1]).appendChild(b); | |
| }); | |
| }); | |
| $("btn-load").addEventListener("click", function () { loadModel($("model").value); }); | |
| $("model").addEventListener("keydown", function (e) { if (e.key === "Enter") loadModel($("model").value); }); | |
| var suggestTimer; | |
| $("model").addEventListener("input", function () { | |
| clearTimeout(suggestTimer); | |
| var q = $("model").value.trim(); | |
| if (q.length < 3 || /\s/.test(q)) return; | |
| suggestTimer = setTimeout(function () { | |
| getJSON(HF + "/api/models?search=" + encodeURIComponent(q) + "&sort=downloads&limit=8").then(function (list) { | |
| var dl = $("model-suggest"); dl.innerHTML = ""; | |
| list.forEach(function (m) { dl.appendChild(opt(m.id, m.id)); }); | |
| }, function () {}); | |
| }, 300); | |
| }); | |
| // ---------- start ---------- | |
| var params = new URLSearchParams(location.search); | |
| var init = {}; | |
| params.forEach(function (v, k) { init[k] = v; }); | |
| if (!init.model) init = load(); | |
| applyState(init); | |
| setKind(kind); | |
| loadModel(init.model || "Qwen/Qwen3-8B"); | |
| window.fitcheckApp = { loadModel: loadModel, rows: function () { return lastRows; }, model: function () { return model; } }; | |
| if ("serviceWorker" in navigator && location.protocol === "https:") navigator.serviceWorker.register("sw.js").catch(function () {}); | |
| })(); | |