elmadany commited on
Commit
e1c75ac
·
verified ·
1 Parent(s): 86ab48f

Update public/index.html

Browse files
Files changed (1) hide show
  1. public/index.html +156 -511
public/index.html CHANGED
@@ -4,562 +4,207 @@
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Voice of a Continent | SimbaBench 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;800&display=swap" rel="stylesheet">
12
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
13
-
14
  <style>
15
  :root {
16
- --bg-deep: #1e1b4b;
17
- --text-yellow: #fbbf24;
 
 
 
 
 
18
  --text-white: #ffffff;
 
 
 
19
  --simba-navy: #0f172a;
20
  --border-gold: #dca02a;
21
- --grad-blue: linear-gradient(135deg, #3b82f6, #0ea5e9);
22
- --grad-red: linear-gradient(135deg, #ef4444, #f43f5e);
23
- --grad-purple: linear-gradient(135deg, #6366f1, #8b5cf6);
24
- --grad-orange: linear-gradient(135deg, #f97316, #fb923c);
25
- --grad-green: linear-gradient(135deg, #22c55e, #10b981);
 
 
 
 
 
 
 
 
 
26
  }
27
 
28
  body {
29
  background-color: var(--bg-deep);
30
  font-family: 'Inter', sans-serif;
31
  color: var(--text-white);
32
- margin: 0; padding: 0;
33
  overflow-x: hidden;
 
34
  }
35
 
36
- a { text-decoration: none; transition: 0.2s; }
37
-
38
- /* --- NAVBAR --- */
39
- .navbar { padding: 20px 40px; display: flex; justify-content: space-between; align-items: center; position: relative; z-index: 100; }
40
- .nav-logo { color: white; font-family: 'Rubik', sans-serif; font-weight: 700; font-size: 22px; display: flex; align-items: center; gap: 12px; }
41
- .nav-logo img { height: 40px; }
42
- .nav-text { display: flex; flex-direction: column; line-height: 1.1; }
43
- .nav-text span:first-child { font-size: 14px; color: var(--text-yellow); }
44
- .nav-links { display: flex; gap: 25px; align-items: center; }
45
- .btn-submit { background: var(--grad-blue); color: white !important; padding: 10px 24px; border-radius: 30px; font-weight: 600; font-size: 14px; box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4); }
46
-
47
- /* --- HERO --- */
48
- .hero { max-width: 1000px; margin: 60px auto 100px; padding: 0 40px; position: relative; text-align: center; }
49
- .hero-content { z-index: 2; display: flex; flex-direction: column; align-items: center; }
50
- .conf-badge { background: white; color: black; display: inline-flex; align-items: center; gap: 10px; padding: 6px 16px; border-radius: 8px; margin-bottom: 30px; font-weight: 700; font-size: 14px; }
51
- .conf-badge i { color: #cc0000; font-size: 18px; }
52
- .hero h1 { font-family: 'Rubik', sans-serif; font-size: 64px; font-weight: 800; margin: 0; line-height: 1.1; }
53
- .hero h2 { font-family: 'Rubik', sans-serif; font-size: 32px; color: var(--text-yellow); margin: 15px 0 30px; font-weight: 700; }
54
- .hero p { color: #cbd5e1; font-size: 18px; line-height: 1.6; max-width: 700px; margin-bottom: 50px; }
55
- .hero-actions { display: flex; gap: 15px; flex-wrap: wrap; justify-content: center; }
56
- .action-btn { display: flex; align-items: center; gap: 8px; padding: 12px 24px; border-radius: 30px; color: white; font-weight: 600; font-size: 15px; transition: transform 0.2s; }
57
- .action-btn:hover { transform: translateY(-3px); color: white; }
58
- .bg-red { background: var(--grad-red); } .bg-purple { background: var(--grad-purple); }
59
-
60
- /* --- CONTENT --- */
61
- .content-container { width: 80%; max-width: 1600px; margin: 0 auto; }
62
- .main-card { background: white; border-radius: 24px; padding: 40px; color: #0f172a; min-height: 600px; position: relative; z-index: 10; margin-bottom: 60px; }
63
-
64
- /* Tabs */
65
- .tabs { display: flex; gap: 10px; border-bottom: 2px solid #e2e8f0; margin-bottom: 30px; padding-bottom: 10px; overflow-x: auto; }
66
- .tab-btn { background: none; border: none; font-size: 15px; font-weight: 600; color: #64748b; padding: 10px 20px; cursor: pointer; transition: 0.3s; border-radius: 8px; white-space: nowrap; }
67
- .tab-btn:hover { background: #f1f5f9; color: var(--bg-deep); }
68
- .tab-btn.active { background: var(--bg-deep); color: white; }
69
- .view { display: none !important; animation: fadeIn 0.4s; }
70
- .view.active { display: block !important; }
71
-
72
- /* Controls */
73
- .controls { background: #f8fafc; padding: 20px; border-radius: 12px; display: flex; gap: 20px; align-items: center; margin-bottom: 20px; flex-wrap: wrap; }
74
- select { padding: 10px; border-radius: 8px; border: 1px solid #cbd5e1; font-size: 14px; min-width: 250px; cursor:pointer; }
75
- .rank-info { font-size: 13px; color: #64748b; margin-top: 5px; font-style: italic; }
76
- .score-desc { font-size: 14px; color: #475569; background: #fff7ed; border-left: 4px solid #f97316; padding: 10px 15px; margin-bottom: 20px; border-radius: 4px; }
77
-
78
- /* ASR Buttons */
79
- .mode-btn { padding: 8px 20px; border-radius: 8px; font-weight: 600; font-size: 13px; cursor: pointer; transition: all 0.2s; border: 1px solid #e2e8f0; background: white; color: var(--simba-navy); }
80
- .mode-btn:hover { border-color: var(--text-yellow); color: var(--text-yellow); }
81
- .mode-btn.active { background-color: var(--simba-navy); color: white; border-color: var(--simba-navy); box-shadow: 0 4px 12px rgba(15, 23, 42, 0.15); }
82
-
83
- /* --- FANCY SUMMARY CARDS --- */
84
- .summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 25px; margin-bottom: 50px; }
85
-
86
- .fancy-card {
87
- background: white; border-radius: 16px; padding: 25px;
88
- display: flex; align-items: center; gap: 20px;
89
- box-shadow: 0 10px 25px -5px rgba(0,0,0,0.08); border: 1px solid #f1f5f9;
90
- transition: transform 0.3s ease, box-shadow 0.3s ease;
91
- }
92
- .fancy-card:hover { transform: translateY(-5px); box-shadow: 0 20px 30px -10px rgba(0,0,0,0.12); border-color: #e2e8f0; }
93
-
94
- .card-icon {
95
- width: 60px; height: 60px; border-radius: 14px;
96
- display: flex; align-items: center; justify-content: center;
97
- font-size: 26px; color: white; flex-shrink: 0;
98
- box-shadow: 0 8px 15px -3px rgba(0,0,0,0.2);
99
  }
100
- .icon-asr { background: var(--grad-blue); }
101
- .icon-tts { background: var(--grad-orange); }
102
- .icon-slid { background: var(--grad-green); }
103
-
104
- .card-content { flex: 1; }
105
- .card-title { font-size: 11px; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 5px; }
106
- .card-model { font-size: 18px; font-weight: 800; color: #0f172a; margin-bottom: 4px; line-height: 1.3; }
107
- .card-score { font-size: 14px; font-weight: 600; color: #475569; }
108
- .card-score b { color: #0f172a; }
109
-
110
- /* Table */
111
- .table-wrap { overflow-x: auto; border: 1px solid #e2e8f0; border-radius: 12px; margin-bottom: 30px; }
112
- table { width: 100%; border-collapse: collapse; font-size: 14px; }
113
- th { background: #f1f5f9; color: #0f172a; font-weight: 700; padding: 16px; text-align: center; border-bottom: 2px solid #e2e8f0; white-space: nowrap; vertical-align: bottom; }
114
- td { padding: 14px; border-bottom: 1px solid #e2e8f0; text-align: center; color: #334155; }
115
- tr:hover td { background: #f8fafc; }
116
- th:first-child, td:first-child { position: sticky; left: 0; background: white; z-index: 2; text-align: left; font-weight: 700; color: #0f172a; border-right: 2px solid #f1f5f9; min-width: 220px; }
117
- thead th:first-child { background: #f1f5f9; z-index: 3; }
118
- th:nth-child(2), td:nth-child(2) { text-align: left; }
119
- h4 { color: var(--text-yellow); font-family: 'Rubik', sans-serif; font-size: 18px; margin: 0 0 15px 0; border-bottom: 1px solid #eee; padding-bottom: 10px; }
120
-
121
- /* Citations */
122
- .citation-section { background: #0f172a; border: 1px solid #334155; border-radius: 16px; padding: 40px; box-sizing: border-box; box-shadow: 0 20px 40px rgba(0,0,0,0.3); position: relative; margin-bottom: 60px; }
123
- .citation-section h3 { color: var(--text-yellow); font-family: 'Rubik', sans-serif; font-size: 24px; margin-top: 0; }
124
- .citation-box { background: #1e293b; color: #cbd5e1; padding: 20px; border-radius: 12px; font-family: monospace; white-space: pre-wrap; margin-top: 20px; overflow-x: auto; border: 1px solid #334155; font-size: 13px; line-height: 1.5; }
125
- .copy-btn { position: absolute; top: 40px; right: 40px; background: var(--text-yellow); border: none; padding: 8px 16px; border-radius: 6px; font-weight: bold; cursor: pointer; color: #0f172a; }
126
-
127
- .footer { text-align: center; padding: 40px; color: #94a3b8; font-size: 14px; }
128
- @keyframes fadeIn { from{opacity:0; transform:translateY(10px)} to{opacity:1; transform:translateY(0)} }
129
-
130
- .arrow-down { color: #d97706; font-size: 10px; }
131
- .arrow-up { color: #16a34a; font-size: 10px; }
132
- .empty-msg { color: #64748b; font-style: italic; padding: 20px; text-align: center; }
133
- </style>
134
- </head>
135
- <body>
136
-
137
- <nav class="navbar layout-width">
138
- <a href="https://africa.dlnlp.ai/simba" class="nav-logo">
139
- <img src="https://africa.dlnlp.ai/simba/images/simba_main_logo.png" alt="Logo">
140
- <div class="nav-text"><span>Voice of a</span> Continent</div>
141
- </a>
142
- <div class="nav-links">
143
- <!-- <a href="https://aclanthology.org/2025.emnlp-main.559" target="_blank" class="nav-link">Paper</a>
144
- <a href="https://africa.dlnlp.ai/simba/" target="_blank" class="btn-submit">Submit New Results</a> -->
145
- </div>
146
- </nav>
147
-
148
- <div class="hero layout-width">
149
- <div class="hero-content">
150
- <div class="conf-badge"><i class="fa-solid fa-location-dot"></i> EMNLP 2025 · Suzhou, China</div>
151
- <h1>SimbaBench Leaderboard</h1>
152
- <h2>Mapping Africa’s Speech Technology</h2>
153
- <p>SimbaBench bridges the digital divide with a unified suite for African AI: the largest open-source speech benchmark covering 61 languages.</p>
154
- <div class="hero-actions">
155
- <a href="https://aclanthology.org/2025.emnlp-main.559" target="_blank" class="action-btn bg-red"><i class="fa-regular fa-file-pdf"></i> Read Paper</a>
156
- <a href="https://africa.dlnlp.ai/simba" target="_blank" class="action-btn bg-indigo"><i class="fa-solid fa-globe"></i> Official Website</a>
157
- <a href="https://huggingface.co/collections/UBC-NLP/simba-speech-series" target="_blank" class="action-btn bg-orange"><i class="fa-solid fa-robot"></i> Simba Model Series</a>
158
- <a href="https://github.com/UBC-NLP/simba" target="_blank" class="action-btn bg-gray"><i class="fa-brands fa-github"></i> GitHub</a>
159
-
160
- </div>
161
- </div>
162
- </div>
163
-
164
- <div class="content-container layout-width">
165
- <div class="main-card" id="board">
166
- <div id="loader" style="text-align:center; padding:60px; color:#64748b;">
167
- <i class="fa-solid fa-circle-notch fa-spin fa-3x"></i><br><br>Loading Leaderboard Data...
168
- </div>
169
-
170
- <div id="app-content" style="display:none;">
171
- <div class="tabs">
172
- <button class="tab-btn active" id="tab-btn-asr" onclick="setTab('asr')">Automatic Speech Recognition (ASR)</button>
173
- <button class="tab-btn" id="tab-btn-tts" onclick="setTab('tts')">Text-to-Speech (TTS)</button>
174
- <button class="tab-btn" id="tab-btn-slid" onclick="setTab('slid')">Spoken Language Identification (SLID)</button>
175
- <button class="tab-btn" id="tab-btn-lang" onclick="setTab('lang')">Language Analysis</button>
176
- </div>
177
-
178
- <div id="asr" class="view active">
179
- <div class="controls">
180
- <span style="font-weight:700;">View Mode:</span>
181
- <button id="btn-over" class="mode-btn active" onclick="setASRMode('overview')">Overview</button>
182
- <button id="btn-fam" class="mode-btn" onclick="setASRMode('family')">By Family</button>
183
- <button id="btn-mod" class="mode-btn" onclick="setASRMode('model')">By Model</button>
184
-
185
- <div style="flex-grow:1; text-align:right;">
186
- <div id="grp-fam" style="display:none;"><label>Select Family: </label><select id="asr-select-fam" onchange="renderASR()"></select></div>
187
- <div id="grp-mod" style="display:none;"><label>Select Model: </label><select id="asr-select-mod" onchange="renderASR()"></select></div>
188
- </div>
189
- </div>
190
-
191
- <div style="display:flex; justify-content:space-between; align-items:end; margin-bottom:10px;">
192
- <h3 id="asr-title" style="color:#d97706; margin:0;">Results Overview</h3>
193
- <div id="asr-rank-info" class="rank-info">Ranking: WER (↓) then CER (↓)</div>
194
- </div>
195
- <div id="asr-desc"></div>
196
- <div id="asr-table" class="table-wrap"></div>
197
- </div>
198
-
199
- <div id="tts" class="view">
200
- <div class="controls">
201
- <span style="font-weight:600;">Select Model:</span>
202
- <select id="tts-select" onchange="renderTTS()"></select>
203
- </div>
204
- <h3 id="tts-title" style="color:#d97706; margin-bottom:10px;"></h3>
205
- <div id="tts-summary" style="margin-bottom:20px; font-weight:600; color:#0f172a;"></div>
206
- <div id="tts-table" class="table-wrap"></div>
207
- </div>
208
-
209
- <div id="slid" class="view">
210
- <div style="display:flex; justify-content:space-between; align-items:end; margin-bottom:15px;">
211
- <h3 style="color:#d97706; margin:0;">Spoken Language Identification</h3>
212
- <div class="rank-info">Ranking: F1-Macro (↑)</div>
213
- </div>
214
- <div id="slid-table" class="table-wrap"></div>
215
- </div>
216
-
217
- <div id="lang" class="view">
218
- <div class="controls">
219
- <span style="font-weight:600;">Select Language:</span>
220
- <select id="lang-select" onchange="renderLanguageView()"></select>
221
- </div>
222
-
223
- <div id="lang-summary" class="summary-grid"></div>
224
-
225
- <h4>Automatic Speech Recognition (ASR) <span class="rank-info" style="font-weight:normal;">(Ranked by WER ↓, then CER ↓)</span></h4>
226
- <div id="lang-asr-table" class="table-wrap"></div>
227
-
228
- <h4>Text-to-Speech (TTS) Results</h4>
229
- <div id="lang-tts-table" class="table-wrap"></div>
230
-
231
- <h4>Spoken Language Identification (SLID) Results <span class="rank-info" style="font-weight:normal;">(Ranked by Score ↑)</span></h4>
232
- <div id="lang-slid-table" class="table-wrap"></div>
233
- </div>
234
- </div>
235
- </div>
236
-
237
- <div class="citation-section layout-width" id="citation">
238
- <h3>Citation</h3>
239
- <button class="copy-btn" onclick="copyCitation()"><i class="fa-regular fa-copy"></i> Copy</button>
240
- <p style="color:#94a3b8; margin-bottom:20px;">If you use the Simba benchmark, please cite our paper:</p>
241
- <div class="citation-box" id="bibtex">@inproceedings{elmadany-etal-2025-voice,
242
- title = "Voice of a Continent: Mapping {A}frica{'}s Speech Technology Frontier",
243
- author = "Elmadany, AbdelRahim A. and Kwon, Sang Yun and Toyin, Hawau Olamide and Alcoba Inciarte, Alcides and Aldarmaki, Hanan and Abdul-Mageed, Muhammad",
244
- editor = "Christodoulopoulos, Christos and Chakraborty, Tanmoy and Rose, Carolyn and Peng, Violet",
245
- booktitle = "Proceedings of the 2025 Conference on Empirical Methods in Natural Language Processing",
246
- month = nov,
247
- year = "2025",
248
- address = "Suzhou, China",
249
- publisher = "Association for Computational Linguistics",
250
- url = "https://aclanthology.org/2025.emnlp-main.559/",
251
- doi = "10.18653/v1/2025.emnlp-main.559",
252
- pages = "11039--11061",
253
- ISBN = "979-8-89176-332-6",
254
- }</div>
255
- </div>
256
- </div>
257
 
258
- <div class="footer">
259
- <img src="https://africa.dlnlp.ai/sahara//img/sahara_web_sponsers.jpg" width="250" style="opacity:0.8; margin-bottom:15px;">
260
- <br>&copy; 2025 Simba Benchmark.
261
- </div>
262
-
263
- <script>
264
- const NAME_TO_ISO = {'Afrikaans':'afr', 'Akuapim-twi':'ak', 'Amharic':'amh', 'Asante-twi':'tw', 'Bemba':'bem', 'Hausa':'hau', 'Igbo':'ibo', 'Yoruba':'yor', 'Zulu':'zul', 'Swahili':'swa', 'Somali':'som', 'Wolof':'wol', 'Xhosa':'xho'};
265
- let DATA = null;
266
- let asrMode = 'overview';
267
-
268
- fetch('/api/data').then(r=>r.json()).then(d=>{
269
- DATA = d;
270
- document.getElementById('loader').style.display='none';
271
- document.getElementById('app-content').style.display='block';
272
- init();
273
- });
274
-
275
- function init() {
276
- populate('asr-select-fam', DATA.metadata.families);
277
- populate('asr-select-mod', DATA.metadata.models);
278
- populate('tts-select', DATA.metadata.tts_models);
279
-
280
- const allLangs = new Set();
281
- // Collect languages from all sources to be thorough
282
- Object.values(DATA.asr.by_model).forEach(rows => rows.forEach(r => { if(r.Language) allLangs.add(r.Language); }));
283
- Object.values(DATA.tts).forEach(rows => rows.forEach(r => { const l = r.Language || r.language; if(l) allLangs.add(l); }));
284
- if(DATA.slid) DATA.slid.forEach(r => { if(r.Language) allLangs.add(r.Language); });
285
-
286
- populate('lang-select', Array.from(allLangs).sort());
287
-
288
- renderASR(); renderTTS(); renderSLID();
289
  }
290
 
291
- function populate(id, list) {
292
- const s = document.getElementById(id); s.innerHTML='';
293
- list.forEach(i=>{ let o=document.createElement('option'); o.value=i; o.text=i; s.add(o); });
294
- }
295
- function fmt(n) { return (n==null)?'N/A':n.toFixed(2); }
296
- function getIso(name, dataIso) {
297
- let iso = dataIso || NAME_TO_ISO[name] || name.substring(0,3).toLowerCase();
298
- return `${name} (${iso})`;
299
  }
300
 
301
- // --- ASR ---
302
- function renderASR() {
303
- const div = document.getElementById('asr-table');
304
- const title = document.getElementById('asr-title');
305
- const desc = document.getElementById('asr-desc');
306
- let html='';
307
-
308
- if (asrMode === 'overview') {
309
- title.innerText = "Results Overview (All Models)";
310
- desc.innerHTML = `<p class="score-desc">The <b>Simba ASR Score</b> is the global average of WER and CER across all languages in the benchmark.</p>`;
311
- document.getElementById('grp-fam').style.display='none';
312
- document.getElementById('grp-mod').style.display='none';
313
-
314
- const modelStats = [];
315
- Object.keys(DATA.asr.by_model).forEach(modName => {
316
- const rows = DATA.asr.by_model[modName];
317
- let sW=0, sC=0, n=0;
318
- rows.forEach(r => { sW+=r.WER; sC+=r.CER; n++; });
319
- if(n>0) modelStats.push({ name: modName, wer: sW/n, cer: sC/n });
320
- });
321
-
322
- modelStats.sort((a,b) => (a.wer - b.wer) || (a.cer - b.cer));
323
- html = `<table><thead><tr><th>Model</th><th>Simba ASR Score (WER/CER) <i class="fa-solid fa-arrow-down arrow-down"></i></th></tr></thead><tbody>`;
324
-
325
- let currentRank = 1;
326
- modelStats.forEach((m, i) => {
327
- if (i > 0 && Math.abs(m.wer - modelStats[i-1].wer) > 0.001) currentRank = i + 1; else currentRank = 1;
328
- let icon = (currentRank===1)?'🥇 ':(currentRank===2)?'🥈 ':(currentRank===3)?'🥉 ':'';
329
- html += `<tr><td style="font-weight:600; color:var(--simba-navy)">${icon}${m.name}</td><td><b>${fmt(m.wer)} / ${fmt(m.cer)}</b></td></tr>`;
330
- });
331
-
332
- } else if(asrMode==='family'){
333
- const val = document.getElementById('asr-select-fam').value;
334
- title.innerText = `Results for Family: ${val}`;
335
- desc.innerHTML = `<p class="score-desc">The <b>Family Score</b> is the average WER and CER calculated across all languages within the <b>${val}</b> family.</p>`;
336
- document.getElementById('grp-fam').style.display='inline-block';
337
- document.getElementById('grp-mod').style.display='none';
338
-
339
- const d = DATA.asr.by_family[val];
340
- if(!d) return;
341
- d.data.sort((a,b) => a.Avg_WER - b.Avg_WER);
342
-
343
- html = `<table><thead><tr><th>Model</th><th>Simba ASR Family Score <i class="fa-solid fa-arrow-down arrow-down"></i></th>`;
344
- d.languages.forEach(l => html += `<th>${getIso(l.name, l.iso)}</th>`);
345
- html += `</tr></thead><tbody>`;
346
-
347
- let currentRank = 1;
348
- d.data.forEach((r, idx) => {
349
- if(idx > 0 && Math.abs(r.Avg_WER - d.data[idx-1].Avg_WER) > 0.001) currentRank = idx + 1; else currentRank = 1;
350
- let icon = (currentRank===1)?'🥇 ':(currentRank===2)?'🥈 ':(currentRank===3)?'🥉 ':'';
351
- html += `<tr><td style="font-weight:600; color:var(--simba-navy)">${icon}${r.Model}</td><td style="font-weight:bold; background:#f8fafc">${fmt(r.Avg_WER)} / ${fmt(r.Avg_CER)}</td>`;
352
- d.languages.forEach(l => {
353
- let w=r[`WER_${l.name}`], c=r[`CER_${l.name}`];
354
- html += `<td>${(w!=null)?fmt(w)+'/'+fmt(c):'-'}</td>`;
355
- });
356
- html += `</tr>`;
357
- });
358
- } else {
359
- const val = document.getElementById('asr-select-mod').value;
360
- title.innerText = `Results for Model: ${val}`;
361
- desc.innerHTML = "";
362
- document.getElementById('grp-fam').style.display='none';
363
- document.getElementById('grp-mod').style.display='inline-block';
364
-
365
- const rows = DATA.asr.by_model[val];
366
- html = `<table><thead><tr><th>Language</th><th>Family</th><th>WER <i class="fa-solid fa-arrow-down arrow-down"></i></th><th>CER <i class="fa-solid fa-arrow-down arrow-down"></i></th></tr></thead><tbody>`;
367
- rows.forEach(r => {
368
- html += `<tr><td>${getIso(r.Language, r.ISO)}</td><td>${r.Family}</td><td>${fmt(r.WER)}</td><td>${fmt(r.CER)}</td></tr>`;
369
- });
370
- }
371
- div.innerHTML = html;
372
  }
373
 
374
- // --- TTS ---
375
- function renderTTS() {
376
- const val = document.getElementById('tts-select').value;
377
- document.getElementById('tts-title').innerText = `Model: ${val}`;
378
- const rows = DATA.tts[val];
379
- if(!rows) return;
380
-
381
- const metrics = [
382
- {k:'wer', l:'WER(↓)', h:false}, {k:'mcd', l:'MCD(↓)', h:false},
383
- {k:'logf0rmse', l:'LogF0RMSE(↓)', h:false}, {k:'speech_token_distance', l:'SpeechTokenDistance(↓)', h:false},
384
- {k:'pesq', l:'PESQ(↑)', h:true}, {k:'utmos', l:'UTMOS(↑)', h:true},
385
- {k:'speechbleu', l:'SpeechBLEU(↑)', h:true}, {k:'speechbert_score', l:'SpeechBERTScore(↑)', h:true}
386
- ];
387
-
388
- let sums={}, c=0;
389
- metrics.forEach(m=>sums[m.k]=0);
390
- rows.forEach(r=>{ metrics.forEach(m=>sums[m.k]+=(r[m.k]||0)); c++; });
391
- document.getElementById('tts-summary').innerHTML = "<b>Averages: </b>" + metrics.map(m=> `${m.l.replace('(↓)','').replace('(↑)','')}: ${fmt(sums[m.k]/c)}`).join(" | ");
392
 
393
- let html = `<table><thead><tr><th>Language</th>`;
394
- metrics.forEach(m => html += `<th>${m.l}</th>`);
395
- html += `</tr></thead><tbody>`;
396
- rows.forEach(r => {
397
- html += `<tr><td>${getIso(r.language, r.iso)}</td>`;
398
- metrics.forEach(m => html += `<td>${fmt(r[m.k])}</td>`);
399
- html += `</tr>`;
400
- });
401
- document.getElementById('tts-table').innerHTML = html;
402
  }
403
 
404
- // --- SLID ---
405
- function renderSLID() {
406
- let html = `<table><thead><tr><th>Language</th><th>MMS-LID-1024 (↑)</th><th>Simba-SLID (↑)</th></tr></thead><tbody>`;
407
- DATA.slid.forEach(r => {
408
- let m = r['MMS-LID-1024'], s = r['Simba-SLID'];
409
- let mS = fmt(m), sS = fmt(s);
410
- if(m > s) mS = `<b>${mS} 🥇</b>`; else if(s > m) sS = `<b>${sS} 🥇</b>`;
411
- html += `<tr><td>${getIso(r.Language)}</td><td>${mS}</td><td>${sS}</td></tr>`;
412
- });
413
- document.getElementById('slid-table').innerHTML = html;
414
  }
415
 
416
- // --- LANGUAGE VIEW ---
417
- function renderLanguageView() {
418
- const lang = document.getElementById('lang-select').value;
419
-
420
- // 1. ASR Data
421
- let asrRows = [];
422
- Object.keys(DATA.asr.by_model).forEach(modName => {
423
- const row = DATA.asr.by_model[modName].find(r => r.Language === lang);
424
- if(row) asrRows.push({model: modName, wer: row.WER, cer: row.CER});
425
- });
426
- asrRows.sort((a,b) => (a.wer - b.wer) || (a.cer - b.cer));
427
-
428
- // 2. TTS Data
429
- let ttsRows = [];
430
- Object.keys(DATA.tts).forEach(mod => {
431
- const row = DATA.tts[mod].find(r => (r.Language || r.language) === lang);
432
- if(row) ttsRows.push({model: mod, ...row});
433
- });
434
 
435
- // 3. SLID Data
436
- let slidRows = [];
437
- const slidRow = DATA.slid.find(r => r.Language === lang) ||
438
- DATA.slid.find(r => r.Language.startsWith(lang + " (")) ||
439
- DATA.slid.find(r => r.Language.includes(lang));
440
- if(slidRow) {
441
- const models = Object.keys(slidRow).filter(k => k !== 'Language' && k !== 'ISO');
442
- models.forEach(m => slidRows.push({model: m, val: slidRow[m]}));
443
- slidRows.sort((a,b) => b.val - a.val); // Descending
444
- }
445
 
446
- // --- SUMMARY CARDS ---
447
- let summaryHTML = "";
448
-
449
- // ASR Winner
450
- if(asrRows.length > 0) {
451
- summaryHTML += `<div class="fancy-card">
452
- <div class="card-icon icon-asr"><i class="fa-solid fa-microphone-lines"></i></div>
453
- <div class="card-content">
454
- <div class="card-title">Best ASR Model</div>
455
- <div class="card-model">${asrRows[0].model}</div>
456
- <div class="card-score">WER: <b>${fmt(asrRows[0].wer)}%</b></div>
457
- </div>
458
- </div>`;
459
- } else summaryHTML += `<div class="fancy-card"><div class="card-icon icon-asr"><i class="fa-solid fa-microphone-slash"></i></div><div class="card-content"><div class="card-title">ASR</div><div class="card-model">No Data</div></div></div>`;
460
 
461
- // TTS Winner
462
- if(ttsRows.length > 0) {
463
- const bestTTS = [...ttsRows].sort((a,b) => a.wer - b.wer)[0];
464
- summaryHTML += `<div class="fancy-card">
465
- <div class="card-icon icon-tts"><i class="fa-solid fa-volume-high"></i></div>
466
- <div class="card-content">
467
- <div class="card-title">Best TTS (Intelligibility)</div>
468
- <div class="card-model">${bestTTS.model}</div>
469
- <div class="card-score">WER: <b>${fmt(bestTTS.wer)}%</b></div>
470
- </div>
471
- </div>`;
472
- } else summaryHTML += `<div class="fancy-card"><div class="card-icon icon-tts"><i class="fa-solid fa-volume-xmark"></i></div><div class="card-content"><div class="card-title">TTS</div><div class="card-model">No Data</div></div></div>`;
 
 
473
 
474
- // SLID Winner
475
- if(slidRows.length > 0) {
476
- summaryHTML += `<div class="fancy-card">
477
- <div class="card-icon icon-slid"><i class="fa-solid fa-language"></i></div>
478
- <div class="card-content">
479
- <div class="card-title">Best SLID Model</div>
480
- <div class="card-model">${slidRows[0].model}</div>
481
- <div class="card-score">F1 Score: <b>${fmt(slidRows[0].val)}%</b></div>
482
- </div>
483
- </div>`;
484
- } else summaryHTML += `<div class="fancy-card"><div class="card-icon icon-slid"><i class="fa-solid fa-circle-question"></i></div><div class="card-content"><div class="card-title">SLID</div><div class="card-model">No Data</div></div></div>`;
485
 
486
- document.getElementById('lang-summary').innerHTML = summaryHTML;
 
 
487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
 
489
- // --- TABLES ---
490
- // ASR Table
491
- let h1 = `<table><thead><tr><th>Model</th><th>WER <i class="fa-solid fa-arrow-down arrow-down"></i></th><th>CER <i class="fa-solid fa-arrow-down arrow-down"></i></th></tr></thead><tbody>`;
492
- if(asrRows.length === 0) h1 += `<tr><td colspan="3" class="empty-msg">No ASR results available for ${lang}.</td></tr>`;
493
- else {
494
- let currentRank = 1;
495
- asrRows.forEach((r, i) => {
496
- if (i > 0 && Math.abs(r.wer - asrRows[i-1].wer) > 0.001) currentRank = i + 1; else currentRank = 1;
497
- let icon = (currentRank===1)?'🥇 ':(currentRank===2)?'🥈 ':(currentRank===3)?'🥉 ':'';
498
- h1 += `<tr><td style="font-weight:600; color:var(--simba-navy)">${icon}${r.model}</td><td>${fmt(r.wer)}</td><td>${fmt(r.cer)}</td></tr>`;
499
- });
500
  }
501
- h1 += `</tbody></table>`;
502
- document.getElementById('lang-asr-table').innerHTML = h1;
503
 
504
- // TTS Table
505
- let h2 = `<table><thead><tr><th>Model</th>
506
- <th>WER(↓)</th><th>MCD(↓)</th><th>LogF0RMSE(↓)</th><th>SpeechTokenDistance(↓)</th>
507
- <th>PESQ(↑)</th><th>UTMOS(↑)</th><th>SpeechBLEU(↑)</th><th>SpeechBERTScore(↑)</th>
508
- </tr></thead><tbody>`;
509
- if(ttsRows.length === 0) h2 += `<tr><td colspan="9" class="empty-msg">No TTS results available for ${lang}.</td></tr>`;
510
- else {
511
- ttsRows.forEach(row => {
512
- h2 += `<tr>
513
- <td style="font-weight:600;">${row.model}</td>
514
- <td>${fmt(row.wer)}</td><td>${fmt(row.mcd)}</td>
515
- <td>${fmt(row.logf0rmse)}</td><td>${fmt(row.speech_token_distance)}</td>
516
- <td>${fmt(row.pesq)}</td><td>${fmt(row.utmos)}</td>
517
- <td>${fmt(row.speechbleu)}</td><td>${fmt(row.speechbert_score)}</td>
518
- </tr>`;
519
- });
520
  }
521
- h2 += `</tbody></table>`;
522
- document.getElementById('lang-tts-table').innerHTML = h2;
523
 
524
- // SLID Table
525
- let h3 = `<table><thead><tr><th>Model</th><th>F1-Score <i class="fa-solid fa-arrow-up arrow-up"></i></th></tr></thead><tbody>`;
526
- if(slidRows.length === 0) h3 += `<tr><td colspan="2" class="empty-msg">No SLID results available for ${lang}.</td></tr>`;
527
- else {
528
- let currentRank = 1;
529
- slidRows.forEach((sc, i) => {
530
- if (i > 0 && Math.abs(sc.val - slidRows[i-1].val) > 0.001) currentRank = i + 1; else currentRank = 1;
531
- let icon = (currentRank===1)?'🥇 ':(currentRank===2)?'🥈 ':(currentRank===3)?'🥉 ':'';
532
- h3 += `<tr><td style="font-weight:600;">${icon}${sc.model}</td><td>${fmt(sc.val)}</td></tr>`;
533
- });
534
  }
535
- h3 += `</tbody></table>`;
536
- document.getElementById('lang-slid-table').innerHTML = h3;
537
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
 
539
- // --- UI ---
540
- window.setTab = (id, btn) => {
541
- document.querySelectorAll('.view').forEach(e => e.classList.remove('active'));
542
- document.querySelectorAll('.tab-btn').forEach(e => e.classList.remove('active'));
543
- document.getElementById(id).classList.add('active');
544
- if(btn) btn.classList.add('active'); else document.getElementById(`tab-btn-${id}`).classList.add('active');
545
- if(id === 'lang') renderLanguageView();
546
- };
547
-
548
- window.setASRMode = (m) => {
549
- asrMode = m;
550
- ['btn-over','btn-fam','btn-mod'].forEach(b => document.getElementById(b).classList.remove('active'));
551
- document.getElementById(m==='overview'?'btn-over':(m==='family'?'btn-fam':'btn-mod')).classList.add('active');
552
- renderASR();
553
- }
554
 
555
- window.copyCitation = () => {
556
- const text = document.getElementById('bibtex').innerText;
557
- navigator.clipboard.writeText(text).then(() => {
558
- const btn = document.querySelector('.copy-btn');
559
- btn.innerHTML = '<i class="fa-solid fa-check"></i> Copied!';
560
- setTimeout(() => btn.innerHTML = '<i class="fa-regular fa-copy"></i> Copy', 2000);
561
- });
562
- }
563
  </script>
564
  </body>
565
  </html>
 
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
  <title>Voice of a Continent | SimbaBench Leaderboard</title>
7
+ <link rel="icon" type="image/png" href="https://africa.dlnlp.ai/simba/images/favicon.png">
 
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Outfit:wght@600;700;800&display=swap" rel="stylesheet">
11
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
 
12
  <style>
13
  :root {
14
+ /* Background colors */
15
+ --bg-deep: #1e1b4b;
16
+ --bg-darker: #0f172a;
17
+ --bg-card: rgba(255, 255, 255, 0.05);
18
+
19
+ /* Text colors */
20
+ --text-yellow: #fbbf24;
21
  --text-white: #ffffff;
22
+ --text-gray: #94a3b8;
23
+
24
+ /* Brand colors */
25
  --simba-navy: #0f172a;
26
  --border-gold: #dca02a;
27
+
28
+ /* Button gradients - matching the hero buttons */
29
+ --grad-red: linear-gradient(135deg, #ef4444, #dc2626);
30
+ --grad-indigo: linear-gradient(135deg, #6366f1, #4f46e5);
31
+ --grad-orange: linear-gradient(135deg, #f97316, #ea580c);
32
+ --grad-blue: linear-gradient(135deg, #3b82f6, #2563eb);
33
+ --grad-green: linear-gradient(135deg, #22c55e, #16a34a);
34
+ --grad-dark: linear-gradient(135deg, #374151, #1f2937);
35
+ }
36
+
37
+ * {
38
+ margin: 0;
39
+ padding: 0;
40
+ box-sizing: border-box;
41
  }
42
 
43
  body {
44
  background-color: var(--bg-deep);
45
  font-family: 'Inter', sans-serif;
46
  color: var(--text-white);
 
47
  overflow-x: hidden;
48
+ line-height: 1.6;
49
  }
50
 
51
+ h1, h2, h3 {
52
+ font-family: 'Outfit', sans-serif;
53
+ font-weight: 700;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
+ a {
57
+ text-decoration: none;
58
+ transition: all 0.3s ease;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
 
61
+ /* Header Section */
62
+ .header {
63
+ text-align: center;
64
+ padding: 60px 20px 40px;
65
+ background: linear-gradient(180deg, var(--bg-darker) 0%, var(--bg-deep) 100%);
66
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
 
 
67
  }
68
 
69
+ .logo {
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ gap: 15px;
74
+ margin-bottom: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
 
77
+ .logo img {
78
+ width: 60px;
79
+ height: 60px;
80
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
+ .logo-text {
83
+ text-align: left;
 
 
 
 
 
 
 
84
  }
85
 
86
+ .logo-text h1 {
87
+ font-size: 2rem;
88
+ font-weight: 800;
89
+ line-height: 1.2;
 
 
 
 
 
 
90
  }
91
 
92
+ .logo-text .highlight {
93
+ color: var(--text-yellow);
94
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
+ .subtitle {
97
+ font-size: 1.1rem;
98
+ color: var(--text-gray);
99
+ margin-bottom: 30px;
100
+ max-width: 800px;
101
+ margin-left: auto;
102
+ margin-right: auto;
103
+ }
 
 
104
 
105
+ /* Action Buttons */
106
+ .action-buttons {
107
+ display: flex;
108
+ flex-wrap: wrap;
109
+ gap: 15px;
110
+ justify-content: center;
111
+ margin-top: 30px;
112
+ }
 
 
 
 
 
 
113
 
114
+ .action-btn {
115
+ padding: 14px 28px;
116
+ border-radius: 50px;
117
+ color: white;
118
+ font-weight: 600;
119
+ font-size: 0.95rem;
120
+ display: inline-flex;
121
+ align-items: center;
122
+ gap: 10px;
123
+ transition: all 0.3s ease;
124
+ border: none;
125
+ cursor: pointer;
126
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
127
+ }
128
 
129
+ .action-btn:hover {
130
+ transform: translateY(-3px);
131
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
132
+ }
 
 
 
 
 
 
 
133
 
134
+ .action-btn i {
135
+ font-size: 1.1rem;
136
+ }
137
 
138
+ .btn-red { background: var(--grad-red); }
139
+ .btn-indigo { background: var(--grad-indigo); }
140
+ .btn-orange { background: var(--grad-orange); }
141
+ .btn-blue { background: var(--grad-blue); }
142
+ .btn-green { background: var(--grad-green); }
143
+ .btn-dark { background: var(--grad-dark); }
144
+
145
+ /* Main Content */
146
+ .container {
147
+ max-width: 1400px;
148
+ margin: 0 auto;
149
+ padding: 40px 20px;
150
+ }
151
 
152
+ /* Responsive Design */
153
+ @media (max-width: 768px) {
154
+ .logo-text h1 {
155
+ font-size: 1.5rem;
 
 
 
 
 
 
 
156
  }
 
 
157
 
158
+ .action-buttons {
159
+ flex-direction: column;
160
+ align-items: stretch;
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  }
 
 
162
 
163
+ .action-btn {
164
+ justify-content: center;
 
 
 
 
 
 
 
 
165
  }
 
 
166
  }
167
+ </style>
168
+ </head>
169
+ <body>
170
+ <div class="header">
171
+ <div class="logo">
172
+ <img src="https://africa.dlnlp.ai/simba/images/simba_main_logo.png" alt="SimbaBench Logo">
173
+ <div class="logo-text">
174
+ <h1>Voice of a <span class="highlight">Continent</span></h1>
175
+ </div>
176
+ </div>
177
+
178
+ <p class="subtitle">
179
+ The largest open-source benchmark for African speech technology, featuring state-of-the-art models for 61 African languages across ASR, TTS, and SLID tasks.
180
+ </p>
181
+
182
+ <div class="action-buttons">
183
+ <a href="https://aclanthology.org/2025.emnlp-main.559/" target="_blank" class="action-btn btn-red">
184
+ <i class="fa-regular fa-file-pdf"></i> Read Paper
185
+ </a>
186
+ <a href="https://africa.dlnlp.ai/simba/" target="_blank" class="action-btn btn-indigo">
187
+ <i class="fa-solid fa-globe"></i> Official Website
188
+ </a>
189
+ <a href="https://huggingface.co/collections/UBC-NLP/simba-speech-series" target="_blank" class="action-btn btn-orange">
190
+ <i class="fa-solid fa-robot"></i> Simba Models
191
+ </a>
192
+ <a href="https://github.com/UBC-NLP/simba" target="_blank" class="action-btn btn-dark">
193
+ <i class="fa-brands fa-github"></i> GitHub
194
+ </a>
195
+ </div>
196
+ </div>
197
 
198
+ <div class="container">
199
+ <!-- Your leaderboard content goes here -->
200
+ <h2 style="text-align: center; margin-bottom: 30px;">Interactive Leaderboard</h2>
201
+
202
+ <!-- Add your leaderboard table/content here -->
203
+
204
+ </div>
 
 
 
 
 
 
 
 
205
 
206
+ <script>
207
+ // Add any interactive functionality here
 
 
 
 
 
 
208
  </script>
209
  </body>
210
  </html>