Spaces:
Running
Running
| // ===== State ===== | |
| let allResults = []; | |
| let activeFilter = 'all'; | |
| let searchQuery = ''; | |
| // ===== DOM Elements ===== | |
| const searchInput = document.getElementById('searchInput'); | |
| const filterButtons = document.querySelectorAll('.filter-btn'); | |
| const resultsContainer = document.getElementById('resultsContainer'); | |
| const resultsInfo = document.getElementById('resultsInfo'); | |
| // ===== Init ===== | |
| document.addEventListener('DOMContentLoaded', () => { | |
| loadBenchmarkData(); | |
| loadSubtitle(); | |
| bindEvents(); | |
| }); | |
| function bindEvents() { | |
| searchInput.addEventListener('input', (e) => { | |
| searchQuery = e.target.value.toLowerCase().trim(); | |
| render(); | |
| }); | |
| filterButtons.forEach(btn => { | |
| btn.addEventListener('click', () => { | |
| setActiveFilter(btn.dataset.filter); | |
| }); | |
| }); | |
| // Stat card shortcuts | |
| document.querySelectorAll('.stat-card[data-filter]').forEach(card => { | |
| card.addEventListener('click', () => { | |
| setActiveFilter(card.dataset.filter); | |
| }); | |
| }); | |
| } | |
| function setActiveFilter(filter) { | |
| activeFilter = filter; | |
| filterButtons.forEach(b => { | |
| b.classList.toggle('active', b.dataset.filter === filter); | |
| }); | |
| render(); | |
| } | |
| // ===== Subtitle ===== | |
| async function loadSubtitle() { | |
| const el = document.getElementById('subtitleText'); | |
| try { | |
| const res = await fetch('data/subtitle.md'); | |
| if (!res.ok) throw new Error(`HTTP ${res.status}`); | |
| const text = await res.text(); | |
| el.innerHTML = renderLightMd(text.trim()) || 'Compare model performance across tests'; | |
| } catch { | |
| el.textContent = 'Compare model performance across tests'; | |
| } | |
| } | |
| function renderLightMd(md) { | |
| return md | |
| .split(/\n\n+/) | |
| .map(block => | |
| '<p>' + block | |
| .replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>') | |
| .replace(/\*(.+?)\*/g, '<em>$1</em>') | |
| .replace(/ \n/g, '<br>') | |
| .replace(/\n/g, '<br>') + | |
| '</p>' | |
| ) | |
| .join(''); | |
| } | |
| // ===== Data Loading ===== | |
| async function loadBenchmarkData() { | |
| try { | |
| const response = await fetch('data/benchmark.md'); | |
| if (!response.ok) throw new Error(`HTTP ${response.status}`); | |
| const mdText = await response.text(); | |
| allResults = parseMarkdownTable(mdText); | |
| updateStats(); | |
| render(); | |
| } catch (err) { | |
| resultsContainer.innerHTML = ` | |
| <div class="error-state"> | |
| <p>Failed to load benchmark data</p> | |
| <code>${escapeHtml(err.message)}</code> | |
| </div> | |
| `; | |
| } | |
| } | |
| // ===== MD Parser ===== | |
| function parseMarkdownTable(md) { | |
| const lines = md.split('\n').filter(line => line.trim().startsWith('|')); | |
| if (lines.length < 2) return []; | |
| // Parse header | |
| const headers = parseRow(lines[0]).map(h => h.trim().toLowerCase()); | |
| // Skip separator row (line index 1), parse data rows | |
| const results = []; | |
| for (let i = 2; i < lines.length; i++) { | |
| const cells = parseRow(lines[i]); | |
| if (cells.length === 0) continue; | |
| const entry = {}; | |
| headers.forEach((header, idx) => { | |
| entry[header] = (cells[idx] || '').trim(); | |
| }); | |
| // Normalize score | |
| const rawScore = (entry.score || '').toLowerCase().trim(); | |
| if (rawScore === 'fail' || rawScore === 'failed' || rawScore === 'f') { | |
| entry.scoreKey = 'fail'; | |
| entry.scoreLabel = 'FAIL'; | |
| entry.scoreNumeric = -1; | |
| } else { | |
| const num = parseInt(rawScore, 10); | |
| if (isNaN(num)) continue; // skip invalid rows | |
| entry.scoreKey = String(Math.min(Math.max(num, 0), 3)); | |
| entry.scoreLabel = String(num); | |
| entry.scoreNumeric = num; | |
| } | |
| results.push(entry); | |
| } | |
| return results; | |
| } | |
| function parseRow(line) { | |
| const parts = line.split('|'); | |
| if (parts.length > 1) { | |
| parts.pop(); | |
| parts.shift(); | |
| } | |
| return parts; | |
| } | |
| // ===== Stats ===== | |
| function updateStats() { | |
| const total = allResults.length; | |
| const scored = allResults.filter(r => r.scoreNumeric >= 0); | |
| const avg = scored.length > 0 | |
| ? (scored.reduce((sum, r) => sum + r.scoreNumeric, 0) / scored.length).toFixed(2) | |
| : '—'; | |
| const fails = allResults.filter(r => r.scoreKey === 'fail').length; | |
| const perfect = allResults.filter(r => r.scoreNumeric === 3).length; | |
| const passRate = total > 0 | |
| ? Math.round((scored.length / total) * 100) + '%' | |
| : '—'; | |
| document.getElementById('statTotal').textContent = total; | |
| document.getElementById('statAvg').textContent = avg; | |
| document.getElementById('statPerfect').textContent = perfect; | |
| document.getElementById('statFails').textContent = fails; | |
| document.getElementById('statPass').textContent = passRate; | |
| } | |
| // ===== Filtering ===== | |
| function getFilteredResults() { | |
| return allResults.filter(entry => { | |
| // Score filter | |
| if (activeFilter !== 'all' && entry.scoreKey !== activeFilter) return false; | |
| // Search filter | |
| if (searchQuery) { | |
| const haystack = [ | |
| entry.model || '', | |
| entry.notes || '', | |
| entry.scoreLabel || '' | |
| ].join(' ').toLowerCase(); | |
| if (!haystack.includes(searchQuery)) return false; | |
| } | |
| return true; | |
| }); | |
| } | |
| // ===== Rendering ===== | |
| function render() { | |
| const filtered = getFilteredResults(); | |
| // Update results info | |
| resultsInfo.textContent = `Showing ${filtered.length} of ${allResults.length} models`; | |
| if (filtered.length === 0) { | |
| resultsContainer.innerHTML = ` | |
| <div class="empty-state"> | |
| <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"> | |
| <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607z"/> | |
| </svg> | |
| <p>No results match your filters</p> | |
| </div> | |
| `; | |
| return; | |
| } | |
| const html = `<div class="results-list">${filtered.map(renderRow).join('')}</div>`; | |
| resultsContainer.innerHTML = html; | |
| } | |
| function renderRow(entry) { | |
| const scoreClass = entry.scoreKey === 'fail' ? 'score-fail' : `score-${entry.scoreKey}`; | |
| const scoreLabel = entry.scoreKey === 'fail' ? 'FAIL' : entry.scoreLabel; | |
| const notes = entry.notes ? escapeHtml(entry.notes) : ''; | |
| const nameDisplay = notes | |
| ? `${escapeHtml(entry.model || 'Unknown')} <span class="result-notes">(${notes})</span>` | |
| : escapeHtml(entry.model || 'Unknown'); | |
| return ` | |
| <div class="result-row"> | |
| <div class="score-badge ${scoreClass}">${scoreLabel}</div> | |
| <div class="result-model">${nameDisplay}</div> | |
| </div> | |
| `; | |
| } | |
| function escapeHtml(text) { | |
| const div = document.createElement('div'); | |
| div.textContent = text; | |
| return div.innerHTML; | |
| } |