dashboard / app.js
3v324v23's picture
wandb read
8a93f94
Raw
History Blame Contribute Delete
7.68 kB
const ACCENT = "#5eead4";
const BASE = "#6b7280";
const css = (v) => getComputedStyle(document.documentElement).getPropertyValue(v).trim();
let DATA = null;
let scoreChart = null;
let lenChart = null;
const $ = (id) => document.getElementById(id);
function shortKey(k) {
if (!k || k.length <= 14) return { head: k || "—", tail: "" };
return { head: k.slice(0, 8), tail: "…" + k.slice(-6) };
}
async function load() {
try {
const res = await fetch("./data.json", { cache: "no-store" });
if (!res.ok) throw new Error("HTTP " + res.status);
DATA = await res.json();
} catch (err) {
console.error("Failed to load data.json", err);
$("board-empty").hidden = false;
$("board-empty").textContent = "Could not load data.json — has the refresh job run yet?";
return;
}
hydrateUpdated();
buildViews();
renderActiveView();
}
function hydrateUpdated() {
const ts = DATA.generated_at;
const label = ts ? new Date(ts).toLocaleString(undefined, { dateStyle: "medium", timeStyle: "short" }) : "unknown";
$("updated").textContent = "updated " + label;
$("footer-meta").textContent = DATA.sample ? "sample data" : "live data";
}
function buildViews() {
const select = $("validator-select");
select.innerHTML = "";
const views = [];
if (DATA.aggregate && Array.isArray(DATA.aggregate.rankings) && DATA.aggregate.rankings.length) {
views.push({ id: "__consensus__", label: "Consensus · all validators" });
}
for (const v of DATA.validators || []) {
const sk = shortKey(v.hotkey);
views.push({ id: v.hotkey, label: "Validator " + sk.head + sk.tail });
}
for (const view of views) {
const opt = document.createElement("option");
opt.value = view.id;
opt.textContent = view.label;
select.appendChild(opt);
}
select.onchange = renderActiveView;
$("stat-validators").textContent = (DATA.validators || []).length || "0";
const everyMiner = new Set();
for (const v of DATA.validators || []) for (const r of v.rankings || []) everyMiner.add(r.hotkey);
$("stat-miners").textContent = everyMiner.size || (DATA.aggregate?.rankings?.length ?? 0);
}
function activeView() {
const id = $("validator-select").value;
if (id === "__consensus__" || !id) {
return {
rankings: DATA.aggregate?.rankings || [],
history: DATA.aggregate?.history || null,
};
}
const v = (DATA.validators || []).find((x) => x.hotkey === id);
return { rankings: v?.rankings || [], history: v?.history || null };
}
function renderActiveView() {
const view = activeView();
renderBoard(view.rankings);
renderStats(view);
renderTrends(view);
}
function renderStats(view) {
const top = view.rankings[0];
$("stat-top").textContent = top ? top.score.toFixed(3) : "—";
const ep = view.history?.epochs;
$("stat-epoch").textContent = ep && ep.length ? ep[ep.length - 1] : "—";
}
function renderBoard(rankings) {
const body = $("board-body");
body.innerHTML = "";
$("board-empty").hidden = rankings.length > 0;
const max = rankings.reduce((m, r) => Math.max(m, r.score), 0) || 1;
rankings.forEach((r, i) => {
const tr = document.createElement("tr");
tr.className = "rank-" + (i + 1);
const sk = shortKey(r.hotkey);
const pct = Math.max(2, Math.round((r.score / max) * 100));
const rankCell = document.createElement("td");
rankCell.className = "c-rank";
const rank = document.createElement("span");
rank.className = "rank-num";
rank.textContent = String(i + 1).padStart(2, "0");
rankCell.appendChild(rank);
const hotkeyCell = document.createElement("td");
const hotkey = document.createElement("span");
hotkey.className = "hotkey";
const head = document.createElement("span");
head.className = "head";
head.textContent = sk.head;
const tail = document.createElement("span");
tail.className = "tail";
tail.textContent = sk.tail;
hotkey.append(head, tail);
hotkeyCell.appendChild(hotkey);
const scoreCell = document.createElement("td");
scoreCell.className = "score-val";
scoreCell.textContent = r.score.toFixed(4);
const barCell = document.createElement("td");
barCell.className = "c-bar";
const bar = document.createElement("div");
bar.className = "bar";
const barFill = document.createElement("i");
barFill.style.width = `${pct}%`;
bar.appendChild(barFill);
barCell.appendChild(bar);
tr.append(rankCell, hotkeyCell, scoreCell, barCell);
body.appendChild(tr);
});
}
function seriesFor(history, hotkey) {
if (!history) return null;
const epochs = history.epochs || [];
const miner = history.miners ? history.miners[hotkey] : null;
const original = history.original || null;
return { epochs, miner, original };
}
function hasPoints(arr) {
return Array.isArray(arr) && arr.some((x) => x !== null && x !== undefined && !Number.isNaN(x));
}
function renderTrends(view) {
const top = view.rankings[0];
const s = top ? seriesFor(view.history, top.hotkey) : null;
const sk = top ? shortKey(top.hotkey) : { head: "—", tail: "" };
$("trend-miner").textContent = sk.head + sk.tail;
drawTrend("score", s, "score", top);
drawTrend("len", s, "completion_len", top);
}
function drawTrend(which, s, field, top) {
const canvasId = which === "score" ? "chart-score" : "chart-len";
const awaitId = which === "score" ? "await-score" : "await-len";
const minerData = s?.miner?.[field];
const origData = s?.original?.[field];
const ok = top && s && s.epochs.length && (hasPoints(minerData) || hasPoints(origData));
$(awaitId).hidden = !!ok;
if (!ok) {
destroyChart(which);
return;
}
const ctx = $(canvasId).getContext("2d");
const datasets = [];
if (hasPoints(minerData)) datasets.push(lineDS("Top miner", minerData, ACCENT, css("--accent-ghost")));
if (hasPoints(origData)) datasets.push(lineDS("Original model", origData, BASE, "transparent", true));
const cfg = {
type: "line",
data: { labels: s.epochs, datasets },
options: chartOptions(which === "len" ? "tokens" : "score"),
};
destroyChart(which);
const chart = new Chart(ctx, cfg);
if (which === "score") scoreChart = chart; else lenChart = chart;
}
function lineDS(label, data, color, fill, dashed = false) {
return {
label, data,
borderColor: color,
backgroundColor: fill,
borderWidth: 2,
borderDash: dashed ? [5, 4] : [],
pointRadius: 0,
pointHoverRadius: 4,
tension: 0.25,
fill: !dashed,
spanGaps: true,
};
}
function chartOptions(yLabel) {
const grid = css("--line-soft");
const tick = css("--faint");
return {
responsive: true,
maintainAspectRatio: false,
interaction: { mode: "index", intersect: false },
plugins: {
legend: { labels: { color: css("--muted"), boxWidth: 10, boxHeight: 10, usePointStyle: true, font: { size: 11 } } },
tooltip: {
backgroundColor: "#0b0e12", borderColor: css("--line"), borderWidth: 1,
titleColor: css("--muted"), bodyColor: css("--text"), padding: 10, displayColors: true,
},
},
scales: {
x: { title: { display: true, text: "epoch", color: tick, font: { size: 10 } }, grid: { color: grid }, ticks: { color: tick, font: { size: 10 } } },
y: { title: { display: true, text: yLabel, color: tick, font: { size: 10 } }, grid: { color: grid }, ticks: { color: tick, font: { size: 10 } } },
},
};
}
function destroyChart(which) {
if (which === "score" && scoreChart) { scoreChart.destroy(); scoreChart = null; }
if (which === "len" && lenChart) { lenChart.destroy(); lenChart = null; }
}
window.addEventListener("DOMContentLoaded", load);