// ── 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