"use strict"; const RESULTS_REPO = "c3aiia3c/read-bench-results"; // Column definitions. Row type is shown via the leading symbol (hover = label); // no separate text "Type" column. Metrics include the three pollution levels // plus full-corpus scale. const COLUMNS = [ { key: "rank", label: "#", kind: "rank", always: true }, { key: "sym", label: "", kind: "sym", always: true }, { key: "name", label: "Method", kind: "name", always: true }, { key: "supervision", label: "Supervision", kind: "tag", on: true }, { key: "reranker", label: "Reranker", kind: "tag", on: true }, { key: "rho0", label: "NDCG@10 ฯ=0%", kind: "metric",on: true }, { key: "rho10", label: "ฯ=10%", kind: "metric",on: true }, { key: "rho20", label: "ฯ=20%", kind: "metric",on: true }, { key: "code", label: "Code", kind: "code", on: true }, ]; const FACETS = { type: [["embedder","๐ข Foundation embedder"],["distance","๐ถ Shape distance"],["symbolic","๐ท Symbolic (BM25)"], ["fusion","๐ฃ Hybrid (fusion)"],["supervised","๐ด Supervised ceiling"],["floor","โช Trivial baseline"]], supervision: [["label-free","label-free"],["neighbour-labels","neighbour-labels"],["supervised","supervised"]], reranker: [["โ","none"],["GPC","GPC"],["PRF","PRF"],["Purity","Purity"],["MajVote","MajVote"],["QPurity","QPurity"],["LM","LM"]], }; // Where submitted method code lives (per-method folder on the results repo). const CODE_BASE = "https://huggingface.co/datasets/c3aiia3c/read-bench-results"; const state = { view: "overall", rho: "rho0", sortKey: "rho0", sortDir: -1, search: "", active: { type: new Set(), supervision: new Set(), reranker: new Set() }, visible: new Set(COLUMNS.filter(c => c.always || c.on).map(c => c.key)), rows: [], }; // ---- toolbar builders ---- function buildFacets() { for (const [facet, opts] of Object.entries(FACETS)) { const host = document.getElementById("f-" + facet); host.innerHTML = ""; for (const [val, label] of opts) { const id = `cb-${facet}-${val}`; const wrap = document.createElement("label"); wrap.className = "cb"; wrap.innerHTML = ` ${label}`; wrap.querySelector("input").onchange = e => { const s = state.active[facet]; e.target.checked ? s.add(val) : s.delete(val); render(); }; host.appendChild(wrap); } } } function buildColumnPicker() { const host = document.getElementById("colbox"); host.innerHTML = ""; for (const c of COLUMNS) { if (c.always) continue; const wrap = document.createElement("label"); wrap.className = "cb"; wrap.innerHTML = ` ${c.label}`; wrap.querySelector("input").onchange = e => { e.target.checked ? state.visible.add(c.key) : state.visible.delete(c.key); render(); }; host.appendChild(wrap); } } // ---- submissions ---- async function loadSubmissions() { const api = `https://huggingface.co/api/datasets/${RESULTS_REPO}/tree/main/submissions?recursive=1`; let tree; try { tree = await (await fetch(api)).json(); } catch (e) { return []; } if (!Array.isArray(tree)) return []; const slugs = new Set(); for (const f of tree) { const m = f.path && f.path.match(/^submissions\/([^/]+)\/results\.json$/); if (m) slugs.add(m[1]); } const out = []; for (const slug of slugs) { const base = `https://huggingface.co/datasets/${RESULTS_REPO}/resolve/main/submissions/${slug}`; try { const res = await (await fetch(`${base}/results.json`)).json(); let meta = {}; try { meta = parseYaml(await (await fetch(`${base}/metadata.yaml`)).text()); } catch (e) {} const h = res.headline || {}; const famToType = { "Foundation embedder":"embedder", "Shape distance":"distance", "Symbolic (BM25)":"symbolic", "Hybrid (fusion)":"fusion", "Supervised ceiling":"supervised", "Trivial baseline":"floor", "FM embedder":"embedder", "Raw-window distance":"distance", "Symbolic":"symbolic", "Fusion + reranker":"fusion", "Supervised":"supervised", "Trivial floor":"floor" }; out.push({ name: meta.name || slug, type: famToType[meta.family] || "embedder", family: meta.family || "Other", supervision: meta.supervision || "label-free", reranker: meta.reranker || "โ", nr: /nr|normal-residual/i.test(meta.name||""), code: true, link: meta.code || meta.paper || "", slug: slug, rho0: h.rho0, rho10: h.rho10, rho20: h.rho20, full: (res.headline||{}).full ?? null, source: "submission", }); } catch (e) {} } return out; } function parseYaml(txt) { const o = {}; for (const line of txt.split("\n")) { const m = line.match(/^([a-zA-Z_]+):\s*(.*)$/); if (!m) continue; let v = m[2].trim(); if (!/^["']/.test(v)) v = v.replace(/\s+#.*$/, "").trim(); v = v.replace(/^["']|["']$/g, ""); if (v) o[m[1]] = v; } return o; } // ---- render ---- function passes(r) { if (state.active.type.size && !state.active.type.has(r.type)) return false; if (state.active.supervision.size && !state.active.supervision.has(r.supervision)) return false; if (state.active.reranker.size && !state.active.reranker.has(r.reranker)) return false; if (state.search && !r.name.toLowerCase().includes(state.search)) return false; return true; } function render() { if (state.view === "domain") { renderDomain(); return; } const cols = COLUMNS.filter(c => c.always || state.visible.has(c.key)); let rows = state.rows.filter(r => typeof r[state.rho] === "number").filter(passes); rows.sort((a, b) => { const x = a[state.sortKey], y = b[state.sortKey]; if (typeof x === "number" || typeof y === "number") return ((x ?? -1) - (y ?? -1)) * state.sortDir; return String(x).localeCompare(String(y)) * state.sortDir; }); const best = rows.length ? Math.max(...rows.map(r => r[state.rho] ?? 0)) : -1; const head = document.getElementById("head"); head.innerHTML = "
NDCG@10 (ฯ=0%) macro-averaged within each diagnostic domain. Filters and search above apply here too.
`; overallWrap.after(dv); } dv.style.display = "block"; renderDomain(); } else { overallWrap.style.display = ""; show(document.getElementById("count"), true); show(document.getElementById("legend"), true); render(); } } document.getElementById("rho").onchange = e => { state.rho = e.target.value; state.sortKey = e.target.value; state.sortDir = -1; state.visible.add(e.target.value); // make sure the active metric column shows buildColumnPicker(); render(); }; document.getElementById("search").oninput = e => { state.search = e.target.value.toLowerCase(); render(); }; document.querySelectorAll(".tab").forEach(t => t.onclick = () => setView(t.dataset.view)); (async () => { buildFacets(); buildColumnPicker(); const subs = await loadSubmissions(); state.rows = window.PAPER_ROWS.concat(subs); render(); })();