Skip to content

Commit 67e2368

Browse files
committed
feat: autogenerate version selector from manifest
- Create data/benchmarks/manifest.json as single source of truth for available versions - Update index.html to remove hardcoded version options - Add loadVersionManifest() function to fetch and parse manifest - Modify initBenchmarkVersionSelector() to dynamically populate options from manifest - Set DEFAULT_BENCHMARK_VERSION from manifest's "latest" version - Add strict error handling: fail if latest version not found in manifest
1 parent 0262094 commit 67e2368

2 files changed

Lines changed: 87 additions & 27 deletions

File tree

index.html

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,10 @@ <h2 class="text-3xl font-semibold text-zinc-800 dark:text-zinc-100 mb-4 text-cen
198198
</table>
199199
</div>
200200

201-
<!-- Version selector: manual fixed list -->
201+
<!-- Version selector: autogenerated from manifest -->
202202
<div class="flex justify-center mt-8">
203203
<select id="version-select"
204204
class="text-sm bg-transparent text-zinc-400 dark:text-zinc-500 border border-zinc-300 dark:border-zinc-600 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:text-zinc-700 dark:focus:text-zinc-200 appearance-none text-center font-mono">
205-
<option value="v0.11.0" selected>v0.11.0</option>
206-
<option value="v0.10.1">v0.10.1</option>
207-
<option value="v0.10.0">v0.10.0</option>
208-
<option value="v0.9.0">v0.9.0</option>
209-
<option value="v0.8.2">v0.8.2</option>
210205
</select>
211206
</div>
212207
</div>

script.js

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,10 @@ function getCurrentTheme() {
3838

3939
// Global state for main leaderboard chart
4040
let performanceChart = null;
41-
const DEFAULT_BENCHMARK_VERSION = 'v0.11.0';
41+
let DEFAULT_BENCHMARK_VERSION = null; // Must be set from manifest
4242

4343
// Load details for a specific model
44-
async function loadDetails(vendor, model, basePath = 'data/benchmarks/v0.11.0/default') {
44+
async function loadDetails(vendor, model, basePath = 'data/benchmarks/v0.12.0/default') {
4545
try {
4646
const response = await fetch(`${basePath}/${vendor}/${model}.json`);
4747
const data = await response.json();
@@ -55,7 +55,7 @@ async function loadDetails(vendor, model, basePath = 'data/benchmarks/v0.11.0/de
5555
}
5656
}
5757

58-
// Create round distribution histogram (uses Chart.js defaults for fills)
58+
// Create round distribution histogram with stacked bars by seed
5959
function createRoundHistogram(stats, canvasId) {
6060
const rounds = stats.map(stat => stat.final_round);
6161
const maxRound = Math.max(...rounds);
@@ -65,39 +65,74 @@ function createRoundHistogram(stats, canvasId) {
6565
const bins = Array.from({
6666
length: maxRound
6767
}, (_, i) => i + minRound);
68-
const counts = bins.map(round => rounds.filter(r => r === round).length);
69-
const maxCount = Math.max(...counts);
7068

69+
// Extract unique seeds and sort them for consistent ordering
70+
const seeds = [...new Set(stats.map(stat => stat.seed || 'Unknown'))].sort();
71+
72+
// Create a color palette for seeds using theme-aware colors
7173
const ctx = document.getElementById(canvasId).getContext('2d');
7274
const theme = getCurrentTheme();
7375
const themeColors = colors[theme] || colors.light;
7476

77+
// Generate seed colors - use HSL with variations for distinction
78+
const seedColors = {};
79+
const hueStep = 360 / Math.max(seeds.length, 1);
80+
seeds.forEach((seed, index) => {
81+
const hue = (index * hueStep) % 360;
82+
const saturation = 60 + (index % 3) * 10; // Vary saturation
83+
const lightness = theme === 'dark' ? 55 : 45;
84+
seedColors[seed] = `hsla(${hue}, ${saturation}%, ${lightness}%, 0.8)`;
85+
});
86+
87+
// Create datasets - one per seed
88+
const datasets = seeds.map(seed => {
89+
const counts = bins.map(round => {
90+
return stats.filter(s => s.final_round === round && (s.seed || 'Unknown') === seed)
91+
.length;
92+
});
93+
94+
return {
95+
label: seed,
96+
data: counts,
97+
backgroundColor: seedColors[seed],
98+
borderColor: seedColors[seed],
99+
borderWidth: 0
100+
};
101+
});
102+
75103
new Chart(ctx, {
76104
type: 'bar',
77105
data: {
78106
labels: bins,
79-
datasets: [{
80-
data: counts
81-
}]
107+
datasets: datasets
82108
},
83109
options: {
84110
responsive: true,
85111
maintainAspectRatio: false,
86112
interaction: {
87113
intersect: false,
88-
mode: 'none'
114+
mode: 'index'
89115
},
90116
plugins: {
91117
legend: {
92-
display: false
118+
display: true,
119+
position: 'bottom',
120+
labels: {
121+
boxWidth: 10,
122+
color: themeColors.axis,
123+
font: {
124+
size: 11
125+
}
126+
}
93127
},
94128
title: {
95129
display: false,
96-
text: 'Rounds'
130+
text: 'Rounds by Seed'
97131
}
98132
},
99133
scales: {
100134
x: {
135+
stacked: true,
101136
title: {
102137
display: false,
103138
text: 'Round'
@@ -114,14 +149,13 @@ function createRoundHistogram(stats, canvasId) {
114149
}
115150
},
116151
y: {
152+
stacked: true,
117153
beginAtZero: true,
118-
max: maxCount + 1,
119154
title: {
120155
display: false,
121156
text: 'Frequency'
122157
},
123158
ticks: {
124-
stepSize: 1,
125159
color: themeColors.axis
126160
},
127161
grid: {
@@ -677,7 +711,7 @@ function createDetailRow(stats, modelName, data, vendor, model, basePath) {
677711
}
678712

679713
// Load and display leaderboard data
680-
async function loadLeaderboard(basePath = 'data/benchmarks/v0.11.0/default', displayMode = 'model',
714+
async function loadLeaderboard(basePath = 'data/benchmarks/v0.12.0/default', displayMode = 'model',
681715
showChart = true) {
682716
try {
683717
const response = await fetch(`${basePath}/leaderboard.json`);
@@ -773,7 +807,7 @@ async function loadLeaderboard(basePath = 'data/benchmarks/v0.11.0/default', dis
773807
<td class="px-4 py-3 text-center text-zinc-700 dark:text-zinc-300 font-mono whitespace-nowrap hidden xl:table-cell">${secondaryValue}</td>
774808
<td class="px-4 py-3 text-center text-zinc-700 dark:text-zinc-300 font-mono">
775809
<div class="flex justify-center items-center">
776-
<span class="w-8 text-center">${avgRound}</span>
810+
<span class="w-10 text-center">${avgRound}</span>
777811
<span class="px-1">±</span>
778812
<span class="w-8 text-center">${avgRoundStdDev}</span>
779813
</div>
@@ -1003,17 +1037,48 @@ function closeRunViewer(state) {
10031037
state.overlay.remove();
10041038
}
10051039

1006-
function initBenchmarkVersionSelector() {
1040+
// Load version manifest and populate version selector
1041+
async function loadVersionManifest() {
1042+
const response = await fetch('data/benchmarks/manifest.json');
1043+
if (!response.ok) {
1044+
throw new Error(`Failed to load version manifest: ${response.status} ${response.statusText}`);
1045+
}
1046+
1047+
const data = await response.json();
1048+
const versions = data.versions || [];
1049+
1050+
// Set DEFAULT_BENCHMARK_VERSION to the latest version (required)
1051+
const latestVersion = versions.find(v => v.latest);
1052+
if (!latestVersion) {
1053+
throw new Error('Manifest must contain a version marked with "latest": true');
1054+
}
1055+
1056+
DEFAULT_BENCHMARK_VERSION = latestVersion.version;
1057+
return versions;
1058+
}
1059+
1060+
// Populate version selector with options from manifest
1061+
async function initBenchmarkVersionSelector() {
10071062
const sel = document.getElementById('version-select');
10081063
const tableEl = document.getElementById('leaderboard-body');
10091064
if (!sel) {
1010-
// Fallback to default if selector missing, only if table exists on page
1011-
if (tableEl) {
1012-
loadLeaderboard(`data/benchmarks/${DEFAULT_BENCHMARK_VERSION}/default`, 'model', true);
1013-
}
1014-
return;
1065+
throw new Error('Version selector element not found');
10151066
}
10161067

1068+
// Load versions from manifest (will throw if latest not found or manifest missing)
1069+
const versions = await loadVersionManifest();
1070+
1071+
// Populate select options
1072+
versions.forEach(versionObj => {
1073+
const option = document.createElement('option');
1074+
option.value = versionObj.version;
1075+
option.textContent = versionObj.label;
1076+
if (versionObj.latest) {
1077+
option.selected = true;
1078+
}
1079+
sel.appendChild(option);
1080+
});
1081+
10171082
const applyVersion = (version) => {
10181083
const basePath = `data/benchmarks/${version}/default`;
10191084
const tbody = document.getElementById('leaderboard-body');

0 commit comments

Comments
 (0)