elmadany commited on
Commit
b27609b
·
verified ·
1 Parent(s): eb2b89b

Update public/index.html

Browse files
Files changed (1) hide show
  1. public/index.html +375 -166
public/index.html CHANGED
@@ -3,167 +3,389 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Simba Benchmark</title>
7
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Rubik:wght@400;600&display=swap" rel="stylesheet">
 
 
 
 
 
 
 
8
  <style>
9
  :root {
10
- --primary-navy: #282351;
11
- --primary-orange: #D97706;
12
- --secondary-navy: #2f3b7d;
13
- --bg-body: #282351;
14
- --bg-card: #ffffff;
15
- --border-gold: #dca02a;
16
- --text-dark: #333;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  }
18
 
19
- body { background-color: var(--bg-body); font-family: 'Inter', sans-serif; color: var(--text-dark); margin: 0; padding: 20px; }
20
- .container { max-width: 1400px; margin: 0 auto; }
21
-
22
- .header { text-align: center; margin-bottom: 30px; }
23
- .header img { max-width: 60%; height: auto; border-radius: 12px; }
24
-
25
- .card { background: var(--bg-card); border-radius: 12px; padding: 40px; box-shadow: 0 4px 15px rgba(0,0,0,0.2); margin-bottom: 30px; }
 
 
 
 
 
 
26
 
27
- h2 { font-family: "Rubik", sans-serif; color: var(--secondary-navy); font-size: 28px; margin-top: 0; }
28
- h3.section-title { font-family: "Rubik", sans-serif; color: var(--primary-orange); font-size: 20px; margin-bottom: 15px; margin-top: 20px;}
29
-
30
- /* Tabs */
31
- .tabs { display: flex; border-bottom: 2px solid var(--primary-navy); margin-bottom: 20px; }
32
- .tab-btn {
33
- background: none; border: none; padding: 12px 20px;
34
- font-size: 16px; font-weight: 600; color: var(--secondary-navy);
35
- cursor: pointer; border-radius: 8px 8px 0 0; transition: 0.3s;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
37
- .tab-btn.active { background: var(--primary-navy); color: white; }
38
- .view { display: none; animation: fadeIn 0.4s; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  .view.active { display: block; }
40
 
41
- /* Controls */
42
- .controls { display: flex; gap: 15px; margin-bottom: 20px; align-items: center; flex-wrap: wrap; background: #f9f9f9; padding: 15px; border-radius: 8px;}
43
- .control-group { display: flex; align-items: center; gap: 10px; }
44
- .control-group label { font-weight: bold; color: var(--primary-navy); }
45
-
46
- .btn { padding: 8px 16px; border-radius: 6px; cursor: pointer; border: none; font-weight: bold; }
47
- .btn-primary { background: var(--primary-navy); color: white; }
48
- .btn-secondary { background: #eee; color: var(--primary-navy); }
49
- select { padding: 8px; border-radius: 6px; border: 1px solid #ccc; min-width: 200px; }
50
-
51
- /* Legend */
52
- .legend-box {
53
- font-size: 13px;
54
- background: #fffbf5;
55
- border: 1px solid #eee;
56
- padding: 10px;
57
- margin-bottom: 15px;
58
- border-radius: 6px;
59
- color: #555;
60
- line-height: 1.6;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
- .legend-item { display: inline-block; margin-right: 15px; }
63
- .legend-item b { color: var(--primary-navy); }
64
 
65
- /* Table */
66
- .table-wrap { overflow-x: auto; }
67
- table { width: 100%; border-collapse: collapse; font-size: 14px; border-top: 2px solid var(--border-gold); border-bottom: 2px solid var(--border-gold); }
68
- th, td { padding: 12px 10px; text-align: center; vertical-align: middle; border-bottom: 1px solid #eee; }
 
 
 
 
 
 
 
 
69
 
70
- /* Header Styling */
71
- thead tr { border-bottom: 2px solid var(--border-gold); }
72
- th { color: #7d3561; font-weight: bold; vertical-align: bottom; }
 
 
 
 
 
73
 
74
- /* Left Alignments */
75
- th:first-child, td:first-child { text-align: left; font-weight: bold; color: var(--primary-navy); min-width: 180px; }
76
- th:nth-child(2), td:nth-child(2) { text-align: left; } /* For Family Column or WER/CER combo */
 
 
 
 
 
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  .val { white-space: nowrap; }
79
- .arrow-up { color: green; font-size: 0.9em; }
80
- .arrow-down { color: #D97706; font-size: 0.9em; }
 
 
 
 
 
81
 
82
- #loader { text-align: center; padding: 40px; font-size: 18px; color: var(--secondary-navy); }
83
- @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
 
 
84
  </style>
85
  </head>
86
  <body>
87
 
88
- <div class="container">
89
- <div class="header"><img src="https://africa.dlnlp.ai/simba/images/simbabench_header.png" alt="Simba"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
 
 
91
  <div class="card">
92
- <div id="loader">🦁 Loading Data...</div>
93
 
94
  <div id="content" style="display:none;">
 
95
  <div class="tabs">
96
- <button class="tab-btn active" onclick="setTab('asr', this)">Automatic Speech Recognition (ASR)</button>
97
- <button class="tab-btn" onclick="setTab('tts', this)">Text-to-Speech (TTS)</button>
98
- <button class="tab-btn" onclick="setTab('slid', this)">Spoken Language Identification (SLID)</button>
 
 
 
 
 
 
99
  </div>
100
 
101
  <div id="asr" class="view active">
102
- <div class="controls">
103
- <button id="btn-fam" class="btn btn-primary" onclick="setASRMode('family')">By Family</button>
104
- <button id="btn-mod" class="btn btn-secondary" onclick="setASRMode('model')">By Model</button>
 
 
105
 
106
- <div style="flex-grow:1; text-align:right;">
107
- <div class="control-group" id="grp-fam">
108
- <label for="asr-select-fam">Select Family:</label>
109
- <select id="asr-select-fam" onchange="renderASR()"></select>
110
- </div>
111
- <div class="control-group" id="grp-mod" style="display:none;">
112
- <label for="asr-select-mod">Select Model:</label>
113
- <select id="asr-select-mod" onchange="renderASR()"></select>
114
- </div>
115
  </div>
116
  </div>
117
 
118
- <h3 id="asr-title" class="section-title"></h3>
119
- <div id="asr-legend" class="legend-box" style="display:none;"></div>
120
-
121
  <div id="asr-table" class="table-wrap"></div>
122
  </div>
123
 
124
  <div id="tts" class="view">
125
- <div class="controls">
126
- <div class="control-group">
127
- <label for="tts-select">Select Model:</label>
128
  <select id="tts-select" onchange="renderTTS()"></select>
129
  </div>
130
  </div>
131
-
132
- <h3 id="tts-title" class="section-title"></h3>
133
- <div id="tts-summary" class="legend-box"></div>
134
  <div id="tts-table" class="table-wrap"></div>
135
  </div>
136
 
137
  <div id="slid" class="view">
 
138
  <div id="slid-table" class="table-wrap"></div>
139
  </div>
 
140
  </div>
141
  </div>
142
 
143
- <div class="card">
144
  <h2>Citation</h2>
145
- <p>If you use the Simba benchmark, please cite our <a href='https://africa.dlnlp.ai/sahara/' style="color:#D97706">ACL2025 paper</a>.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
  </div>
147
- <center><img src='https://africa.dlnlp.ai/sahara//img/sahara_web_sponsers.jpg' width='25%'></center>
148
  </div>
149
 
150
  <script>
151
- // --- CONSTANTS ---
152
- // Static mapping based on dataset metadata to ensure correct ISO codes
153
  const NAME_TO_ISO = {
154
- 'Afrikaans': 'afr', 'Akuapim-twi': 'Akuapim-twi', 'Amharic': 'amh', 'Asante-twi': 'Asante-twi',
155
- 'Basaa': 'bas', 'Bemba': 'bem', 'Central Atlas Tamazight': 'tzm', 'Dyula': 'dyu', 'Edo': 'bin',
156
- 'Ewe': 'ewe', 'Fanti': 'fat', 'Fon': 'fon', 'Ga': 'gaa', 'Ganda': 'lug', 'Guerze/Kpelle': 'kpe',
157
- 'Hausa': 'hau', 'Ibibio': 'ibb', 'Igbo': 'ibo', 'Kabyle': 'kab', 'Kalenjin': 'kln',
158
- 'Kinyarwanda': 'kin', 'Kisi': 'kss', 'Konyanka Maninka': 'mku', 'Lingala': 'lin', 'Lozi': 'loz',
159
- 'Lunda': 'lun', 'Luo (Kenya and Tanzania)': 'luo', 'Malagasy': 'mlg', 'Mandinka': 'mnk',
160
- 'Nigerian Pidgin': 'pcm', 'North Ndebele': 'nde', 'Northern Sotho': 'nso', 'Nyanja': 'nya',
161
- 'Oromo': 'orm', 'Pulaar': 'fuc', 'Pular': 'fuf', 'Serer': 'srr', 'Shona': 'sna', 'Somali': 'som',
162
- 'South Ndebele': 'nbl', 'Southern Sotho': 'sot', 'Standard Moroccan Tamazight': 'zgh', 'Susu': 'sus',
163
- 'Susuami': 'ssu', 'Swahili': 'swa', 'Swati': 'ssw', 'Taita': 'dav', 'Tem': 'kdh', 'Tigre': 'tig',
164
- 'Tigrinya': 'tir', 'Tiv': 'tiv', 'Tonga (Zambia)': 'toi', 'Tsonga': 'tso', 'Tswana': 'tsn',
165
- 'Twi': 'twi', 'Venda': 'ven', 'Western Maninkakan': 'mlq', 'Wolof': 'wol', 'Xhosa': 'xho',
166
- 'Yoruba': 'yor', 'Zulu': 'zul'
167
  };
168
 
169
  let DATA = null;
@@ -174,6 +396,9 @@
174
  document.getElementById('loader').style.display='none';
175
  document.getElementById('content').style.display='block';
176
  init();
 
 
 
177
  });
178
 
179
  function init() {
@@ -182,67 +407,64 @@
182
  populate('tts-select', DATA.metadata.tts_models);
183
  renderASR(); renderTTS(); renderSLID();
184
  }
 
185
  function populate(id, list) {
186
  const s = document.getElementById(id); s.innerHTML='';
187
  list.forEach(i=>{ let o=document.createElement('option'); o.value=i; o.text=i; s.add(o); });
188
  }
 
189
  function fmt(n) { return (n==null)?'N/A':n.toFixed(2); }
190
- function getIso(name) { return NAME_TO_ISO[name] || name.substring(0,3); }
191
 
192
  // --- RENDER ASR ---
193
  function renderASR() {
194
  const div = document.getElementById('asr-table');
195
- const title = document.getElementById('asr-title');
196
  const legend = document.getElementById('asr-legend');
197
- let html = '';
198
 
199
  if(asrMode === 'family'){
200
  const val = document.getElementById('asr-select-fam').value;
201
- title.innerText = `Results based on Family: ${val}`;
202
-
203
  const d = DATA.asr.by_family[val];
204
  if(!d) return;
205
 
206
- // Build Legend & Headers
207
- let legendHtml = "<b>Legend:</b> ";
208
- let headerHtml = `<th>Model</th><th>Avg WER/CER <span class="arrow-down">↓</span></th>`;
209
-
210
- d.languages.forEach(l => {
211
- const iso = getIso(l);
212
- legendHtml += `<span class="legend-item"><b>${iso}</b>: ${l}</span>`;
213
- // Normal direction (not 45 degrees)
214
- headerHtml += `<th>${iso}</th>`;
215
- });
216
-
217
  legend.style.display = 'block';
218
- legend.innerHTML = legendHtml;
 
 
 
 
 
219
 
220
- html = `<table><thead><tr>${headerHtml}</tr></thead><tbody>`;
221
  d.data.forEach(r => {
222
  html += `<tr>
223
- <td>${r.Model}</td>
224
- <td class="val"><b>${fmt(r.Avg_WER)} / ${fmt(r.Avg_CER)}</b></td>`;
225
  d.languages.forEach(l => {
226
  let w = r[`WER_${l}`], c = r[`CER_${l}`];
227
- html += `<td class="val">${(w!=null)?fmt(w)+'/'+fmt(c):'-'}</td>`;
228
  });
229
  html += `</tr>`;
230
  });
231
  } else {
232
  const val = document.getElementById('asr-select-mod').value;
233
- title.innerText = `Results based on Model: ${val}`;
234
  legend.style.display = 'none';
235
-
 
236
  html = `<table><thead><tr>
237
  <th>Language</th>
238
  <th>Family</th>
239
- <th>WER (%) <span class="arrow-down">↓</span></th>
240
- <th>CER (%) <span class="arrow-down">↓</span></th>
241
  </tr></thead><tbody>`;
242
 
243
- const rows = DATA.asr.by_model[val];
244
  rows.forEach(r => {
245
- html += `<tr><td>${r.Language}</td><td>${r.Family}</td><td class="val">${fmt(r.WER)}</td><td class="val">${fmt(r.CER)}</td></tr>`;
 
 
 
 
 
246
  });
247
  }
248
  html += `</tbody></table>`;
@@ -253,13 +475,8 @@
253
  function renderTTS() {
254
  const val = document.getElementById('tts-select').value;
255
  const rows = DATA.tts[val];
256
-
257
- document.getElementById('tts-title').innerText = `Results for Model: ${val}`;
258
-
259
  if(!rows) return;
260
 
261
- // Metrics configuration
262
- // key: json key, label: col header, higherBetter: bool
263
  const metrics = [
264
  {k:'wer', l:'WER', h:false}, {k:'mcd', l:'MCD', h:false},
265
  {k:'logf0rmse', l:'LogF0', h:false}, {k:'speech_token_distance', l:'SpTokDist', h:false},
@@ -267,33 +484,26 @@
267
  {k:'speechbleu', l:'SpBLEU', h:true}, {k:'speechbert_score', l:'SpBERT', h:true}
268
  ];
269
 
270
- // Compute Averages
271
  let sums = {}, count = 0;
272
  metrics.forEach(m => sums[m.k] = 0);
273
-
274
- rows.forEach(r => {
275
- metrics.forEach(m => sums[m.k] += (r[m.k] || 0));
276
- count++;
277
- });
278
 
279
- let summaryHtml = "<b>Average Metrics: </b>";
280
- metrics.forEach((m, idx) => {
281
- if(idx > 0) summaryHtml += " | ";
282
- summaryHtml += `${m.l}: ${fmt(sums[m.k]/count)}`;
283
- });
284
- document.getElementById('tts-summary').innerHTML = summaryHtml;
285
 
286
- // Build Table
287
  let html = `<table><thead><tr><th>Language</th>`;
288
  metrics.forEach(m => {
289
- const arrow = m.h ? '<span class="arrow-up">↑</span>' : '<span class="arrow-down">↓</span>';
290
- html += `<th>${m.l} ${arrow}</th>`;
 
291
  });
292
  html += `</tr></thead><tbody>`;
293
 
294
  rows.forEach(r => {
295
- html += `<tr><td>${r.language}</td>`;
296
- metrics.forEach(m => html += `<td class="val">${fmt(r[m.k])}</td>`);
297
  html += `</tr>`;
298
  });
299
  html += `</tbody></table>`;
@@ -304,21 +514,22 @@
304
  function renderSLID() {
305
  let html = `<table><thead><tr>
306
  <th>Language</th>
307
- <th>MMS-LID-1024 <span class="arrow-up">↑</span></th>
308
- <th>Simba-SLID <span class="arrow-up">↑</span></th>
309
  </tr></thead><tbody>`;
310
 
311
  DATA.slid.forEach(r => {
312
  let m = r['MMS-LID-1024'], s = r['Simba-SLID'];
313
  let mS = fmt(m), sS = fmt(s);
314
- if(m > s) mS = `<b>${mS}</b>`; else if(s > m) sS = `<b>${sS}</b>`;
315
- html += `<tr><td>${r.Language}</td><td class="val">${mS}</td><td class="val">${sS}</td></tr>`;
 
316
  });
317
  html += `</tbody></table>`;
318
  document.getElementById('slid-table').innerHTML = html;
319
  }
320
 
321
- // --- INTERACTIONS ---
322
  window.setTab = (id, btn) => {
323
  document.querySelectorAll('.view').forEach(e => e.classList.remove('active'));
324
  document.querySelectorAll('.tab-btn').forEach(e => e.classList.remove('active'));
@@ -328,12 +539,10 @@
328
 
329
  window.setASRMode = (m) => {
330
  asrMode = m;
331
- // Toggle Buttons
332
  document.getElementById('btn-fam').className = m==='family'?'btn btn-primary':'btn btn-secondary';
333
  document.getElementById('btn-mod').className = m==='model'?'btn btn-primary':'btn btn-secondary';
334
- // Toggle Dropdown Groups
335
- document.getElementById('grp-fam').style.display = m==='family'?'flex':'none';
336
- document.getElementById('grp-mod').style.display = m==='model'?'flex':'none';
337
  renderASR();
338
  }
339
  </script>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Simba Benchmark Leaderboard</title>
7
+ <link rel="icon" type="image/jpeg" href="https://africa.dlnlp.ai/simba/images/favicon.png">
8
+
9
+ <link rel="preconnect" href="https://fonts.googleapis.com">
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Rubik:wght@500;600;700&display=swap" rel="stylesheet">
12
+
13
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
14
+
15
  <style>
16
  :root {
17
+ /* Simba Brand Colors */
18
+ --simba-navy: #0f172a; /* Deep Slate Navy */
19
+ --simba-blue: #1e293b; /* Lighter Navy for Cards */
20
+ --simba-gold: #d97706; /* Primary Action Color */
21
+ --simba-gold-light: #f59e0b; /* Hover State */
22
+ --bg-cream: #f8fafc; /* Very Light Grey/Cream for body */
23
+ --text-main: #334155;
24
+ --text-dark: #0f172a;
25
+ --border-color: #e2e8f0;
26
+ }
27
+
28
+ body {
29
+ background-color: var(--bg-cream);
30
+ font-family: 'Inter', sans-serif;
31
+ color: var(--text-main);
32
+ margin: 0;
33
+ padding-top: 80px; /* Space for fixed navbar */
34
+ }
35
+
36
+ /* --- NAVIGATION BAR --- */
37
+ .navbar {
38
+ background-color: var(--simba-navy);
39
+ position: fixed;
40
+ top: 0;
41
+ width: 100%;
42
+ z-index: 1000;
43
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
44
+ }
45
+
46
+ .nav-container {
47
+ max-width: 1280px;
48
+ margin: 0 auto;
49
+ padding: 0 20px;
50
+ height: 70px;
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: space-between;
54
+ }
55
+
56
+ .nav-logo {
57
+ color: white;
58
+ font-family: 'Rubik', sans-serif;
59
+ font-weight: 700;
60
+ font-size: 24px;
61
+ text-decoration: none;
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 10px;
65
  }
66
 
67
+ .nav-logo img { height: 40px; border-radius: 5px; }
68
+
69
+ .nav-links { display: flex; gap: 25px; }
70
+
71
+ .nav-link {
72
+ color: #cbd5e1;
73
+ text-decoration: none;
74
+ font-weight: 500;
75
+ font-size: 15px;
76
+ transition: color 0.2s;
77
+ }
78
+
79
+ .nav-link:hover, .nav-link.active { color: var(--simba-gold); }
80
 
81
+ .nav-btn {
82
+ background-color: var(--simba-gold);
83
+ color: white !important;
84
+ padding: 8px 16px;
85
+ border-radius: 9999px; /* Pill shape */
86
+ transition: background-color 0.2s;
87
+ }
88
+ .nav-btn:hover { background-color: var(--simba-gold-light); }
89
+
90
+ /* --- HERO SECTION --- */
91
+ .hero {
92
+ text-align: center;
93
+ padding: 40px 20px;
94
+ background: white;
95
+ border-bottom: 1px solid var(--border-color);
96
+ margin-bottom: 40px;
97
+ }
98
+ .hero img { max-width: 600px; width: 90%; height: auto; }
99
+ .hero h1 {
100
+ font-family: 'Rubik', sans-serif;
101
+ color: var(--simba-navy);
102
+ margin-top: 20px;
103
+ font-size: 32px;
104
+ }
105
+
106
+ /* --- MAIN CONTAINER --- */
107
+ .container { max-width: 1280px; margin: 0 auto; padding: 0 20px 60px; }
108
+
109
+ /* --- CARDS --- */
110
+ .card {
111
+ background: white;
112
+ border-radius: 16px;
113
+ border: 1px solid var(--border-color);
114
+ padding: 30px;
115
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
116
+ margin-bottom: 30px;
117
+ }
118
+
119
+ h2 {
120
+ font-family: 'Rubik', sans-serif;
121
+ color: var(--simba-navy);
122
+ font-size: 24px;
123
+ margin-top: 0;
124
+ border-bottom: 2px solid var(--simba-gold);
125
+ display: inline-block;
126
+ padding-bottom: 8px;
127
+ margin-bottom: 20px;
128
+ }
129
+
130
+ /* --- TABS --- */
131
+ .tabs {
132
+ display: flex;
133
+ gap: 10px;
134
+ margin-bottom: 25px;
135
+ background: #f1f5f9;
136
+ padding: 5px;
137
+ border-radius: 12px;
138
+ width: fit-content;
139
  }
140
+
141
+ .tab-btn {
142
+ background: transparent;
143
+ border: none;
144
+ padding: 10px 20px;
145
+ font-family: 'Inter', sans-serif;
146
+ font-weight: 600;
147
+ color: #64748b;
148
+ cursor: pointer;
149
+ border-radius: 8px;
150
+ transition: all 0.2s ease;
151
+ }
152
+
153
+ .tab-btn:hover { color: var(--simba-navy); }
154
+
155
+ .tab-btn.active {
156
+ background-color: white;
157
+ color: var(--simba-gold);
158
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
159
+ }
160
+
161
+ .view { display: none; animation: fadeIn 0.3s; }
162
  .view.active { display: block; }
163
 
164
+ /* --- CONTROLS --- */
165
+ .controls-bar {
166
+ display: flex;
167
+ justify-content: space-between;
168
+ align-items: center;
169
+ background: #f8fafc;
170
+ padding: 15px;
171
+ border-radius: 10px;
172
+ border: 1px solid var(--border-color);
173
+ margin-bottom: 20px;
174
+ flex-wrap: wrap;
175
+ gap: 15px;
176
+ }
177
+
178
+ .btn-group { display: flex; gap: 10px; }
179
+
180
+ .btn {
181
+ padding: 8px 20px;
182
+ border-radius: 8px;
183
+ font-weight: 600;
184
+ font-size: 14px;
185
+ cursor: pointer;
186
+ border: 1px solid transparent;
187
+ transition: all 0.2s;
188
+ }
189
+
190
+ .btn-primary {
191
+ background-color: var(--simba-navy);
192
+ color: white;
193
+ }
194
+ .btn-primary:hover { background-color: #334155; }
195
+
196
+ .btn-secondary {
197
+ background-color: white;
198
+ color: var(--simba-navy);
199
+ border: 1px solid #cbd5e1;
200
  }
201
+ .btn-secondary:hover { border-color: var(--simba-navy); }
 
202
 
203
+ select {
204
+ padding: 8px 32px 8px 12px;
205
+ border-radius: 8px;
206
+ border: 1px solid #cbd5e1;
207
+ background-color: white;
208
+ font-size: 14px;
209
+ min-width: 220px;
210
+ cursor: pointer;
211
+ }
212
+
213
+ /* --- TABLES --- */
214
+ .table-wrap { overflow-x: auto; border-radius: 8px; border: 1px solid var(--border-color); }
215
 
216
+ table {
217
+ width: 100%;
218
+ border-collapse: collapse;
219
+ font-size: 14px;
220
+ background: white;
221
+ }
222
+
223
+ thead { background-color: #f8fafc; }
224
 
225
+ th {
226
+ text-align: center;
227
+ padding: 16px 12px;
228
+ font-weight: 600;
229
+ color: var(--simba-navy);
230
+ border-bottom: 2px solid #e2e8f0;
231
+ white-space: nowrap;
232
+ }
233
 
234
+ td {
235
+ padding: 12px;
236
+ border-bottom: 1px solid #e2e8f0;
237
+ text-align: center;
238
+ color: #475569;
239
+ }
240
+
241
+ tr:last-child td { border-bottom: none; }
242
+ tr:hover td { background-color: #f8fafc; }
243
+
244
+ /* Sticky Columns */
245
+ th:first-child, td:first-child {
246
+ position: sticky;
247
+ left: 0;
248
+ background-color: inherit;
249
+ z-index: 1;
250
+ text-align: left;
251
+ font-weight: 600;
252
+ color: var(--simba-navy);
253
+ border-right: 2px solid #e2e8f0;
254
+ }
255
+ thead th:first-child { z-index: 2; background-color: #f8fafc; }
256
+
257
+ /* Left Align Text */
258
+ th:nth-child(2), td:nth-child(2) { text-align: left; }
259
+
260
+ /* Metrics & Arrows */
261
+ .metric-good { color: #16a34a; font-weight: 600; } /* Green */
262
+ .metric-neutral { color: #d97706; } /* Orange */
263
  .val { white-space: nowrap; }
264
+
265
+ /* Rotated Headers Override */
266
+ .vertical-head { font-size: 12px; color: #64748b; }
267
+
268
+ /* --- FOOTER --- */
269
+ .footer { text-align: center; margin-top: 40px; color: #64748b; font-size: 14px; }
270
+ .footer a { color: var(--simba-gold); text-decoration: none; }
271
 
272
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: translateY(0); } }
273
+
274
+ /* Loading */
275
+ #loader { padding: 60px; text-align: center; font-size: 18px; color: var(--simba-navy); font-weight: 500; }
276
  </style>
277
  </head>
278
  <body>
279
 
280
+ <nav class="navbar">
281
+ <div class="nav-container">
282
+ <a href="https://africa.dlnlp.ai/simba/" class="nav-logo">
283
+ <i class="fa-solid fa-paw" style="color: var(--simba-gold);"></i>
284
+ SimbaBench
285
+ </a>
286
+ <div class="nav-links">
287
+ <a href="https://africa.dlnlp.ai/simba/" class="nav-link">Home</a>
288
+ <a href="https://arxiv.org/abs/2510.17998" class="nav-link" target="_blank">Paper</a>
289
+ <a href="https://github.com/UBC-NLP/simba" class="nav-link" target="_blank">Code</a>
290
+ <a href="https://huggingface.co/datasets/UBC-NLP/simba" class="nav-link" target="_blank">Dataset</a>
291
+ <a href="#" class="nav-link active nav-btn">Leaderboard</a>
292
+ </div>
293
+ </div>
294
+ </nav>
295
+
296
+ <div class="hero">
297
+ <img src="https://africa.dlnlp.ai/simba/images/simbabench_header.png" alt="Simba Header">
298
+ <h1>Official Benchmark Leaderboard</h1>
299
+ </div>
300
 
301
+ <div class="container">
302
+
303
  <div class="card">
304
+ <div id="loader"><i class="fa-solid fa-circle-notch fa-spin"></i> Loading Leaderboard Data...</div>
305
 
306
  <div id="content" style="display:none;">
307
+
308
  <div class="tabs">
309
+ <button class="tab-btn active" onclick="setTab('asr', this)">
310
+ <i class="fa-solid fa-microphone-lines"></i> ASR
311
+ </button>
312
+ <button class="tab-btn" onclick="setTab('tts', this)">
313
+ <i class="fa-solid fa-volume-high"></i> TTS
314
+ </button>
315
+ <button class="tab-btn" onclick="setTab('slid', this)">
316
+ <i class="fa-solid fa-language"></i> SLID
317
+ </button>
318
  </div>
319
 
320
  <div id="asr" class="view active">
321
+ <div class="controls-bar">
322
+ <div class="btn-group">
323
+ <button id="btn-fam" class="btn btn-primary" onclick="setASRMode('family')">By Language Family</button>
324
+ <button id="btn-mod" class="btn btn-secondary" onclick="setASRMode('model')">By Model</button>
325
+ </div>
326
 
327
+ <div id="grp-fam">
328
+ <span style="font-weight: 600; margin-right: 10px; color: var(--simba-navy);">Select Family:</span>
329
+ <select id="asr-select-fam" onchange="renderASR()"></select>
330
+ </div>
331
+ <div id="grp-mod" style="display:none;">
332
+ <span style="font-weight: 600; margin-right: 10px; color: var(--simba-navy);">Select Model:</span>
333
+ <select id="asr-select-mod" onchange="renderASR()"></select>
 
 
334
  </div>
335
  </div>
336
 
337
+ <div id="asr-legend" style="margin-bottom: 15px; font-size: 13px; color: #64748b; background: #f8fafc; padding: 10px; border-radius: 6px; display:none;"></div>
 
 
338
  <div id="asr-table" class="table-wrap"></div>
339
  </div>
340
 
341
  <div id="tts" class="view">
342
+ <div class="controls-bar">
343
+ <div>
344
+ <span style="font-weight: 600; margin-right: 10px; color: var(--simba-navy);">Select Model:</span>
345
  <select id="tts-select" onchange="renderTTS()"></select>
346
  </div>
347
  </div>
348
+ <div id="tts-summary" style="margin-bottom: 15px; font-weight:500; color:var(--simba-navy);"></div>
 
 
349
  <div id="tts-table" class="table-wrap"></div>
350
  </div>
351
 
352
  <div id="slid" class="view">
353
+ <h3 style="color:var(--simba-navy); font-size:18px; margin-top:0;">Spoken Language Identification</h3>
354
  <div id="slid-table" class="table-wrap"></div>
355
  </div>
356
+
357
  </div>
358
  </div>
359
 
360
+ <div class="card" style="text-align: center;">
361
  <h2>Citation</h2>
362
+ <p style="color: #64748b; line-height: 1.6;">
363
+ If you use the Simba benchmark for your scientific publication, please cite our
364
+ <a href='https://africa.dlnlp.ai/sahara/' style="color:var(--simba-gold); font-weight:bold;">ACL2025 paper</a>.
365
+ </p>
366
+ <div class="citation-block" style="background:#1e293b; color:#cbd5e1; padding:15px; border-radius:8px; text-align:left; font-family:monospace; margin-top:20px; font-size:12px; overflow-x:auto;">
367
+ @inproceedings{simba2025,
368
+ title={Simba: A Unified Benchmark for Speech Tasks in African Languages},
369
+ author={Put Authors Here},
370
+ booktitle={ACL},
371
+ year={2025}
372
+ }
373
+ </div>
374
+ </div>
375
+
376
+ <div class="footer">
377
+ <img src="https://africa.dlnlp.ai/sahara//img/sahara_web_sponsers.jpg" width="300px" style="opacity: 0.8;">
378
+ <p>&copy; 2025 Simba Benchmark Team</p>
379
  </div>
 
380
  </div>
381
 
382
  <script>
383
+ // --- DATA LOGIC ---
 
384
  const NAME_TO_ISO = {
385
+ 'Afrikaans': 'afr', 'Akuapim-twi': 'ak', 'Amharic': 'amh', 'Asante-twi': 'tw',
386
+ 'Bemba': 'bem', 'Hausa': 'hau', 'Igbo': 'ibo', 'Yoruba': 'yor', 'Zulu': 'zul',
387
+ 'Swahili': 'swa', 'Somali': 'som', 'Wolof': 'wol', 'Xhosa': 'xho'
388
+ // Add remaining ISO mappings here as needed
 
 
 
 
 
 
 
 
 
389
  };
390
 
391
  let DATA = null;
 
396
  document.getElementById('loader').style.display='none';
397
  document.getElementById('content').style.display='block';
398
  init();
399
+ }).catch(e=>{
400
+ document.getElementById('loader').innerHTML = `<span style="color:red">Error loading data. Please refresh.</span>`;
401
+ console.error(e);
402
  });
403
 
404
  function init() {
 
407
  populate('tts-select', DATA.metadata.tts_models);
408
  renderASR(); renderTTS(); renderSLID();
409
  }
410
+
411
  function populate(id, list) {
412
  const s = document.getElementById(id); s.innerHTML='';
413
  list.forEach(i=>{ let o=document.createElement('option'); o.value=i; o.text=i; s.add(o); });
414
  }
415
+
416
  function fmt(n) { return (n==null)?'N/A':n.toFixed(2); }
417
+ function getIso(name) { return NAME_TO_ISO[name] || name.substring(0,3).toLowerCase(); }
418
 
419
  // --- RENDER ASR ---
420
  function renderASR() {
421
  const div = document.getElementById('asr-table');
 
422
  const legend = document.getElementById('asr-legend');
423
+ let html='';
424
 
425
  if(asrMode === 'family'){
426
  const val = document.getElementById('asr-select-fam').value;
 
 
427
  const d = DATA.asr.by_family[val];
428
  if(!d) return;
429
 
430
+ // Legend
 
 
 
 
 
 
 
 
 
 
431
  legend.style.display = 'block';
432
+ legend.innerHTML = `<b>Languages in ${val}:</b> ` + d.languages.map(l => `<span style="margin-left:10px; color:var(--simba-navy)"><b>${getIso(l)}</b>: ${l}</span>`).join("");
433
+
434
+ // Table
435
+ html = `<table><thead><tr><th>Model</th><th>Avg WER/CER <i class="fa-solid fa-arrow-down" style="font-size:10px"></i></th>`;
436
+ d.languages.forEach(l => html += `<th>${getIso(l)}</th>`);
437
+ html += `</tr></thead><tbody>`;
438
 
 
439
  d.data.forEach(r => {
440
  html += `<tr>
441
+ <td style="font-weight:600; color:var(--simba-navy)">${r.Model}</td>
442
+ <td style="background:#f1f5f9; font-weight:bold;">${fmt(r.Avg_WER)} / ${fmt(r.Avg_CER)}</td>`;
443
  d.languages.forEach(l => {
444
  let w = r[`WER_${l}`], c = r[`CER_${l}`];
445
+ html += `<td>${(w!=null)?fmt(w)+'/'+fmt(c):'-'}</td>`;
446
  });
447
  html += `</tr>`;
448
  });
449
  } else {
450
  const val = document.getElementById('asr-select-mod').value;
 
451
  legend.style.display = 'none';
452
+ const rows = DATA.asr.by_model[val];
453
+
454
  html = `<table><thead><tr>
455
  <th>Language</th>
456
  <th>Family</th>
457
+ <th>WER (%) <i class="fa-solid fa-arrow-down" style="font-size:10px"></i></th>
458
+ <th>CER (%) <i class="fa-solid fa-arrow-down" style="font-size:10px"></i></th>
459
  </tr></thead><tbody>`;
460
 
 
461
  rows.forEach(r => {
462
+ html += `<tr>
463
+ <td style="font-weight:600;">${r.Language}</td>
464
+ <td>${r.Family}</td>
465
+ <td>${fmt(r.WER)}</td>
466
+ <td>${fmt(r.CER)}</td>
467
+ </tr>`;
468
  });
469
  }
470
  html += `</tbody></table>`;
 
475
  function renderTTS() {
476
  const val = document.getElementById('tts-select').value;
477
  const rows = DATA.tts[val];
 
 
 
478
  if(!rows) return;
479
 
 
 
480
  const metrics = [
481
  {k:'wer', l:'WER', h:false}, {k:'mcd', l:'MCD', h:false},
482
  {k:'logf0rmse', l:'LogF0', h:false}, {k:'speech_token_distance', l:'SpTokDist', h:false},
 
484
  {k:'speechbleu', l:'SpBLEU', h:true}, {k:'speechbert_score', l:'SpBERT', h:true}
485
  ];
486
 
487
+ // Averages
488
  let sums = {}, count = 0;
489
  metrics.forEach(m => sums[m.k] = 0);
490
+ rows.forEach(r => { metrics.forEach(m => sums[m.k] += (r[m.k]||0)); count++; });
 
 
 
 
491
 
492
+ let sumHtml = metrics.map(m => `<span style="margin-right:15px">${m.l}: <b>${fmt(sums[m.k]/count)}</b></span>`).join("");
493
+ document.getElementById('tts-summary').innerHTML = sumHtml;
 
 
 
 
494
 
495
+ // Table
496
  let html = `<table><thead><tr><th>Language</th>`;
497
  metrics.forEach(m => {
498
+ let icon = m.h ? 'up' : 'down';
499
+ let color = m.h ? 'green' : 'orange';
500
+ html += `<th>${m.l} <i class="fa-solid fa-arrow-${icon}" style="color:${color}; font-size:10px"></i></th>`;
501
  });
502
  html += `</tr></thead><tbody>`;
503
 
504
  rows.forEach(r => {
505
+ html += `<tr><td style="font-weight:600;">${r.language}</td>`;
506
+ metrics.forEach(m => html += `<td>${fmt(r[m.k])}</td>`);
507
  html += `</tr>`;
508
  });
509
  html += `</tbody></table>`;
 
514
  function renderSLID() {
515
  let html = `<table><thead><tr>
516
  <th>Language</th>
517
+ <th>MMS-LID-1024 <i class="fa-solid fa-arrow-up" style="color:green; font-size:10px"></i></th>
518
+ <th>Simba-SLID <i class="fa-solid fa-arrow-up" style="color:green; font-size:10px"></i></th>
519
  </tr></thead><tbody>`;
520
 
521
  DATA.slid.forEach(r => {
522
  let m = r['MMS-LID-1024'], s = r['Simba-SLID'];
523
  let mS = fmt(m), sS = fmt(s);
524
+ if(m > s) mS = `<b style="color:green">${mS}</b>`;
525
+ else if(s > m) sS = `<b style="color:green">${sS}</b>`;
526
+ html += `<tr><td style="font-weight:600;">${r.Language}</td><td>${mS}</td><td>${sS}</td></tr>`;
527
  });
528
  html += `</tbody></table>`;
529
  document.getElementById('slid-table').innerHTML = html;
530
  }
531
 
532
+ // --- INTERACTION ---
533
  window.setTab = (id, btn) => {
534
  document.querySelectorAll('.view').forEach(e => e.classList.remove('active'));
535
  document.querySelectorAll('.tab-btn').forEach(e => e.classList.remove('active'));
 
539
 
540
  window.setASRMode = (m) => {
541
  asrMode = m;
 
542
  document.getElementById('btn-fam').className = m==='family'?'btn btn-primary':'btn btn-secondary';
543
  document.getElementById('btn-mod').className = m==='model'?'btn btn-primary':'btn btn-secondary';
544
+ document.getElementById('grp-fam').style.display = m==='family'?'block':'none';
545
+ document.getElementById('grp-mod').style.display = m==='model'?'block':'none';
 
546
  renderASR();
547
  }
548
  </script>