// ── Output Example Demo renderer ─────────────────────────────────────────────
// Supports multiple clips with left/right arrow navigation, device selector,
// and streaming text effect at real TPS speed.
const DEMO_DEVICE_LABELS = {
orin_nano_super: "Jetson Orin Nano Super",
agx_orin: "Jetson AGX Orin",
agx_thor: "Jetson AGX Thor",
};
const DEMO_DEFAULT_DEVICE = "agx_orin";
const DEMO_TOKENS_PER_WORD = 1.33;
// ── CSV parser (minimal, demo-only) ─────────────────────────────────────────
function demoParseCsv(text) {
const lines = text.replace(/\r/g, "").trim().split("\n");
const headers = lines[0].split(",");
return lines.slice(1).map(line => {
const vals = line.split(",");
const row = {};
headers.forEach((h, i) => { row[h] = (vals[i] || "").trim(); });
return row;
});
}
// ── Look up TPS from benchmark data ─────────────────────────────────────────
function demoLookupTps(csvRows, modelName, device, matchCriteria) {
const row = csvRows.find(r =>
r.model === modelName &&
r.device === device &&
Object.entries(matchCriteria).every(([col, val]) => r[col] === val)
);
if (row) {
if (!row.tps || row.tps.toUpperCase() === "OOM") return { found: true, tps: null };
return { found: true, tps: parseFloat(row.tps) };
}
const oomRow = csvRows.find(r =>
r.model === modelName &&
r.device === device &&
r.tps && r.tps.toUpperCase() === "OOM"
);
if (oomRow) return { found: true, tps: null };
return { found: false, tps: null };
}
// ── Determine available devices from benchmark data ─────────────────────────
function demoAvailableDevices(csvRows, models, matchCriteria) {
const deviceSet = new Set();
csvRows.forEach(r => {
if (!models.includes(r.model)) return;
if (!Object.entries(matchCriteria).every(([col, val]) => r[col] === val)) return;
if (r.tps && r.tps.toUpperCase() !== "OOM") deviceSet.add(r.device);
});
return Object.keys(DEMO_DEVICE_LABELS).filter(d => deviceSet.has(d));
}
// ── Streaming text animation ────────────────────────────────────────────────
function demoStreamText(element, fullText, tps) {
const handle = { _tid: null, cancel() { clearTimeout(this._tid); } };
element.textContent = "";
if (!tps || tps <= 0) {
element.textContent = fullText;
return handle;
}
const words = fullText.split(/(\s+)/);
const delayMs = 1000 / (tps / DEMO_TOKENS_PER_WORD);
let idx = 0;
function tick() {
if (idx < words.length) {
element.textContent += words[idx];
idx++;
handle._tid = setTimeout(tick, delayMs);
}
}
tick();
return handle;
}
// ── Pre-calculate height for an output box to prevent layout shift ──────────
function demoPreCalcHeight(box, textEl, fullText) {
textEl.textContent = fullText;
const h = box.offsetHeight;
box.style.minHeight = h + "px";
textEl.textContent = "";
}
// ── Main render function ────────────────────────────────────────────────────
async function renderDemo(data, container, optimizedOrg, dataFile, modelColors) {
if (!data) return;
// Normalise: support both old single-clip format and new clips array
let clips = data.clips;
if (!clips) {
clips = [{
video: data.video,
label: data.title,
prompt: data.prompt,
inference_setup: data.inference_setup,
citation: data.citation,
citation_url: data.citation_url,
outputs: data.outputs,
}];
}
if (!clips.length) return;
const matchCriteria = data.benchmark_match || {};
// Collect all model names across clips
const allModelNames = [...new Set(clips.flatMap(c => (c.outputs || []).map(o => o.model)))];
// Load benchmark CSV
let csvRows = [];
if (dataFile) {
try {
const csvResp = await fetch(dataFile);
if (csvResp.ok) csvRows = demoParseCsv(await csvResp.text());
} catch { /* proceed without */ }
}
const devices = csvRows.length
? demoAvailableDevices(csvRows, allModelNames, matchCriteria)
: [];
let selectedDevice = devices.includes(DEMO_DEFAULT_DEVICE)
? DEMO_DEFAULT_DEVICE
: (devices[0] || DEMO_DEFAULT_DEVICE);
let currentClipIdx = 0;
let activeStreams = [];
// ── Build DOM skeleton ──────────────────────────────────────────────
const section = document.createElement("div");
section.className = "demo-section";
// Toggle button
const toggle = document.createElement("button");
toggle.className = "demo-toggle";
toggle.innerHTML = '▶ Show Demo';
// Collapsible wrapper
const content = document.createElement("div");
content.className = "demo-content";
const inner = document.createElement("div");
inner.className = "demo-content-inner";
const card = document.createElement("div");
card.className = "demo-card";
// Title row: h3 + device selector
const titleRow = document.createElement("div");
titleRow.className = "demo-title-row";
const titleLeft = document.createElement("div");
titleLeft.className = "demo-title-left";
const h3 = document.createElement("h3");
titleLeft.appendChild(h3);
const clipSetup = document.createElement("span");
clipSetup.className = "demo-clip-setup";
titleLeft.appendChild(clipSetup);
titleRow.appendChild(titleLeft);
const deviceSelector = document.createElement("div");
deviceSelector.className = "demo-device-selector";
if (devices.length > 1) {
const deviceGroup = document.createElement("div");
deviceGroup.className = "btn-group";
function renderDeviceButtons() {
deviceGroup.innerHTML = "";
devices.forEach(dev => {
const btn = document.createElement("button");
btn.className = "btn" + (dev === selectedDevice ? " active" : "");
btn.dataset.value = dev;
btn.textContent = DEMO_DEVICE_LABELS[dev] || dev;
deviceGroup.appendChild(btn);
});
}
renderDeviceButtons();
deviceGroup.addEventListener("click", e => {
const btn = e.target.closest(".btn");
if (!btn) return;
const newDevice = btn.dataset.value;
if (newDevice === selectedDevice) return;
selectedDevice = newDevice;
renderDeviceButtons();
renderOutputs();
});
deviceSelector.appendChild(deviceGroup);
}
card.appendChild(titleRow);
// Video with overlay arrows
const videoWrap = document.createElement("div");
videoWrap.className = "demo-video-wrap";
// Pre-create and buffer a