import { CONFIG } from "./config.js";
import { costAt, rateText } from "./cost.js";
import * as hf from "./hf.js";
const CAT_COLORS = { code: "#3b82f6", general: "#f97316", cyber: "#10b981", visual: "#f59e0b", chat: "#ec4899" };
const RUN_COLORS = { pro: "#f0643c", flash: "#3b82f6" };
const UNITS = ["second", "minute", "hour", "day", "month", "year"];
const state = {
data: null,
error: null,
authError: null,
lastSync: null,
tab: "overview",
token: null,
me: null,
isAdmin: false,
dirty: false,
saveStatus: "",
saveFailed: false,
jsonDraft: null,
jsonError: "",
ui: { xMode: "step", yLog: false, smooth: 0, compMode: "count" },
};
let chartSeq = 0;
const chartStore = {};
/* ---------- helpers ---------- */
const $ = (sel) => document.querySelector(sel);
const esc = (s) =>
String(s ?? "").replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c]));
const fmtInt = (n) => (n == null || isNaN(n) ? "—" : Math.round(n).toLocaleString("en-US"));
const fmtMoney = (n) => "$" + fmtInt(n);
function fmtNum(v) {
if (v == null || isNaN(v)) return "—";
const a = Math.abs(v);
if (a >= 1000) return Math.round(v).toLocaleString("en-US");
if (a >= 1) return v.toFixed(2);
if (a === 0) return "0";
return v.toPrecision(3);
}
function fmtBig(n) {
if (n == null || isNaN(n)) return "—";
const a = Math.abs(n);
if (a >= 1e9) return (n / 1e9).toFixed(2) + "B";
if (a >= 1e6) return (n / 1e6).toFixed(1) + "M";
if (a >= 1e3) return (n / 1e3).toFixed(0) + "k";
return String(Math.round(n));
}
function fmtUtc(iso) {
const d = new Date(iso);
return isNaN(d) ? "—" : d.toISOString().slice(0, 16).replace("T", " ") + " UTC";
}
function fmtTime(t) {
return isNaN(Date.parse(t)) ? String(t ?? "") : fmtUtc(t);
}
function fmtDuration(ms) {
if (isNaN(ms)) return "—";
const s = Math.max(0, Math.floor(ms / 1000));
const d = Math.floor(s / 86400);
const h = String(Math.floor((s % 86400) / 3600)).padStart(2, "0");
const m = String(Math.floor((s % 3600) / 60)).padStart(2, "0");
const sec = String(s % 60).padStart(2, "0");
return `${d}d ${h}:${m}:${sec}`;
}
const last = (vals) => (vals || []).filter((v) => v != null).slice(-1)[0];
const runName = (k) => state.data?.runs?.find((r) => r.id === k)?.name ?? k;
const runColor = (k) => state.data?.runs?.find((r) => r.id === k)?.color ?? RUN_COLORS[k] ?? "#888";
const costNow = () => (state.data ? costAt(state.data.cost, Date.now()) : 0);
function metricLast(group, name, runId) {
const m = state.data.metrics.find((x) => x.group === group && x.name === name);
return m ? last(m.series[runId]) : undefined;
}
function delta(vals) {
const v = (vals || []).filter((x) => x != null);
if (v.length < 2) return "";
const a = v[v.length - 1];
const b = v[v.length - 2];
if (v.every((x) => x >= 0 && x <= 1)) {
const d = (a - b) * 100;
return `${d >= 0 ? "▲" : "▼"} ${Math.abs(d).toFixed(2)} pt`;
}
const p = b ? ((a - b) / Math.abs(b)) * 100 : 0;
return `${p >= 0 ? "▲" : "▼"} ${Math.abs(p).toFixed(1)}%`;
}
const deltaClass = (vals) => (delta(vals).startsWith("▲") ? "up" : "down");
function smooth(vals, w) {
if (w <= 1) return vals;
return vals.map((_, i) => {
const s = vals.slice(Math.max(0, i - w + 1), i + 1).filter((v) => v != null);
return s.length ? s.reduce((x, y) => x + y, 0) / s.length : null;
});
}
// Hours per training step, used for the "time" x-axis option.
function stepHours() {
const r = state.data?.runs?.find((x) => x.step > 0 && x.startedAt);
if (!r) return 1;
const end = r.stoppedAt ? Date.parse(r.stoppedAt) : Date.now();
return (end - Date.parse(r.startedAt)) / 3600000 / r.step;
}
function xLabel(i) {
return state.ui.xMode === "time" ? (i * stepHours()).toFixed(1) + "h" : String(i + 1);
}
/* ---------- charts ---------- */
function chartSvg(series) {
const n = Math.max(0, ...series.map((s) => s.values.length));
const logOn = state.ui.yLog;
const ser = series.map((s) => ({ ...s, values: smooth(s.values, state.ui.smooth) }));
const ok = (v) => v != null && !isNaN(v) && (!logOn || v > 0);
const tv = (v) => (logOn ? Math.log10(v) : v);
const flat = ser.flatMap((s) => s.values.filter(ok));
if (n < 2 || !flat.length) return `
no data
`;
let lo = tv(Math.min(...flat));
let hi = tv(Math.max(...flat));
if (hi - lo < 1e-9) { lo -= 1; hi += 1; }
const pad = (hi - lo) * 0.08;
lo -= pad;
hi += pad;
const W = 600, H = 220, pl = 48, pr = 12, pt = 10, pb = 24;
const X = (i) => pl + ((W - pl - pr) * i) / (n - 1);
const Y = (v) => pt + (H - pt - pb) * (1 - (tv(v) - lo) / (hi - lo));
const inv = (t) => (logOn ? 10 ** t : t);
let grid = "";
for (let k = 0; k <= 4; k++) {
const y = pt + (H - pt - pb) * (1 - k / 4);
const val = inv(lo + ((hi - lo) * k) / 4);
grid += ``;
grid += `${fmtNum(val)}`;
}
const labels = Array.from({ length: n }, (_, i) => xLabel(i));
let xl = "";
for (let k = 0; k <= 4; k++) {
const i = Math.round(((n - 1) * k) / 4);
xl += `${labels[i]}`;
}
const paths = ser
.map((s) => {
let d = "";
let pen = false;
s.values.forEach((v, i) => {
if (!ok(v)) { pen = false; return; }
d += (pen ? "L" : "M") + X(i).toFixed(1) + " " + Y(v).toFixed(1) + " ";
pen = true;
});
return ``;
})
.join("");
const id = "c" + ++chartSeq;
chartStore[id] = { ser, labels, n, W, pl, pr };
return ``;
}
function stackedSvg(cats) {
const keys = Object.keys(cats);
const n = Math.max(0, ...keys.map((k) => cats[k].length));
if (!n) return `no data
`;
const totals = Array.from({ length: n }, (_, i) => keys.reduce((s, k) => s + (cats[k][i] || 0), 0));
const share = state.ui.compMode === "share";
const W = 600, H = 220, pl = 48, pt = 10, pb = 24;
const max = share ? 1 : Math.max(...totals) || 1;
const bw = (W - pl) / n;
let bars = "";
for (let i = 0; i < n; i++) {
let acc = 0;
for (const k of keys) {
const raw = cats[k][i] || 0;
const v = share ? (totals[i] ? raw / totals[i] : 0) : raw;
const h = ((H - pt - pb) * v) / max;
bars += `step ${i + 1} · ${k}: ${fmtInt(raw)}`;
acc += h;
}
}
const ticks = [0, 0.5, 1]
.map((f) => {
const y = pt + (H - pt - pb) * (1 - f);
const label = share ? Math.round(f * 100) + "%" : fmtInt(max * f);
return `${label}`;
})
.join("");
const xl = [0, Math.floor((n - 1) / 2), n - 1]
.map((i) => `${i + 1}`)
.join("");
return ``;
}
function legendHtml(series, showDelta = false) {
return `${series
.map(
(s) => `${esc(s.name)} ${fmtNum(last(s.values))}${
showDelta ? ` ${delta(s.values)}` : ""
}`
)
.join("")}
`;
}
/* ---------- sections ---------- */
const tabBtn = (id, label) =>
``;
const segBtn = (k, v, on) =>
``;
function authHtml() {
if (state.isAdmin) {
return `ADMIN · @${esc(state.me.name)}`;
}
if (state.me) {
return `@${esc(state.me.name)} · read-only`;
}
return ``;
}
function saveHtml() {
if (!state.saveStatus) return "";
return (
`${esc(state.saveStatus)}` +
(state.saveFailed ? `` : "")
);
}
function runCard(r) {
const running = r.status === "running" && !r.stoppedAt;
const start = Date.parse(r.startedAt);
const stop = r.stoppedAt ? Date.parse(r.stoppedAt) : "";
const stat = (label, value) =>
`${label}${value}
`;
return `
${esc(r.name)}
${running ? "running" : "stopped"}
step ${fmtInt(r.step)}
${fmtDuration((stop || Date.now()) - start)}
${stat("avg@n", fmtNum(metricLast("dynsam", "avg@n", r.id)))}
${stat("cost so far", fmtMoney(r.costSoFar))}
${stat("tokens · step", fmtBig(r.tokensAtStep))}
${stat("tokens · total", fmtBig(r.tokensTotal))}
${stat("samples trained", fmtBig(r.samplesTrained))}
${stat("train batch × rollouts", `${fmtInt(r.trainBatch)} × ${r.rollouts ?? "—"}`)}
`;
}
function noticesHtml() {
const items = [...state.data.notices].sort((a, b) => Date.parse(b.time) - Date.parse(a.time));
const form = state.isAdmin
? ``
: "";
const list = items.length
? items
.map(
(n) => `
${fmtUtc(n.time)}
${esc(n.text)}
${state.isAdmin ? `` : ""}
`
)
.join("")
: `No notices.
`;
return `
noticesUTC
${form}
${list}
`;
}
function readCostForm() {
const raw = $("#cost-correct").value.trim();
const correct = raw === "" ? Math.round(costNow()) : Number(raw);
const inc = Number($("#cost-inc").value);
const every = Number($("#cost-every").value);
const unit = $("#cost-unit").value;
const ok = isFinite(correct) && isFinite(inc) && inc >= 0 && isFinite(every) && every > 0;
return { ok, correct, inc, every, unit };
}
function updateCostPreview() {
const el = $("#cost-preview");
if (!el) return;
const f = readCostForm();
el.textContent = f.ok
? `Preview: shows ${fmtMoney(f.correct)} now, then ${rateText({ increment: f.inc, every: f.every, unit: f.unit })}`
: "Enter valid numbers.";
}
function adminCostHtml() {
const c = state.data.cost;
return `
`;
}
function benchHtml() {
const bs = state.data.benchmarks;
if (!bs.length) return "";
const cards = bs
.map((b) => {
const series = Object.keys(b.series).map((k) => ({ name: runName(k), color: runColor(k), values: b.series[k] }));
return `
${esc(b.name)}${esc(b.subtitle || "")}
${legendHtml(series)}
${chartSvg(series)}
`;
})
.join("");
return `benchmarks
`;
}
function batchHtml() {
const bc = state.data.batchComposition || {};
const cats = bc.categories || {};
const keys = Object.keys(cats);
if (!keys.length) return "";
const legend = keys
.map((c) => `${esc(c)}`)
.join("");
return `
batch composition
what each step's samples are made of · by data source
${legend}
${stackedSvg(cats)}
`;
}
function sourcesHtml() {
const src = state.data.sources;
if (!src.length) return "";
const latest = Math.max(...src.map((s) => s.step));
const rows = src
.filter((s) => s.step === latest)
.sort((a, b) => b.accepted - a.accepted)
.map((r) => {
const pct = r.target ? Math.min(100, (r.accepted / r.target) * 100) : 0;
return `
| ${esc(runName(r.run))} |
${esc(r.name)} |
● ${esc(r.category)} |
${fmtInt(r.accepted)} / ${fmtInt(r.target)}
|
${fmtInt(r.remaining)} |
${r.judged == null ? "—" : fmtInt(r.judged)} |
${fmtInt(r.inFlight)} |
`;
})
.join("");
return `
sources
latest step · ${latest}
| run | source | category | accepted / target | remaining | judged | in flight |
${rows}
`;
}
function feedHtml() {
const f = state.data.feed;
const items = f
.map((x) => `${esc(fmtTime(x.time))} ${esc(x.message)}
`)
.join("");
return `
feed
`;
}
function overviewHtml() {
return `
${state.isAdmin ? adminCostHtml() : ""}
${noticesHtml()}
${state.data.runs.map(runCard).join("")}
${benchHtml()}
${batchHtml()}
${sourcesHtml()}
${feedHtml()}`;
}
function metricCard(m) {
const series = Object.keys(m.series).map((k) => ({ name: runName(k), color: runColor(k), values: m.series[k] }));
return `
${esc(m.group)}/${esc(m.name)}
${legendHtml(series, true)}
${chartSvg(series)}
`;
}
function metricGridHtml() {
const ms = state.data.metrics;
return ms.length ? ms.map(metricCard).join("") : `No metrics.
`;
}
function metricsHtml() {
const ui = state.ui;
return `
${metricGridHtml()}
`;
}
function renderMd(src) {
return esc(src || "")
.split(/\n\s*\n/)
.map((block) => {
if (/^#\s/.test(block)) return `${block.replace(/^#\s/, "")}
`;
if (/^- /m.test(block)) {
const items = block.split("\n").map((l) => `${l.replace(/^- /, "")}`).join("");
return ``;
}
return `${block.replace(/\n/g, "
")}
`;
})
.join("");
}
function aboutHtml() {
const admin = state.isAdmin
? `
edit about# heading · - bullets · blank line = new paragraph
${saveHtml()}
`
: "";
return `${renderMd(state.data.about)}${admin}`;
}
function jsonHtml() {
const text = state.jsonDraft ?? JSON.stringify(state.data, null, 2);
return `
Edit data (JSON)validated before saving
${state.jsonError ? "⚠ " + esc(state.jsonError) : "valid JSON"}
${state.dirty ? `unsaved changes` : ""}
${saveHtml()}
`;
}
function mainHtml() {
if (state.tab === "metrics") return metricsHtml();
if (state.tab === "about") return aboutHtml();
if (state.tab === "json" && state.isAdmin) return jsonHtml();
return overviewHtml();
}
function footerHtml() {
const f = state.data.footer || {};
const synced = state.lastSync ? ` · synced ${state.lastSync.toLocaleTimeString("en-GB", { hour12: false })}` : "";
return ``;
}
/* ---------- render & ticks ---------- */
function render() {
const d = state.data;
const banner = state.error || state.authError;
$("#app").innerHTML = `
${banner && d ? `Sync problem (${esc(banner)}), showing last good data.
` : ""}
${banner && !d ? `Could not load data: ${esc(banner)}
` : ""}
${d ? mainHtml() : `Loading…
`}
${d ? footerHtml() : ""}
`;
tickTime();
tickCost();
updateCostPreview();
}
function tickCost() {
if (!state.data) return;
const txt = fmtMoney(costNow());
document.querySelectorAll("[data-cost]").forEach((el) => (el.textContent = txt));
}
function tickTime() {
const now = new Date();
document.querySelectorAll("[data-clock]").forEach((el) => {
el.textContent = new Intl.DateTimeFormat("en-GB", {
timeZone: el.dataset.clock,
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: "h23",
}).format(now);
});
document.querySelectorAll(".elapsed").forEach((el) => {
const start = Number(el.dataset.start);
const end = el.dataset.stop ? Number(el.dataset.stop) : Date.now();
el.textContent = fmtDuration(end - start);
});
}
/* ---------- data flow ---------- */
function normalize(d) {
const cost = {
base: 0,
baseTime: new Date().toISOString(),
increment: 0,
every: 1,
unit: "hour",
...(d.cost || {}),
};
return {
notices: [],
runs: [],
metrics: [],
benchmarks: [],
sources: [],
feed: [],
about: "",
footer: {},
...d,
cost,
batchComposition: d.batchComposition || { categories: {} },
};
}
async function sync(force = false) {
if (state.dirty && !force) return;
try {
state.data = normalize(await hf.readData());
state.error = null;
state.lastSync = new Date();
} catch (e) {
state.error = e.message;
}
render();
}
async function save() {
if (!state.token) return;
state.saveStatus = "Saving...";
state.saveFailed = false;
render();
try {
await hf.writeData(state.token, state.data);
state.dirty = false;
state.jsonDraft = null;
state.jsonError = "";
state.saveStatus = "Saved";
await sync(true);
} catch (e) {
state.saveStatus = "Failed: " + e.message;
state.saveFailed = true;
render();
}
}
async function refreshIdentity() {
state.me = await hf.whoami(state.token).catch(() => null);
if (!state.me) {
hf.logout();
state.token = null;
}
state.isAdmin = !!state.me && state.me.name?.toLowerCase() === CONFIG.OWNER_HF_USERNAME.toLowerCase();
}
async function init() {
try {
state.token = (await hf.handleRedirect()) || sessionStorage.getItem("hf_token");
} catch (e) {
state.authError = e.message;
}
if (state.token) await refreshIdentity();
await sync(true);
setInterval(() => sync(false), CONFIG.REFRESH_MS);
setInterval(tickCost, 100);
setInterval(tickTime, 1000);
}
/* ---------- events ---------- */
document.addEventListener("click", async (e) => {
const el = e.target.closest("[data-action]");
if (!el) return;
switch (el.dataset.action) {
case "tab":
state.tab = el.dataset.tab;
render();
break;
case "login":
hf.login();
break;
case "logout":
hf.logout();
state.token = null;
state.me = null;
state.isAdmin = false;
state.dirty = false;
render();
break;
case "theme":
document.body.classList.toggle("light");
break;
case "ui": {
const k = el.dataset.k;
const v = el.dataset.v;
state.ui[k] = k === "yLog" ? v === "log" : v;
render();
break;
}
case "post-notice": {
const text = $("#notice-text").value.trim();
if (!text) break;
state.data.notices.push({ id: "n" + Date.now(), time: new Date().toISOString(), text });
save();
break;
}
case "del-notice":
if (confirm("Delete this notice?")) {
state.data.notices = state.data.notices.filter((n) => n.id !== el.dataset.id);
save();
}
break;
case "save-cost": {
const f = readCostForm();
if (!f.ok) {
state.saveStatus = "Invalid cost values";
state.saveFailed = true;
render();
break;
}
state.data.cost = {
base: f.correct,
baseTime: new Date().toISOString(),
increment: f.inc,
every: f.every,
unit: f.unit,
};
save();
break;
}
case "save-about":
state.data.about = $("#about-text").value;
save();
break;
case "json-save": {
try {
const parsed = JSON.parse(state.jsonDraft ?? JSON.stringify(state.data));
state.data = normalize(parsed);
state.jsonError = "";
save();
} catch (err) {
state.jsonError = err.message;
render();
}
break;
}
case "json-discard":
state.jsonDraft = null;
state.jsonError = "";
state.dirty = false;
sync(true);
break;
case "save":
save();
break;
}
});
function handleField(e) {
const t = e.target;
if (t.closest?.("[data-admin]")) state.dirty = true;
if (t.id === "json-edit") {
state.jsonDraft = t.value;
try {
JSON.parse(t.value);
state.jsonError = "";
} catch (err) {
state.jsonError = err.message;
}
const s = $("#json-status");
if (s) {
s.textContent = state.jsonError ? "⚠ " + state.jsonError : "valid JSON";
s.className = state.jsonError ? "err" : "muted";
}
}
if (t.id?.startsWith("cost-")) updateCostPreview();
if (t.id === "smooth") {
state.ui.smooth = Number(t.value);
$("#smooth-val").textContent = state.ui.smooth > 1 ? state.ui.smooth + " pts" : "off";
$("#metric-grid").innerHTML = metricGridHtml();
}
}
document.addEventListener("input", handleField);
document.addEventListener("change", handleField);
document.addEventListener("pointermove", (e) => {
const tip = $("#tip");
const svg = e.target.closest?.("svg[data-chart]");
const c = svg && chartStore[svg.dataset.chart];
if (!c) {
tip.hidden = true;
return;
}
const r = svg.getBoundingClientRect();
const x = ((e.clientX - r.left) / r.width) * c.W;
const frac = (x - c.pl) / (c.W - c.pl - c.pr);
const i = Math.max(0, Math.min(c.n - 1, Math.round(frac * (c.n - 1))));
tip.innerHTML =
`step ${esc(c.labels[i])}
` +
c.ser
.map((s) => `${esc(s.name)}: ${fmtNum(s.values[i])}
`)
.join("");
tip.hidden = false;
tip.style.left = e.clientX + 14 + "px";
tip.style.top = e.clientY + 14 + "px";
});
init();