import { type GpuMetricKind } from "./metrics-parser"; import { type ModelRuntimeState } from "./inflight-tracker"; import { type UsageStats } from "./stats"; import { escapeXml, shorten } from "./util"; export function svgDataUrl(svg: string): string { return `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`; } const METRIC_LABEL: Record = { util_percent: "UTIL", memory_util_percent: "VRAM", temperature: "TEMP", power: "PWR", fan: "FAN", }; export interface InflightRenderOptions { modelName: string; state?: ModelRuntimeState; count: number; offline: boolean; history?: number[]; } export function renderInflight(opts: InflightRenderOptions): string { const name = escapeXml(shorten(opts.modelName === "all" ? "ALL MODELS" : opts.modelName)); if (opts.offline) { return frame("#10131a", [ centerText("!!", 34, 20, "bold", "#e0e0e0"), centerText("OFFLINE", 52, 9, "normal", "#bdbdbd"), centerText(name, 64, 7, "normal", "#ffffff"), ]); } if (opts.modelName === "unset") { return frame("#10131a", [ centerText("?", 36, 16, "bold", "#888888"), centerText("NO MODEL", 54, 8, "normal", "#666666"), ]); } if (!opts.state) { return frame("#10131a", [centerText("…", 36, 16, "bold", "#999999"), centerText(name, 60, 7, "normal", "#999999")]); } const isActive = opts.state === "ready" && opts.count > 0; const center = isActive ? `${opts.count}` : opts.state === "ready" ? "IDLE" : opts.state === "loading" ? "LOADING" : "OFF"; const centerSize = isActive ? 24 : 16; const parts: string[] = [ centerText(name, 12, 7, "normal", "#ffffff"), centerText(center, 40, centerSize, "bold", "#ffffff"), ]; if (opts.state === "ready") { const points = inflightSparkPoints(opts.history ?? []); if (points.length > 1) { parts.push( ``, ``, ); } } return frame("#10131a", parts); } export interface GpuGraphRenderOptions { gpuName: string; metric: GpuMetricKind; value: number | undefined; history: number[]; offline: boolean; } export function renderGpuGraph(opts: GpuGraphRenderOptions): string { const label = escapeXml(shorten(opts.gpuName)); if (opts.offline) { return ` !! OFFLINE ${label} `; } const color = opts.value === undefined ? "#666666" : severityColor(opts.metric, opts.value); const valueText = opts.value === undefined ? "--" : `${Math.round(opts.value)}${unit(opts.metric)}`; const points = chartPoints(opts.history, opts.metric); const line = points.length > 1 ? `` : ""; const area = points.length > 1 ? `` : ""; return ` ${area} ${line} ${valueText} ${METRIC_LABEL[opts.metric]} · ${label} `; } function unit(metric: GpuMetricKind): string { return metric === "temperature" ? "°C" : metric === "power" ? "W" : "%"; } function severityColor(metric: GpuMetricKind, value: number): string { if (metric === "temperature") return value >= 80 ? "#e0453a" : value >= 60 ? "#d9a02a" : "#3fae5a"; if (metric === "power") return value >= 300 ? "#e0453a" : value >= 150 ? "#d9a02a" : "#3fae5a"; return value >= 85 ? "#e0453a" : value >= 50 ? "#d9a02a" : "#3fae5a"; } function chartPoints(history: number[], metric: GpuMetricKind): { x: number; y: number }[] { const n = history.length; if (n === 0) return []; const left = 3; const right = 69; const top = 20; const bottom = 55; const yMax = yScaleMax(metric, history); return history.map((v, i) => { const x = n === 1 ? (left + right) / 2 : left + ((right - left) * i) / (n - 1); const clamped = Math.max(0, Math.min(v, yMax)); const y = bottom - ((clamped - 0) / (yMax - 0 || 1)) * (bottom - top); return { x: round1(x), y: round1(y) }; }); } function inflightSparkPoints(history: number[]): { x: number; y: number }[] { const n = history.length; if (n === 0) return []; const left = 4; const right = 68; const top = 50; const bottom = 63; const yMax = Math.max(...history, 1); return history.map((v, i) => { const x = n === 1 ? (left + right) / 2 : left + ((right - left) * i) / (n - 1); const clamped = Math.max(0, Math.min(v, yMax)); const y = bottom - (clamped / yMax) * (bottom - top); return { x: round1(x), y: round1(y) }; }); } function yScaleMax(metric: GpuMetricKind, history: number[]): number { if (metric !== "power") return 100; const maxValue = Math.max(...history); if (!isFinite(maxValue) || maxValue <= 0) return 100; return niceCeil(maxValue * 1.1); } function niceCeil(value: number): number { const magnitude = Math.pow(10, Math.floor(Math.log10(value))); for (const m of [1, 2, 2.5, 5, 10]) { if (m * magnitude >= value) return m * magnitude; } return value; } function round1(value: number): number { return Math.round(value * 10) / 10; } function centerText(text: string, y: number, size: number, weight: "normal" | "bold", fill: string, opacity?: number): string { return `${text}`; } function frame(bg: string, parts: string[]): string { return ` ${parts.join("\n ")} `; } export function formatCompact(n: number): string { if (!Number.isFinite(n)) return "--"; if (n < 1000) return `${Math.round(n)}`; if (n < 1_000_000) return `${(n / 1000).toFixed(1)}k`; return `${(n / 1_000_000).toFixed(1)}M`; } export interface UsageRenderOptions { modelName: string; stats?: UsageStats; primaryStat: "requests" | "input_tokens" | "output_tokens" | "gen_p95"; offline: boolean; } export function renderUsage(opts: UsageRenderOptions): string { const name = escapeXml(shorten(opts.modelName === "all" ? "ALL MODELS" : opts.modelName)); if (opts.offline) { return frame("#10131a", [ centerText("!!", 34, 20, "bold", "#e0e0e0"), centerText("OFFLINE", 52, 9, "normal", "#bdbdbd"), centerText(name, 64, 7, "normal", "#ffffff"), ]); } const s = opts.stats; const big = s ? formatCompact(primaryValue(s, opts.primaryStat)) : "--"; const rows = usageRows(s, opts.primaryStat); const parts: string[] = [ centerText(name, 10, 7, "normal", "#ffffff"), centerText(big, 36, 24, "bold", "#ffffff"), ]; for (const row of rows) { parts.push( `${row.label}`, `${row.value}`, ); } return frame("#10131a", parts); } function primaryValue(s: UsageStats, primary: "requests" | "input_tokens" | "output_tokens" | "gen_p95"): number { switch (primary) { case "requests": return s.totalRequests; case "input_tokens": return s.totalInputTokens; case "output_tokens": return s.totalOutputTokens; case "gen_p95": return s.genP95; } } function usageRows( s: UsageStats | undefined, primary: "requests" | "input_tokens" | "output_tokens" | "gen_p95", ): { label: string; value: string; y: number }[] { const items: { label: string; value: string }[] = []; if (primary !== "requests") items.push({ label: "REQ", value: s ? formatCompact(s.totalRequests) : "--" }); if (primary !== "input_tokens") items.push({ label: "IN", value: s ? formatCompact(s.totalInputTokens) : "--" }); if (primary !== "output_tokens") items.push({ label: "OUT", value: s ? formatCompact(s.totalOutputTokens) : "--" }); if (primary !== "gen_p95") items.push({ label: "P95", value: s ? `${Math.round(s.genP95)} t/s` : "--" }); return items.map((it, i) => ({ ...it, y: 52 + i * 7 })); }