Download demo/inspect.html from FluidInference/citenet-coreml: direct link, hf CLI and curl.
- Browser
- Download file 23 kB
-
https://huggingface.co/FluidInference/citenet-coreml/resolve/main/demo/inspect.html
- Command line
-
hf download hf://FluidInference/citenet-coreml/demo/inspect.html
-
curl -L -o inspect.html https://huggingface.co/FluidInference/citenet-coreml/resolve/main/demo/inspect.html
23 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>CiteNet</title> | |
| <style> | |
| :root { | |
| --bg: #f6f5f1; --panel: #ffffff; --ink: #1c1b19; --muted: #6b6860; --line: #e4e1d8; | |
| --ok: #1f7a4d; --ok-bg: #dff1e6; --bad: #c2321f; --bad-bg: #fbe1dc; --warn: #a86a00; --warn-bg: #fbedcc; | |
| --accent: #2f4fd6; --accent-bg: #e6eafc; --cell: #2f4fd6; --grid: #eeece6; | |
| --mono: ui-monospace, "SF Mono", Menlo, monospace; | |
| --text: "Iowan Old Style", "Palatino", Georgia, serif; | |
| } | |
| @media (prefers-color-scheme: dark) { | |
| :root { | |
| --bg: #141412; --panel: #1d1c1a; --ink: #ecebe6; --muted: #9a978e; --line: #2f2e2a; | |
| --ok: #4fc487; --ok-bg: #1d3528; --bad: #ff7a66; --bad-bg: #44211b; --warn: #f0b545; --warn-bg: #3d3018; | |
| --accent: #8ea2ff; --accent-bg: #252c4d; --cell: #8ea2ff; --grid: #2a2926; | |
| } | |
| } | |
| * { box-sizing: border-box; } | |
| body { margin: 0; background: var(--bg); color: var(--ink); font: 15px/1.45 -apple-system, BlinkMacSystemFont, "Inter", system-ui, sans-serif; } | |
| header { padding: 22px 28px 8px; display: flex; align-items: baseline; gap: 18px; flex-wrap: wrap; } | |
| h1 { margin: 0; font-size: 26px; letter-spacing: -0.02em; } | |
| header .tag { color: var(--muted); } | |
| header .tag b { color: var(--ink); font-weight: 600; } | |
| .stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; padding: 10px 28px 16px; } | |
| .stat { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; } | |
| .stat .k { color: var(--muted); font-size: 12px; text-transform: uppercase; letter-spacing: .06em; } | |
| .stat .v { font-size: 28px; font-weight: 650; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; } | |
| .stat .s { color: var(--muted); font-size: 13px; } | |
| main { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 16px; padding: 0 28px 20px; } | |
| .panel { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 14px 16px; min-width: 0; } | |
| .panel h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .07em; color: var(--muted); margin: 0 0 10px; font-weight: 600; } | |
| .toolbar { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; align-items: center; } | |
| button { font: inherit; font-size: 13px; border: 1px solid var(--line); background: var(--bg); color: var(--ink); padding: 6px 11px; border-radius: 8px; cursor: pointer; } | |
| button:hover { border-color: var(--accent); } | |
| button.primary { background: var(--accent); color: #fff; border-color: var(--accent); } | |
| .editor { position: relative; height: 470px; border: 1px solid var(--line); border-radius: 10px; background: var(--bg); } | |
| .editor .backdrop, .editor textarea { | |
| position: absolute; inset: 0; margin: 0; padding: 14px 16px; font: 17px/1.6 var(--text); white-space: pre-wrap; overflow-wrap: break-word; | |
| overflow-y: auto; border: 0; letter-spacing: 0; | |
| } | |
| .editor .backdrop { color: transparent; pointer-events: none; } | |
| .editor textarea { background: transparent; color: var(--ink); resize: none; outline: none; caret-color: var(--accent); } | |
| mark { color: transparent; border-radius: 3px; padding: 1px 0; } | |
| mark.ok { background: var(--ok-bg); box-shadow: inset 0 -2px 0 var(--ok); } | |
| mark.phantom { background: var(--bad-bg); box-shadow: inset 0 -2px 0 var(--bad); } | |
| mark.unknown { background: var(--warn-bg); box-shadow: inset 0 -2px 0 var(--warn); } | |
| mark.sel { outline: 2px solid var(--accent); } | |
| .legend { display: flex; gap: 14px; color: var(--muted); font-size: 13px; margin-top: 8px; flex-wrap: wrap; } | |
| .dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: -1px; } | |
| .list { display: flex; flex-direction: column; gap: 4px; max-height: 210px; overflow-y: auto; margin-bottom: 12px; } | |
| .row { display: grid; grid-template-columns: 74px minmax(0, 1fr) 54px; gap: 8px; align-items: center; padding: 5px 8px; border-radius: 7px; cursor: pointer; font-size: 14px; } | |
| .row:hover, .row.sel { background: var(--accent-bg); } | |
| .row .c { font-family: var(--mono); font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .row .p { text-align: right; font-variant-numeric: tabular-nums; color: var(--muted); font-size: 12.5px; } | |
| .badge { font-size: 11px; font-weight: 650; text-transform: uppercase; letter-spacing: .05em; padding: 2px 7px; border-radius: 6px; text-align: center; } | |
| .badge.ok { color: var(--ok); background: var(--ok-bg); } | |
| .badge.phantom { color: var(--bad); background: var(--bad-bg); } | |
| .badge.unknown { color: var(--warn); background: var(--warn-bg); } | |
| .insp h3 { font: 600 15px var(--mono); margin: 2px 0 8px; overflow-wrap: anywhere; } | |
| .ev { display: grid; grid-template-columns: minmax(0, 1fr) 58px; gap: 4px 10px; font-size: 13.5px; margin: 6px 0 10px; } | |
| .ev .n { color: var(--ink); } | |
| .ev .n small { color: var(--muted); display: block; font-size: 12px; } | |
| .ev .l { text-align: right; font: 600 13px var(--mono); color: var(--bad); } | |
| .chips { display: flex; flex-wrap: wrap; gap: 5px; margin: 4px 0 10px; } | |
| .chip { font: 12px var(--mono); padding: 2px 7px; border-radius: 6px; background: var(--accent-bg); color: var(--accent); } | |
| .sub { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; margin: 12px 0 4px; font-weight: 600; } | |
| svg text { fill: var(--muted); font: 11px -apple-system, system-ui, sans-serif; } | |
| .heat { display: grid; gap: 1px; font: 11px var(--mono); margin-top: 4px; } | |
| .heat .lab { white-space: nowrap; overflow: hidden; } | |
| .heat div { height: 17px; display: flex; align-items: center; justify-content: center; } | |
| .heat .lab { color: var(--muted); justify-content: flex-end; padding-right: 4px; } | |
| .heat .cell { background: var(--grid); } | |
| .heat .on { background: var(--cell); color: #fff; } | |
| .heat .in { color: var(--ink); font-weight: 600; } | |
| .filters { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px; } | |
| .filters button { font-family: var(--mono); font-size: 12px; padding: 3px 8px; } | |
| .filters button.on { background: var(--accent); color: #fff; border-color: var(--accent); } | |
| .speed { padding: 0 28px 28px; display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; } | |
| .split { display: flex; height: 22px; border-radius: 6px; overflow: hidden; margin-top: 10px; font: 600 12px var(--mono); } | |
| .split div { display: flex; align-items: center; justify-content: center; color: #fff; white-space: nowrap; overflow: hidden; } | |
| .split .ane { background: var(--accent); } | |
| .split .gpu { background: var(--ok); } | |
| .big { font-size: 40px; font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; } | |
| pre { font: 12.5px/1.5 var(--mono); margin: 6px 0 0; white-space: pre-wrap; color: var(--ink); } | |
| .muted { color: var(--muted); } | |
| .note { color: var(--muted); font-size: 13px; margin-top: 8px; } | |
| .empty { color: var(--muted); padding: 20px 4px; } | |
| .arch { font: 12.5px/1.7 var(--mono); color: var(--muted); } | |
| .arch b { color: var(--ink); font-weight: 600; } | |
| @media (max-width: 980px) { | |
| main, .speed { grid-template-columns: minmax(0, 1fr); padding-left: 16px; padding-right: 16px; } | |
| .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 10px 16px; } | |
| header { padding: 18px 16px 6px; } | |
| .editor { height: 380px; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <h1>CiteNet</h1> | |
| <div class="tag">A phantom legal-citation detector that was never trained. <b id="params">–</b> parameters, every nonzero weight written by hand, running on Core ML.</div> | |
| </header> | |
| <section class="stats"> | |
| <div class="stat"><div class="k">This check</div><div class="v" id="s-ms">–</div><div class="s" id="s-ms2">–</div></div> | |
| <div class="stat"><div class="k">One citation</div><div class="v" id="h-one">–</div><div class="s">p50, b1 on CPU, native Swift</div></div> | |
| <div class="stat"><div class="k">Bulk</div><div class="v" id="h-bulk">–</div><div class="s" id="h-bulk2">–</div></div> | |
| <div class="stat"><div class="k">LePhantomCite eval</div><div class="v">31 / 31</div><div class="s">phantoms caught · 1 / 983 real cites flagged</div></div> | |
| </section> | |
| <main> | |
| <section class="panel"> | |
| <h2>Brief</h2> | |
| <div class="toolbar"> | |
| <button data-sample="brief">Brief with planted phantoms</button> | |
| <button data-sample="lepc">Random LePhantomCite excerpt</button> | |
| <button data-sample="mata">Mata v. Avianca fakes</button> | |
| <span class="muted" id="src" style="font-size:12px"></span> | |
| </div> | |
| <div class="editor"> | |
| <div class="backdrop" id="backdrop"></div> | |
| <textarea id="ta" spellcheck="false"></textarea> | |
| </div> | |
| <div class="legend"> | |
| <span><span class="dot" style="background:var(--bad)"></span>phantom: the citation is impossible</span> | |
| <span><span class="dot" style="background:var(--warn)"></span>unrecognized reporter</span> | |
| <span><span class="dot" style="background:var(--ok)"></span>structurally possible (not proof the case exists)</span> | |
| </div> | |
| </section> | |
| <section class="panel insp"> | |
| <h2>Citations <span id="count" class="muted"></span></h2> | |
| <div class="list" id="list"></div> | |
| <div id="detail"><div class="empty">Click a citation to see which hand-written neurons fired.</div></div> | |
| </section> | |
| </main> | |
| <section class="speed"> | |
| <div class="panel"> | |
| <h2>Speed</h2> | |
| <div class="toolbar"> | |
| <span class="muted" style="font-size:13px">Check 1,000,000 citations on</span> | |
| <button data-lanes="ane">Neural Engine</button> | |
| <button data-lanes="gpu">GPU</button> | |
| <button class="primary" data-lanes="ane+gpu">Neural Engine + GPU</button> | |
| <button id="bench">Score the LePhantomCite eval split</button> | |
| </div> | |
| <div class="big" id="fire-n">–</div> | |
| <div class="muted" id="fire-s">Native Swift Core ML (bench/firehose): ANE b512 and GPU b8192, two threads per unit.</div> | |
| <div class="split" id="split"></div> | |
| <div id="bench-out" class="note"></div> | |
| <div class="sub">Native Swift benchmark, M5 Pro (bench/bench.swift)</div> | |
| <pre id="swift"></pre> | |
| </div> | |
| <div class="panel"> | |
| <h2>How the weights were written</h2> | |
| <div class="arch" id="arch"></div> | |
| <p class="note">Nothing was trained. <code>citenet/spec.py</code> lists reporters, series, courts, West regions and approximate volume-to-year timelines; <code>citenet/net.py</code> compiles each entry into specific filters and ReLU neurons. Design used only the LePhantomCite <code>aux_train</code> split. The <code>eval</code> split was scored once with the frozen v1.0 weights: 31/31 phantoms, 3/983 false flags. Two of those were tokenizer bugs, fixed in v1.1 (shown here). The remaining flag, <code>652 A.2d 634 (D.C. Cir. 1995)</code>, pairs a state reporter with a federal circuit.</p> | |
| <p class="note">Limits: a string-only model checks that a citation <i>could</i> exist. LePhantomCite's non-existent citations are structurally impossible (F.5th, S.W.4th), so it catches all of them. Real LLM fakes such as the Mata v. Avianca cases copy valid formats, so they pass. Catching those needs a case-law lookup.</p> | |
| </div> | |
| </section> | |
| <script> | |
| const $ = (id) => document.getElementById(id); | |
| const ta = $("ta"), bd = $("backdrop"); | |
| let items = [], selected = -1, inflight = false, dirty = false, info = null; | |
| const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">"); | |
| const EVTEXT = {}; | |
| async function getJSON(u) { const r = await fetch(u); return r.json(); } | |
| function paint() { | |
| const t = ta.value; let out = "", pos = 0; | |
| items.forEach((it, i) => { | |
| out += esc(t.slice(pos, it.start)); | |
| out += `<mark class="${it.status}${i === selected ? " sel" : ""}">${esc(t.slice(it.start, it.end))}</mark>`; | |
| pos = it.end; | |
| }); | |
| out += esc(t.slice(pos)) + " \n"; | |
| bd.innerHTML = out; | |
| bd.scrollTop = ta.scrollTop; | |
| } | |
| function renderList() { | |
| $("count").textContent = items.length ? `· ${items.length} found · ${items.filter(i => i.status === "phantom").length} phantom` : ""; | |
| $("list").innerHTML = items.map((it, i) => | |
| `<div class="row${i === selected ? " sel" : ""}" data-i="${i}"> | |
| <span class="badge ${it.status}">${it.status === "ok" ? "possible" : it.status}</span> | |
| <span class="c">${esc(it.cite)}</span><span class="p">${it.p.toFixed(3)}</span></div>`).join(""); | |
| $("list").querySelectorAll(".row").forEach(r => r.onclick = () => select(+r.dataset.i)); | |
| } | |
| async function check() { | |
| if (inflight) { dirty = true; return; } | |
| inflight = true; dirty = false; | |
| const t0 = performance.now(); | |
| const r = await fetch("/check", { method: "POST", body: JSON.stringify({ text: ta.value }) }).then(r => r.json()); | |
| const rtt = performance.now() - t0; | |
| const prevCite = items[selected]?.cite; | |
| items = r.items; | |
| selected = prevCite ? items.findIndex(i => i.cite === prevCite) : selected; | |
| if (selected >= items.length) selected = -1; | |
| $("s-ms").textContent = r.n ? `${r.model_ms < 1 ? r.model_ms.toFixed(2) : r.model_ms.toFixed(1)} ms` : "–"; | |
| $("s-ms2").textContent = r.n ? `${r.n} citations on ${r.model} · ${rtt.toFixed(1)} ms round trip` : "no citations"; | |
| paint(); renderList(); | |
| if (selected >= 0) renderDetail(items[selected]); else if (!items.length) $("detail").innerHTML = `<div class="empty">No reporter citations found.</div>`; | |
| inflight = false; | |
| if (dirty) check(); | |
| } | |
| function select(i) { | |
| selected = i; paint(); renderList(); renderDetail(items[i]); | |
| } | |
| const NICE = (n) => n | |
| .replace(/^class:/, "class ").replace(/^region:/, "region ").replace(/^home:/, "home state ") | |
| .replace(/^state:/, "court state ").replace(/^court:/, "court ").replace(/^phantom:/, "phantom series "); | |
| async function renderDetail(it) { | |
| if (!it) return; | |
| const logit = it.logit_bias + it.reasons.reduce((a, r) => a + r.logit, 0); | |
| let h = `<div style="display:flex;gap:10px;align-items:center"><span class="badge ${it.status}">${it.status === "ok" ? "possible" : it.status}</span> | |
| <span class="muted" style="font-size:13px">p(phantom) = ${it.p.toFixed(3)} · logit ${logit.toFixed(2)}</span></div> | |
| <h3>${esc(it.norm)}</h3>`; | |
| h += `<div class="sub">Evidence → logit (bias ${it.logit_bias})</div>`; | |
| h += it.reasons.length ? `<div class="ev">${it.reasons.map(r => | |
| `<div class="n">${r.name.replace(/_/g, " ")}${r.name === "volume_year" ? ` (${r.value.toFixed(1)} yr past tolerance)` : ""}<small>${esc(r.text)}</small></div><div class="l">+${r.logit.toFixed(2)}</div>`).join("")}</div>` | |
| : `<div class="note" style="margin:4px 0 10px">No rule fired. Volume, reporter, court and year are mutually consistent.</div>`; | |
| const parts = []; | |
| if (it.volume) parts.push(`volume = ${it.volume}`); | |
| if (it.year) parts.push(`year = ${it.year}`); | |
| if (it.knots) parts.push(`${it.knots} volume knots active`); | |
| h += `<div class="sub">Neurons that fired</div><div class="chips">${[...parts, ...it.fired.map(NICE)].map(c => `<span class="chip">${esc(c)}</span>`).join("")}</div>`; | |
| h += `<div id="chart"></div><div class="sub">First-layer filters that matched</div><div class="filters" id="filters"></div><div id="heat"></div>`; | |
| $("detail").innerHTML = h; | |
| if (it.curve) drawCurve(it); | |
| const fired = await getJSON("/fired?cite=" + encodeURIComponent(it.cite)); | |
| $("filters").innerHTML = fired.map((f, i) => `<button data-i="${i}">${esc(f.name)}</button>`).join("") || `<span class="muted">none</span>`; | |
| const btns = $("filters").querySelectorAll("button"); | |
| btns.forEach(b => b.onclick = () => { btns.forEach(x => x.classList.remove("on")); b.classList.add("on"); drawFilter(fired[+b.dataset.i], it); }); | |
| const first = fired.findIndex(f => f.name.startsWith("rep:") || f.name.startsWith("series:")); | |
| if (btns.length) btns[Math.max(0, first)].click(); | |
| } | |
| async function drawCurve(it) { | |
| const c = await getJSON("/curve?key=" + it.curve); | |
| const W = 460, H = 170, L = 40, R = 10, T = 10, B = 24; | |
| const xs = c.net.map(p => p[0]), ys = c.net.map(p => p[1]); | |
| const y0 = Math.min(...ys, it.year || 1e9) - c.tol - 3, y1 = Math.max(...ys, it.year || 0) + c.tol + 3; | |
| const x1 = Math.max(c.vmax, it.volume || 0) * 1.04; | |
| const X = v => L + (W - L - R) * v / x1, Y = y => T + (H - T - B) * (1 - (y - y0) / (y1 - y0)); | |
| const up = c.net.map(p => `${X(p[0])},${Y(p[1] + c.tol)}`), dn = c.net.slice().reverse().map(p => `${X(p[0])},${Y(p[1] - c.tol)}`); | |
| const line = c.net.map(p => `${X(p[0])},${Y(p[1])}`).join(" "); | |
| const ticks = []; | |
| const step = (y1 - y0) > 80 ? 40 : (y1 - y0) > 30 ? 10 : 5; | |
| for (let y = Math.ceil(y0 / step) * step; y <= y1; y += step) ticks.push(`<line x1="${L}" x2="${W - R}" y1="${Y(y)}" y2="${Y(y)}" stroke="var(--grid)"/><text x="${L - 5}" y="${Y(y) + 4}" text-anchor="end">${y}</text>`); | |
| let pt = ""; | |
| if (it.year && it.volume) { | |
| const out = it.reasons.some(r => r.name === "volume_year" || r.name === "volume_missing"); | |
| pt = `<circle cx="${X(it.volume)}" cy="${Y(it.year)}" r="6" fill="${out ? "var(--bad)" : "var(--ok)"}" stroke="var(--panel)" stroke-width="2"/>`; | |
| } | |
| $("chart").innerHTML = `<div class="sub">Volume → year: what the knot neurons compute for ${esc(c.reporters.join(" / "))} (±${c.tol} yr)</div> | |
| <svg viewBox="0 0 ${W} ${H}" width="100%" role="img" aria-label="volume to year curve"> | |
| ${ticks.join("")} | |
| <polygon points="${up.concat(dn).join(" ")}" fill="var(--accent-bg)"/> | |
| <polyline points="${line}" fill="none" stroke="var(--accent)" stroke-width="2"/> | |
| <line x1="${X(c.vmax)}" x2="${X(c.vmax)}" y1="${T}" y2="${H - B}" stroke="var(--muted)" stroke-dasharray="3 3"/> | |
| <text x="${X(c.vmax) - 4}" y="${T + 10}" text-anchor="end">last volume ${c.vmax}</text> | |
| <text x="${L}" y="${H - 6}">vol 0</text><text x="${W - R}" y="${H - 6}" text-anchor="end">vol ${Math.round(x1)}</text> | |
| ${pt} | |
| </svg>`; | |
| } | |
| async function drawFilter(f, it) { | |
| const w = await getJSON("/filter?name=" + encodeURIComponent(f.name)); | |
| const norm = "‹" + it.norm + "›"; // BOS / EOS markers, as the network sees them | |
| const win = []; | |
| for (let o = 0; o < w.k; o++) { | |
| const ch = norm[f.pos + 1 + o]; | |
| win.push(ch === undefined ? "" : ch === " " ? "␣" : ch); | |
| } | |
| let g = `<div class="heat" style="grid-template-columns: 64px repeat(${w.k}, minmax(0, 1fr))">`; | |
| g += `<div class="lab">input</div>` + win.map(c => `<div class="in">${esc(c)}</div>`).join(""); | |
| for (const r of w.rows) { | |
| g += `<div class="lab">${esc(r.ch)}</div>` + r.w.map(v => `<div class="cell${v ? " on" : ""}"></div>`).join(""); | |
| } | |
| g += `</div><div class="note">${esc(w.name)} · ${w.layer} · ${w.nonzero} nonzero of ${w.params} weights · bias ${w.bias}. ` + | |
| `It outputs relu(matches + bias), which is 1 only when every column hits.</div>`; | |
| $("heat").innerHTML = g; | |
| } | |
| async function loadSample(kind, pick) { | |
| const r = await getJSON("/sample?kind=" + kind); | |
| ta.value = r.text; selected = -1; | |
| $("src").textContent = kind === "lepc" ? `LePhantomCite eval · ${r.file} · planted: ${Object.values(r.planted).join(", ") || "none"}` : ""; | |
| await check(); | |
| const want = pick ? items.findIndex(i => i.cite.includes(pick)) : -1; | |
| const firstBad = items.findIndex(i => i.status === "phantom"); | |
| if (want >= 0) select(want); else if (firstBad >= 0) select(firstBad); else if (items.length) select(0); | |
| } | |
| document.querySelectorAll("[data-sample]").forEach(b => b.onclick = () => loadSample(b.dataset.sample)); | |
| ta.addEventListener("input", () => check()); | |
| ta.addEventListener("scroll", () => { bd.scrollTop = ta.scrollTop; }); | |
| ta.addEventListener("click", () => { | |
| const p = ta.selectionStart, i = items.findIndex(it => p >= it.start && p <= it.end); | |
| if (i >= 0) select(i); | |
| }); | |
| document.querySelectorAll("[data-lanes]").forEach(b => b.onclick = async () => { | |
| const lanes = b.dataset.lanes; | |
| $("fire-n").textContent = "…"; $("split").innerHTML = ""; | |
| const r = await getJSON("/firehose?n=1000000&lanes=" + encodeURIComponent(lanes)); | |
| const dur = 700, t0 = performance.now(); | |
| const tick = (t) => { | |
| const f = Math.min(1, (t - t0) / dur); | |
| $("fire-n").textContent = Math.round(r.n * f).toLocaleString() + " citations"; | |
| if (f < 1) requestAnimationFrame(tick); | |
| else $("fire-n").textContent = `${r.n.toLocaleString()} in ${(r.seconds * 1000).toFixed(0)} ms`; | |
| }; | |
| requestAnimationFrame(tick); | |
| const name = { ane: "Neural Engine", gpu: "GPU", "ane+gpu": "Neural Engine + GPU" }[lanes]; | |
| $("fire-s").textContent = `${r.per_sec.toLocaleString()} citations/s on the ${name} · ${r.flagged.toLocaleString()} flagged · native Swift Core ML`; | |
| $("split").innerHTML = Object.entries(r.lanes).map(([k, v]) => | |
| `<div class="${k}" style="width:${100 * v.cites / r.n}%">${k.toUpperCase()} b${v.batch} · ${(v.cites / r.seconds / 1e3).toFixed(0)}k/s</div>`).join(""); | |
| }); | |
| $("bench").onclick = async () => { | |
| const r = await getJSON("/bench"); | |
| $("bench-out").innerHTML = `${r.n.toLocaleString()} eval citations in <b>${r.ms} ms</b> on ${r.model}: ` + | |
| `${r.recall[0]}/${r.recall[1]} phantoms caught, ${r.false_flags[0]}/${r.false_flags[1]} real citations flagged` + | |
| (r.false_flag_cites.length ? ` (${r.false_flag_cites.map(esc).join("; ")})` : "") + "."; | |
| }; | |
| (async () => { | |
| info = await getJSON("/info"); | |
| $("params").textContent = `${info.params.toLocaleString()}`; | |
| $("swift").textContent = info.swift.trim(); | |
| const hl = info.headline, k = (n) => n >= 1e6 ? (n / 1e6).toFixed(2) + "M" : Math.round(n / 1e3) + "k"; | |
| if (hl.b1_cpu) $("h-one").textContent = `${Math.round(hl.b1_cpu.p50_us)} µs`; | |
| const both = hl["concurrent:ane b512 + gpu b8192"]; | |
| if (both) { | |
| $("h-bulk").textContent = `${k(both)}/s`; | |
| $("h-bulk2").textContent = `citations/s, Neural Engine + GPU together (ANE alone ${k(hl.b512_ane.per_sec)}/s, GPU ${k(hl.b8192_gpu.per_sec)}/s)`; | |
| } else if (hl.b512_ane) { | |
| $("h-bulk").textContent = `${k(hl.b512_ane.per_sec)}/s`; $("h-bulk2").textContent = "citations/s, b512 on the Neural Engine"; | |
| } | |
| const L = info.layers; | |
| $("arch").innerHTML = [ | |
| `<b>char codes</b> [B, 1, 1, 64]`, | |
| `→ <b>one-hot</b> relu(1 − |code − k|), k = 0…47 (no weights)`, | |
| `→ <b>${L.rep} reporter filters</b> (conv 1×15) + <b>${L.court} court filters</b> (conv 1×8) + <b>6 digit decoders</b>, max over positions`, | |
| `→ <b>${L.concepts} concept neurons</b>: reporter classes, West regions, courts, a 29-knot volume thermometer`, | |
| `→ <b>${L.rules} rule neurons</b>: AND(class, bad court), |year − curve(volume)| − tol, volume > last`, | |
| `→ <b>${L.evidence} evidence</b> sums, saturated → <b>logit</b> → sigmoid`, | |
| `${info.params.toLocaleString()} parameters · ${info.nonzero.toLocaleString()} nonzero · 0 training steps`, | |
| ].join("<br>"); | |
| const q = new URLSearchParams(location.search); // ?sample=mata&pick=925 (deep links for screenshots) | |
| await loadSample(q.get("sample") || "brief", q.get("pick")); | |
| if (q.get("fire")) document.querySelector(`[data-lanes="${q.get("fire")}"]`)?.click(); | |
| })(); | |
| </script> | |
| </body> | |
| </html> | |