File size: 17,595 Bytes
1e3f4b2 0d28c16 1e3f4b2 0d28c16 1e3f4b2 0d28c16 1e3f4b2 0d28c16 1e3f4b2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 | // MWP script-model leaderboard. Static page: reads the eval repo's JSON at load.
// Contract: My-Weird-Prompts monorepo PLAN-040 "Data contracts".
// ?base=<url> overrides the data location (e.g. ?base=../../results/ for a local check).
"use strict";
const params = new URLSearchParams(location.search);
const BASE = params.get("base") || "https://raw.githubusercontent.com/My-Weird-Prompts/eval/main/results/";
const SITE = "https://myweirdprompts.com";
const COLS = [
// [field, label, numeric, title]
["model", "model", false, "OpenRouter model id (aired baselines: the show's own writer label)"],
["technical_fail", "tech fail", false, "Any refusal by the model or a provider filter"],
["v1_score", "V1 score", true, "25 x (priority - 1), gated on parse and length 0.8-1.2x"],
["on_length", "on length", true, "Scripts that passed the length gate"],
["priority", "priority", true, "Mean of the priority rubric axes (1-5)"],
["mid_hold", "mid hold", true, "Long-form coherence: holds the middle (1-5)"],
["fun", "fun", true, "1-5"],
["candour", "candour", true, "1-5"],
["liveness", "liveness", true, "1-5"],
["len_ratio", "len ratio", true, "Words / 3,800 target"],
["cost_vs_baseline", "cost vs DeepSeek", true, "Episode cost with this writer / DeepSeek V4.1 Flash episode"],
["usd_per_script", "$/script", true, "Writer cost per script"],
["est_usd_per_episode", "est $/episode", true, "Whole production episode with this writer"],
["judge_overall", "judge overall", true, ""],
["n", "n", true, "Samples"],
];
// Run kinds whose rows don't fit COLS get their own column map. Each entry:
// [key, label, numeric, title, getter(row)]; `extra.x` keys read row.extra.x.
const ex = (k) => (r) => (r.extra || {})[k];
const iqr = (k) => (r) => { const q = (r.extra || {})[k + "_iqr"]; return q ? `IQR ${q[0]} β ${q[1]}` : ""; };
const KIND_COLS = {
"aired-catalogue": {
caveat: "Different prompts per model; repetition is length-dependent (r = 0.28); era flags, not a ranking.",
sort: { key: "extra.first", dir: 1 },
foot: "Medians over each writer's sampled aired scripts; hover a cell for its IQR. Sorted by era. Lower is better for every repetition, recycling, echo and tic column. Offline rows were written in Claude Code, not by the pipeline. Per-episode rows: results/aired-catalogue.json.",
cols: [
["model", "model", false, "llm_model_canonical (the show's writer label)"],
["extra.written", "written", false, "pipeline, or offline (Claude Code) where the model never wrote a pipeline episode"],
["extra.first", "era", false, "First and last aired date of the model's eligible episodes", (r) => r.extra.first === r.extra.last ? r.extra.first : `${r.extra.first} β ${r.extra.last}`],
["n", "n", true, "Episodes sampled (up to 20, stratified across the era)"],
["extra.word_count", "words", true, "Spoken words (median)"],
["len_ratio", "len ratio", true, "Words / target: the planner's midpoint where a target length was recorded, else 3,800"],
["on_length", "on length", true, "Scripts within 0.8-1.2x of target"],
["extra.rep_4", "rep_4", true, "Share of repeated 4-grams (length-dependent)"],
["extra.repeated_span_ratio", "repeated span", true, "Share of tokens inside a repeated 25-token run"],
["extra.rep_4_last_third", "rep_4 last β
", true, "rep_4 over the last third"],
["extra.recycle_middle", "recycle middle", true, "Middle third's 6-grams already said in the first third"],
["extra.recycle_last", "recycle last", true, "Last third's 6-grams already said in the first two"],
["extra.rep_4_middle_third", "rep_4 middle β
", true, "rep_4 over the middle third"],
["extra.echo_last_decile", "echo last 10%", true, "Last-decile turns: share of 5-grams said earlier"],
["extra.adjacent_turn_similarity_mean", "adj. turn sim", true, "Mean TF-IDF cosine between consecutive turns (length-independent)"],
["extra.tic_per_1k_named", "tics/1k", true, "Catalogued stock phrases per 1k words"],
["extra.gate_pass_rate", "gate pass", true, "TTS-format gate (parseability only, not length)"],
],
},
};
const $ = (id) => document.getElementById(id);
const esc = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
const label = (k) => k.replace(/_/g, " ");
let LB = null;
let sortState = { key: null, dir: -1 };
async function getJSON(name) {
const r = await fetch(BASE + name, { cache: "no-cache" });
if (!r.ok) throw new Error(`${name}: HTTP ${r.status}`);
return r.json();
}
function fmt(v, key) {
if (v === null || v === undefined) return '<span class="muted">β</span>';
if (typeof v === "boolean") return v ? '<span class="fail-tag">FAIL</span>' : '<span class="pass-tag">pass</span>';
if (typeof v === "number") {
if (key === "cost_vs_baseline") return `${Math.round(v * 100)}%`;
if (key && key.startsWith("usd") || key === "est_usd_per_episode") return "$" + (v < 0.01 ? v.toPrecision(2) : v.toFixed(3));
const scoreKey = COLS.some(([k, , num]) => num && k === key) && !["v1_score", "n"].includes(key);
if (Number.isInteger(v) && !scoreKey) return String(v);
return Math.abs(v) < 0.1 ? v.toFixed(4) : v.toFixed(2);
}
return esc(v);
}
function sortValue(row, key) {
const v = key.startsWith("extra.") ? (row.extra || {})[key.slice(6)] : row[key];
if (v === null || v === undefined) return null;
if (typeof v === "string") {
if (/^\d{4}-\d{2}-\d{2}/.test(v)) return v;
const m = v.match(/^(\d+)\/(\d+)$/);
if (m) return +m[1] / +m[2];
const n = parseFloat(v);
return Number.isNaN(n) ? v.toLowerCase() : n;
}
if (typeof v === "boolean") return v ? 1 : 0;
return v;
}
function defaultSortKey(run) {
for (const k of ["v1_score", "priority", "usd_per_script", "n"]) if (run.rows.some((r) => r[k] != null)) return k;
return "model";
}
function renderCurrent() {
const c = LB.current || {};
// Latest scored row for the current writer.
let row = null, rowRun = null;
for (const run of LB.runs) {
const r = run.rows.find((x) => x.model === c.writer && x.v1_score != null);
if (r) { row = r; rowRun = run; break; }
}
const stats = row ? `<div class="kv">
<span>latest scored run: <b>${esc(rowRun.run_id)}</b></span>
<span>V1 score <b>${fmt(row.v1_score)}</b></span>
<span>on length <b>${fmt(row.on_length)}</b></span>
<span>mid hold <b>${fmt(row.mid_hold, "mid_hold")}</b></span>
<span>fun <b>${fmt(row.fun, "fun")}</b></span>
<span>cost vs DeepSeek <b>${fmt(row.cost_vs_baseline, "cost_vs_baseline")}</b></span>
</div>` : "";
$("current").innerHTML = `<div class="current">
<span class="writer">${esc(c.writer)}</span>
<span class="meta">writing every pipeline episode since <b>${esc(c.since)}</b>${c.decision ? ` (decision ${esc(c.decision)})` : ""}</span>
${c.note ? `<span class="meta small">${esc(c.note)}</span>` : ""}
${stats}
</div>`;
}
function renderPicker() {
const sel = $("run-picker");
sel.innerHTML = LB.runs.map((r, i) =>
`<option value="${i}">${esc(r.date || "")} Β· ${esc(r.run_id)} (${esc(r.kind)}, ${r.rows.length} models)</option>`).join("");
// Default: the latest run with V1 scores (a ranked leaderboard); every run stays in the picker.
let idx = LB.runs.findIndex((r) => r.rows.some((x) => x.v1_score != null));
if (params.get("run")) {
const j = LB.runs.findIndex((r) => r.run_id === params.get("run"));
if (j >= 0) idx = j;
}
sel.value = String(Math.max(idx, 0));
sel.addEventListener("change", () => { sortState = { key: null, dir: -1 }; renderRun(); });
}
function renderRun() {
const run = LB.runs[+$("run-picker").value];
const bits = [
run.kind && `<span class="chip">${esc(run.kind)}</span>`,
run.benchmark_version && `<span class="chip">benchmark ${esc(run.benchmark_version)}</span>`,
`<span class="chip">judge: ${esc(run.judge || "none")}</span>`,
run.spend_usd != null && `<span class="chip">spend ~$${esc(run.spend_usd)}</span>`,
].filter(Boolean).join("");
const extraLinks = [
run.pdf && `<a href="https://github.com/My-Weird-Prompts/eval/blob/main/${esc(run.pdf)}">reading copy (PDF)</a>`,
run.hf_dataset && `<a href="https://huggingface.co/datasets/${esc(run.hf_dataset)}">samples on HF</a>`,
`<a href="https://github.com/My-Weird-Prompts/eval/blob/main/${esc(run.source || "results/README.md")}">write-up</a>`,
].filter(Boolean).join(" Β· ");
const spec = KIND_COLS[run.kind];
const caveat = spec && (run.caveat || spec.caveat);
$("run-head").innerHTML = `<p>${bits}</p><p>${esc(run.summary)}</p>` +
(caveat ? `<p class="caveat"><b>Caveat.</b> ${esc(caveat)}</p>` : "") + `<p class="small">${extraLinks}</p>`;
if (spec) return renderKind(run, spec);
const cols = COLS.filter(([k]) => k === "model" || run.rows.some((r) => r[k] !== null && r[k] !== undefined));
const extraKeys = [...new Set(run.rows.flatMap((r) => Object.keys(r.extra || {})))];
const hasNotes = run.rows.some((r) => r.notes);
if (!sortState.key) sortState = { key: defaultSortKey(run), dir: defaultSortKey(run) === "model" ? 1 : -1 };
const ranked = cols.some(([k]) => k === "v1_score");
const rows = [...run.rows].sort((a, b) => {
// Technical fails always sink to the bottom and are never ranked.
if (ranked && !!a.technical_fail !== !!b.technical_fail) return a.technical_fail ? 1 : -1;
const va = sortValue(a, sortState.key), vb = sortValue(b, sortState.key);
if (va === vb) return 0;
if (va === null) return 1;
if (vb === null) return -1;
return (va < vb ? -1 : 1) * sortState.dir;
});
const th = (key, text, num, title) => {
const aria = sortState.key === key ? ` aria-sort="${sortState.dir > 0 ? "ascending" : "descending"}"` : "";
return `<th class="${num ? "num" : ""}"${aria} title="${esc(title || "")}"><button data-key="${esc(key)}">${esc(text)}</button></th>`;
};
let html = "<thead><tr>" + (ranked ? '<th class="num">#</th>' : "") +
cols.map(([k, l, num, t]) => th(k, l, num, t)).join("") +
extraKeys.map((k) => th("extra." + k, label(k), false, "run-specific column")).join("") +
(hasNotes ? "<th>notes</th>" : "") + "</tr></thead><tbody>";
let rank = 0;
for (const r of rows) {
const cur = r.model === LB.current?.writer;
html += `<tr class="${r.technical_fail ? "fail" : ""}">`;
if (ranked) html += `<td class="num">${r.technical_fail ? "β" : ++rank}</td>`;
for (const [k, , num] of cols) {
if (k === "model") html += `<td class="model${cur ? " is-current" : ""}" title="${esc(r.exclusion || "")}">${esc(r.model)}${cur ? " β
" : ""}</td>`;
else html += `<td class="${num ? "num" : ""}">${fmt(r[k], k)}</td>`;
}
for (const k of extraKeys) {
const v = (r.extra || {})[k];
html += `<td class="${typeof v === "number" ? "num" : ""}">${fmt(v, k)}</td>`;
}
if (hasNotes) html += `<td class="notes">${esc(r.notes || "")}</td>`;
html += "</tr>";
}
$("board").innerHTML = html + "</tbody>";
$("board").querySelectorAll("th button").forEach((b) => b.addEventListener("click", () => {
const key = b.dataset.key;
sortState = sortState.key === key ? { key, dir: -sortState.dir } : { key, dir: key === "model" ? 1 : -1 };
renderRun();
}));
$("board-foot").innerHTML = ranked
? "Click a column to sort. Technical fails sink to the bottom unranked. β
= current writer. Three scripts per model is triage, not a ranking; scores compare only within one benchmark version."
: "Click a column to sort. This run has no V1 score, so there is no rank. β
= current writer.";
}
function renderKind(run, spec) {
if (!sortState.key) sortState = { ...spec.sort };
const get = (r, c) => (c[4] ? c[4](r) : c[0].startsWith("extra.") ? (r.extra || {})[c[0].slice(6)] : r[c[0]]);
const rows = [...run.rows].sort((a, b) => {
const va = sortValue(a, sortState.key), vb = sortValue(b, sortState.key);
if (va === vb) return 0;
if (va === null) return 1;
if (vb === null) return -1;
return (va < vb ? -1 : 1) * sortState.dir;
});
const th = ([key, text, num, title]) => {
const aria = sortState.key === key ? ` aria-sort="${sortState.dir > 0 ? "ascending" : "descending"}"` : "";
return `<th class="${num ? "num" : ""}"${aria} title="${esc(title || "")}"><button data-key="${esc(key)}">${esc(text)}</button></th>`;
};
let html = "<thead><tr>" + spec.cols.map(th).join("") + "<th>notes</th></tr></thead><tbody>";
for (const r of rows) {
const offline = (r.extra || {}).written === "offline";
html += `<tr class="${offline ? "offline" : ""}">`;
for (const c of spec.cols) {
const [k, , num] = c;
const v = get(r, c);
if (k === "model") html += `<td class="model">${esc(r.model)}</td>`;
else if (k === "extra.written") html += `<td><span class="chip${offline ? " chip-warn" : ""}">${esc(v)}</span></td>`;
else if (k === "extra.gate_pass_rate" || k === "on_length" && typeof v === "number") html += `<td class="num">${v == null ? fmt(v) : Math.round(v * 100) + "%"}</td>`;
else if (k === "extra.word_count") html += `<td class="num" title="${esc(iqr("word_count")(r))}">${v == null ? fmt(v) : Math.round(v).toLocaleString("en")}</td>`;
else if (k.startsWith("extra.") && num) html += `<td class="num" title="${esc(iqr(k.slice(6))(r))}">${fmt(v, k)}</td>`;
else html += `<td class="${num ? "num" : "nowrap"}">${num ? fmt(v, k) : esc(v)}</td>`;
}
html += `<td class="notes">${esc(r.notes || "")}</td></tr>`;
}
$("board").innerHTML = html + "</tbody>";
$("board").querySelectorAll("th button").forEach((b) => b.addEventListener("click", () => {
const key = b.dataset.key;
sortState = sortState.key === key ? { key, dir: -sortState.dir } : { key, dir: ["model", "extra.first", "extra.written"].includes(key) ? 1 : -1 };
renderRun();
}));
$("board-foot").textContent = spec.foot;
}
function renderFails() {
const rows = [];
for (const run of LB.runs) for (const r of run.rows) if (r.technical_fail) rows.push([run, r]);
$("fails").innerHTML = "<thead><tr><th>model</th><th>run</th><th>why</th></tr></thead><tbody>" +
(rows.length ? rows.map(([run, r]) => `<tr class="fail"><td class="model">${esc(r.model)}</td><td>${esc(run.run_id)}</td>
<td class="notes">${esc(r.notes || r.exclusion || (run.kind === "censorship" ? "censorship (refined reading)" : "technical fail"))}</td></tr>`).join("")
: '<tr><td colspan="3" class="muted">None.</td></tr>') + "</tbody>";
const render = () => {
const q = $("excl-filter").value.trim().toLowerCase();
const items = Object.entries(LB.exclusions || {}).filter(([k, v]) => !q || k.toLowerCase().includes(q) || v.toLowerCase().includes(q));
$("exclusions").innerHTML = "<thead><tr><th>model or family</th><th>reason</th></tr></thead><tbody>" +
items.map(([k, v]) => `<tr><td class="model">${esc(k)}</td><td class="notes">${esc(v)}</td></tr>`).join("") + "</tbody>";
};
$("excl-filter").addEventListener("input", render);
render();
}
function renderInformal(data) {
const entries = (data && data.entries) || [];
if (!entries.length) { $("informal").innerHTML = '<p class="muted">No entries yet.</p>'; return; }
$("informal").innerHTML = entries.map((e) => {
const eps = (e.episodes || []).map((ep) =>
`<li><span class="model">${esc(ep.model)}</span>: <a href="${SITE}/episode/${encodeURIComponent(ep.slug)}/">#${esc(ep.episode_number)} ${esc(ep.slug)}</a>
<span class="chip">${esc(ep.written)}</span>${ep.note ? ` <span class="muted small">${esc(ep.note)}</span>` : ""}</li>`).join("");
const costs = Object.entries(e.cost_per_script || {}).map(([m, c]) => `<span class="chip">${esc(m)} ~$${Number(c).toFixed(2)}/script</span>`).join(" ");
const imps = Object.entries(e.impressions || {}).map(([m, t]) => `<li><b>${esc(m)}</b>: ${esc(t)}</li>`).join("");
return `<article class="card entry">
<h3>${esc(e.date)}${e.title ? ": " + esc(e.title) : ""}</h3>
<p class="small muted">Judge: ${esc(e.judge)}. Models: ${(e.models || []).map(esc).join(", ")}</p>
<details><summary>Episodes read (${(e.episodes || []).length})</summary><ul>${eps}</ul>
${e.caveats ? `<p class="small muted">${esc(e.caveats)}</p>` : ""}</details>
${costs ? `<p class="small">${costs}${e.cost_basis ? ` <span class="muted">(${esc(e.cost_basis.source || "")}, ${esc(e.cost_basis.mix || "")})</span>` : ""}</p>` : ""}
<ul>${imps}${e.impressions_all_models ? `<li><b>all models</b>: ${esc(e.impressions_all_models)}</li>` : ""}</ul>
${e.daniel ? `<blockquote>β${esc(e.daniel)}β <span class="muted small">(Daniel)</span></blockquote>` : ""}
${e.verdict ? `<div class="verdict"><b>Verdict.</b> ${esc(e.verdict)}</div>` : ""}
</article>`;
}).join("");
}
async function main() {
try {
LB = await getJSON("leaderboard.json");
$("generated").textContent = `Leaderboard generated ${LB.generated}; benchmark ${LB.benchmark_version}.`;
renderCurrent();
renderPicker();
renderRun();
renderFails();
} catch (err) {
$("current").innerHTML = `<p class="error">Couldn't load leaderboard.json (${esc(err.message)}).</p>`;
}
try {
renderInformal(await getJSON("informal-evaluations.json"));
} catch (err) {
$("informal").innerHTML = `<p class="error">Couldn't load informal-evaluations.json (${esc(err.message)}).</p>`;
}
}
main();
|