elmadany commited on
Commit
b7d2379
Β·
verified Β·
1 Parent(s): 107ece8

Update public/index.html

Browse files
Files changed (1) hide show
  1. public/index.html +299 -125
public/index.html CHANGED
@@ -10,159 +10,333 @@
10
  --primary-navy: #282351;
11
  --primary-orange: #D97706;
12
  --secondary-navy: #2f3b7d;
13
- --bg-cream: #FFFBF5;
 
14
  --border-gold: #dca02a;
 
15
  }
16
- body { background: var(--bg-cream); font-family: 'Inter', sans-serif; color: #333; margin: 0; padding: 20px; }
 
 
 
 
 
 
 
 
17
  .container { max-width: 1400px; margin: 0 auto; }
 
 
18
  .header { text-align: center; margin-bottom: 30px; }
19
- .header img { max-width: 60%; height: auto; }
20
- .card { background: white; border-radius: 12px; padding: 30px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); margin-bottom: 30px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  /* Tabs */
23
  .tabs { display: flex; border-bottom: 2px solid var(--primary-navy); margin-bottom: 20px; }
24
- .tab-btn { background: none; border: none; padding: 12px 20px; font-size: 16px; font-weight: 600; color: var(--secondary-navy); cursor: pointer; border-radius: 8px 8px 0 0; }
 
 
 
 
 
25
  .tab-btn.active { background: var(--primary-navy); color: white; }
26
- .view { display: none; }
27
  .view.active { display: block; }
28
 
29
  /* Controls */
30
- .controls { display: flex; gap: 10px; margin-bottom: 15px; align-items: center; }
31
  .btn { padding: 8px 16px; border-radius: 6px; cursor: pointer; border: none; font-weight: bold; }
32
  .btn-primary { background: var(--primary-navy); color: white; }
33
  .btn-secondary { background: #eee; color: var(--primary-navy); }
34
- select { padding: 8px; border-radius: 6px; min-width: 200px; }
35
-
36
- /* Tables */
37
- .table-wrap { overflow-x: auto; }
38
- table { width: 100%; border-collapse: collapse; border-top: 2px solid var(--border-gold); border-bottom: 2px solid var(--border-gold); font-size: 14px; }
39
- th, td { padding: 10px; text-align: center; border-bottom: 1px solid #eee; white-space: nowrap; }
40
- th { color: #7d3561; vertical-align: bottom; }
41
- th:first-child, td:first-child { text-align: left; font-weight: bold; color: var(--primary-navy); }
42
- .v-head { writing-mode: vertical-rl; transform: rotate(180deg); height: 130px; text-align: left; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- #loader { text-align: center; padding: 50px; font-size: 18px; color: var(--secondary-navy); }
 
 
 
 
 
45
  </style>
46
  </head>
47
  <body>
48
 
49
- <div class="container">
50
- <div class="header"><img src="https://africa.dlnlp.ai/simba/images/simbabench_header.png" alt="Simba"></div>
 
 
51
 
52
- <div class="card">
53
- <div id="loader">🦁 Loading Data...</div>
54
- <div id="content" style="display:none;">
55
- <div class="tabs">
56
- <button class="tab-btn active" onclick="setTab('asr', this)">ASR Leaderboard</button>
57
- <button class="tab-btn" onclick="setTab('tts', this)">TTS Leaderboard</button>
58
- <button class="tab-btn" onclick="setTab('slid', this)">SLID Leaderboard</button>
59
- </div>
 
60
 
61
- <div id="asr" class="view active">
62
- <div class="controls">
63
- <button id="btn-fam" class="btn btn-primary" onclick="setASRMode('family')">By Family</button>
64
- <button id="btn-mod" class="btn btn-secondary" onclick="setASRMode('model')">By Model</button>
65
- <div style="flex-grow:1; text-align:right;"><select id="asr-select" onchange="renderASR()"></select></div>
 
 
 
 
 
 
 
 
 
 
 
 
66
  </div>
67
- <div id="asr-table" class="table-wrap"></div>
68
- </div>
69
 
70
- <div id="tts" class="view">
71
- <div class="controls"><label>Model: </label><select id="tts-select" onchange="renderTTS()"></select></div>
72
- <div id="tts-table" class="table-wrap"></div>
73
  </div>
 
74
 
75
- <div id="slid" class="view"><div id="slid-table" class="table-wrap"></div></div>
 
 
76
  </div>
 
77
  </div>
78
- <div class="card">
79
- <h3>Citation</h3>
80
- <p>If you use Simba, please cite our <a href='https://africa.dlnlp.ai/sahara/' style="color:#D97706">ACL2025 paper</a>.</p>
81
- </div>
82
- </div>
83
-
84
- <script>
85
- let DATA = null;
86
- let asrMode = 'family';
87
-
88
- fetch('/api/data').then(r=>r.json()).then(d=>{
89
- DATA = d;
90
- document.getElementById('loader').style.display='none';
91
- document.getElementById('content').style.display='block';
92
- init();
93
- });
94
-
95
- function init() {
96
- populate('asr-select', DATA.metadata.families);
97
- populate('tts-select', DATA.metadata.tts_models);
98
- renderASR(); renderTTS(); renderSLID();
99
- }
100
- function populate(id, list) {
101
- const s = document.getElementById(id); s.innerHTML='';
102
- list.forEach(i=>{ let o=document.createElement('option'); o.value=i; o.text=i; s.add(o); });
103
- }
104
- function fmt(n) { return (n==null)?'N/A':n.toFixed(2); }
105
-
106
- function renderASR() {
107
- const val = document.getElementById('asr-select').value;
108
- const div = document.getElementById('asr-table');
109
- let html='';
110
- if(asrMode==='family'){
111
- const d=DATA.asr.by_family[val];
112
- if(!d) return;
113
- html=`<table><thead><tr><th>Model</th><th>Avg WER/CER</th>`;
114
- d.languages.forEach(l=>html+=`<th><div class="v-head">${l}</div></th>`);
115
- html+=`</tr></thead><tbody>`;
116
- d.data.forEach(r=>{
117
- html+=`<tr><td>${r.Model}</td><td><b>${fmt(r.Avg_WER)} / ${fmt(r.Avg_CER)}</b></td>`;
118
- d.languages.forEach(l=>{
119
- let w=r[`WER_${l}`], c=r[`CER_${l}`];
120
- html+=`<td>${(w!=null)?fmt(w)+'/'+fmt(c):'-'}</td>`;
 
 
 
 
 
 
 
 
 
 
121
  });
122
- html+=`</tr>`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  });
124
- } else {
125
- const rows=DATA.asr.by_model[val];
126
- html=`<table><thead><tr><th>Language</th><th>Family</th><th>WER</th><th>CER</th></tr></thead><tbody>`;
127
- rows.forEach(r=>html+=`<tr><td>${r.Language}</td><td>${r.Family}</td><td>${fmt(r.WER)}</td><td>${fmt(r.CER)}</td></tr>`);
128
- }
129
- html+=`</tbody></table>`;
130
- div.innerHTML=html;
131
- }
132
-
133
- function renderTTS() {
134
- const rows=DATA.tts[document.getElementById('tts-select').value];
135
- if(!rows) return;
136
- let w=0,m=0,c=0;
137
- rows.forEach(r=>{w+=r.wer;m+=r.mcd;c++;});
138
- let html=`<p><b>Avg:</b> WER: ${fmt(w/c)} | MCD: ${fmt(m/c)}</p><table><thead><tr><th>Lang</th><th>WER</th><th>MCD</th><th>PESQ</th></tr></thead><tbody>`;
139
- rows.forEach(r=>html+=`<tr><td>${r.language}</td><td>${fmt(r.wer)}</td><td>${fmt(r.mcd)}</td><td>${fmt(r.pesq)}</td></tr>`);
140
- html+=`</tbody></table>`;
141
- document.getElementById('tts-table').innerHTML=html;
142
- }
143
-
144
- function renderSLID() {
145
- let html=`<table><thead><tr><th>Lang</th><th>MMS</th><th>Simba</th></tr></thead><tbody>`;
146
- DATA.slid.forEach(r=>{
147
- let m=r['MMS-LID-1024'], s=r['Simba-SLID'];
148
- html+=`<tr><td>${r.Language}</td><td>${m>s?'<b>'+fmt(m)+'</b>':fmt(m)}</td><td>${s>m?'<b>'+fmt(s)+'</b>':fmt(s)}</td></tr>`;
149
- });
150
- html+=`</tbody></table>`;
151
- document.getElementById('slid-table').innerHTML=html;
152
- }
153
-
154
- window.setTab=(id,btn)=>{
155
- document.querySelectorAll('.view').forEach(e=>e.classList.remove('active'));
156
- document.querySelectorAll('.tab-btn').forEach(e=>e.classList.remove('active'));
157
- document.getElementById(id).classList.add('active'); btn.classList.add('active');
158
- };
159
- window.setASRMode=(m)=>{
160
- asrMode=m;
161
- document.getElementById('btn-fam').className=m==='family'?'btn btn-primary':'btn btn-secondary';
162
- document.getElementById('btn-mod').className=m==='model'?'btn btn-primary':'btn btn-secondary';
163
- populate('asr-select', m==='family'?DATA.metadata.families:DATA.metadata.models);
164
- renderASR();
165
- }
166
- </script>
167
  </body>
168
  </html>
 
10
  --primary-navy: #282351;
11
  --primary-orange: #D97706;
12
  --secondary-navy: #2f3b7d;
13
+ --bg-body: #282351; /* Deep Navy Background */
14
+ --bg-card: #ffffff; /* White Card Background */
15
  --border-gold: #dca02a;
16
+ --text-dark: #333;
17
  }
18
+
19
+ body {
20
+ background-color: var(--bg-body);
21
+ font-family: 'Inter', sans-serif;
22
+ color: var(--text-dark);
23
+ margin: 0;
24
+ padding: 20px;
25
+ }
26
+
27
  .container { max-width: 1400px; margin: 0 auto; }
28
+
29
+ /* Header Image */
30
  .header { text-align: center; margin-bottom: 30px; }
31
+ .header img {
32
+ max-width: 60%;
33
+ height: auto;
34
+ border-radius: 12px; /* Optional: Softens the image against the dark bg */
35
+ }
36
+
37
+ /* Content Card */
38
+ .card {
39
+ background: var(--bg-card);
40
+ border-radius: 12px;
41
+ padding: 40px;
42
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
43
+ margin-bottom: 30px;
44
+ }
45
+
46
+ h2 { font-family: "Rubik", sans-serif; color: var(--secondary-navy); font-size: 28px; margin-top: 0; }
47
 
48
  /* Tabs */
49
  .tabs { display: flex; border-bottom: 2px solid var(--primary-navy); margin-bottom: 20px; }
50
+ .tab-btn {
51
+ background: none; border: none; padding: 12px 20px;
52
+ font-size: 16px; font-weight: 600; color: var(--secondary-navy);
53
+ cursor: pointer; border-radius: 8px 8px 0 0;
54
+ transition: 0.3s;
55
+ }
56
  .tab-btn.active { background: var(--primary-navy); color: white; }
57
+ .view { display: none; animation: fadeIn 0.4s; }
58
  .view.active { display: block; }
59
 
60
  /* Controls */
61
+ .controls { display: flex; gap: 10px; margin-bottom: 20px; align-items: center; flex-wrap: wrap; }
62
  .btn { padding: 8px 16px; border-radius: 6px; cursor: pointer; border: none; font-weight: bold; }
63
  .btn-primary { background: var(--primary-navy); color: white; }
64
  .btn-secondary { background: #eee; color: var(--primary-navy); }
65
+ select { padding: 8px; border-radius: 6px; border: 1px solid #ccc; min-width: 200px; }
66
+
67
+ /* --- TABLE STYLING --- */
68
+ .table-wrap { overflow-x: auto; padding-bottom: 50px; /* Space for rotated headers */ }
69
+
70
+ table {
71
+ width: 100%;
72
+ border-collapse: collapse;
73
+ font-size: 14px;
74
+ border-top: 2px solid var(--border-gold);
75
+ /* We remove the bottom border from table to let rows define it, or keep it */
76
+ border-bottom: 2px solid var(--border-gold);
77
+ }
78
+
79
+ th, td {
80
+ padding: 12px 10px;
81
+ text-align: center;
82
+ vertical-align: middle;
83
+ border-bottom: 1px solid #eee;
84
+ }
85
+
86
+ /* Header Row Styling */
87
+ thead tr {
88
+ /* Make header bottom border match the top border color */
89
+ border-bottom: 2px solid var(--border-gold);
90
+ }
91
+
92
+ th {
93
+ color: #7d3561;
94
+ font-weight: bold;
95
+ vertical-align: bottom; /* Align text to bottom for rotated headers */
96
+ }
97
+
98
+ /* Left Align First Column (Languages/Models) */
99
+ th:first-child, td:first-child {
100
+ text-align: left;
101
+ font-weight: bold;
102
+ color: var(--primary-navy);
103
+ min-width: 180px;
104
+ }
105
+
106
+ /* Left Align Second Column (Often Family) */
107
+ th:nth-child(2), td:nth-child(2) {
108
+ text-align: left;
109
+ }
110
+
111
+ /* 45 Degree Rotated Headers */
112
+ .rotate-wrapper {
113
+ height: 120px;
114
+ white-space: nowrap;
115
+ position: relative;
116
+ }
117
+
118
+ .rotate-wrapper > div {
119
+ transform: translate(0px, 40px) rotate(-45deg);
120
+ width: 30px;
121
+ position: absolute;
122
+ bottom: 10px;
123
+ left: 50%;
124
+ text-align: left;
125
+ transform-origin: bottom left;
126
+ }
127
+ .rotate-wrapper span {
128
+ border-bottom: 1px solid #ccc;
129
+ padding-bottom: 2px;
130
+ }
131
+ .sub-header {
132
+ font-size: 10px;
133
+ color: #666;
134
+ font-weight: normal;
135
+ display: block;
136
+ margin-top: 2px;
137
+ }
138
+
139
+ /* Value Cells */
140
+ .val { white-space: nowrap; }
141
 
142
+ /* Metric Arrow Colors */
143
+ .arrow-up { color: green; font-size: 0.9em; }
144
+ .arrow-down { color: #D97706; font-size: 0.9em; } /* Orange for lower-is-better */
145
+
146
+ #loader { text-align: center; padding: 40px; font-size: 18px; color: var(--secondary-navy); }
147
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
148
  </style>
149
  </head>
150
  <body>
151
 
152
+ <div class="container">
153
+ <div class="header">
154
+ <img src="https://africa.dlnlp.ai/simba/images/simbabench_header.png" alt="Simba">
155
+ </div>
156
 
157
+ <div class="card">
158
+ <div id="loader">🦁 Loading Data...</div>
159
+
160
+ <div id="content" style="display:none;">
161
+ <div class="tabs">
162
+ <button class="tab-btn active" onclick="setTab('asr', this)">Automatic Speech Recognition</button>
163
+ <button class="tab-btn" onclick="setTab('tts', this)">Text-to-Speech</button>
164
+ <button class="tab-btn" onclick="setTab('slid', this)">Language ID</button>
165
+ </div>
166
 
167
+ <div id="asr" class="view active">
168
+ <div class="controls">
169
+ <button id="btn-fam" class="btn btn-primary" onclick="setASRMode('family')">By Family</button>
170
+ <button id="btn-mod" class="btn btn-secondary" onclick="setASRMode('model')">By Model</button>
171
+ <div style="flex-grow:1; text-align:right;">
172
+ <select id="asr-select" onchange="renderASR()"></select>
173
+ </div>
174
+ </div>
175
+ <div id="asr-table" class="table-wrap"></div>
176
+ </div>
177
+
178
+ <div id="tts" class="view">
179
+ <div class="controls">
180
+ <label>Select Model: </label>
181
+ <select id="tts-select" onchange="renderTTS()"></select>
182
+ </div>
183
+ <div id="tts-table" class="table-wrap"></div>
184
  </div>
 
 
185
 
186
+ <div id="slid" class="view">
187
+ <div id="slid-table" class="table-wrap"></div>
188
+ </div>
189
  </div>
190
+ </div>
191
 
192
+ <div class="card">
193
+ <h2>Citation</h2>
194
+ <p>If you use the Simba benchmark, please cite our <a href='https://africa.dlnlp.ai/sahara/' style="color:#D97706">ACL2025 paper</a>.</p>
195
  </div>
196
+ <center><img src='https://africa.dlnlp.ai/sahara//img/sahara_web_sponsers.jpg' width='25%'></center>
197
  </div>
198
+
199
+ <script>
200
+ let DATA = null;
201
+ let asrMode = 'family';
202
+
203
+ // Fetch Data
204
+ fetch('/api/data').then(r=>r.json()).then(d=>{
205
+ DATA = d;
206
+ document.getElementById('loader').style.display='none';
207
+ document.getElementById('content').style.display='block';
208
+ init();
209
+ }).catch(e => {
210
+ document.getElementById('loader').innerHTML = "Error loading data.";
211
+ console.error(e);
212
+ });
213
+
214
+ function init() {
215
+ populate('asr-select', DATA.metadata.families);
216
+ populate('tts-select', DATA.metadata.tts_models);
217
+ renderASR(); renderTTS(); renderSLID();
218
+ }
219
+ function populate(id, list) {
220
+ const s = document.getElementById(id); s.innerHTML='';
221
+ list.forEach(i=>{ let o=document.createElement('option'); o.value=i; o.text=i; s.add(o); });
222
+ }
223
+ function fmt(n) { return (n==null)?'N/A':n.toFixed(2); }
224
+
225
+ // --- Render ASR ---
226
+ function renderASR() {
227
+ const val = document.getElementById('asr-select').value;
228
+ const div = document.getElementById('asr-table');
229
+ let html='';
230
+
231
+ if(asrMode==='family'){
232
+ const d=DATA.asr.by_family[val];
233
+ if(!d) return;
234
+
235
+ // Rotated Headers for Languages
236
+ html=`<table><thead><tr>
237
+ <th>Model</th>
238
+ <th>Avg WER/CER <span class="arrow-down">↓</span></th>`;
239
+ d.languages.forEach(l=>html+=`<th><div class="rotate-wrapper"><div>${l}<br><span class="sub-header">WER/CER</span></div></div></th>`);
240
+ html+=`</tr></thead><tbody>`;
241
+
242
+ d.data.forEach(r=>{
243
+ html+=`<tr>
244
+ <td>${r.Model}</td>
245
+ <td class="val"><b>${fmt(r.Avg_WER)} / ${fmt(r.Avg_CER)}</b></td>`;
246
+ d.languages.forEach(l=>{
247
+ let w=r[`WER_${l}`], c=r[`CER_${l}`];
248
+ html+=`<td class="val">${(w!=null)?fmt(w)+'/'+fmt(c):'-'}</td>`;
249
+ });
250
+ html+=`</tr>`;
251
  });
252
+ } else {
253
+ const rows=DATA.asr.by_model[val];
254
+ html=`<table><thead><tr>
255
+ <th>Language</th>
256
+ <th>Family</th>
257
+ <th>WER (%) <span class="arrow-down">↓</span></th>
258
+ <th>CER (%) <span class="arrow-down">↓</span></th>
259
+ </tr></thead><tbody>`;
260
+ rows.forEach(r=>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>`);
261
+ }
262
+ html+=`</tbody></table>`;
263
+ div.innerHTML=html;
264
+ }
265
+
266
+ // --- Render TTS (All Metrics) ---
267
+ function renderTTS() {
268
+ const rows=DATA.tts[document.getElementById('tts-select').value];
269
+ if(!rows) return;
270
+
271
+ // Calculate Average for Summary
272
+ let w=0, m=0, c=0;
273
+ rows.forEach(r=>{w+=r.wer;m+=r.mcd;c++;});
274
+
275
+ let html=`<p><b>Average Metrics:</b> WER: ${fmt(w/c)} | MCD: ${fmt(m/c)}</p>
276
+ <table><thead><tr>
277
+ <th>Language</th>
278
+ <th>WER <span class="arrow-down">↓</span></th>
279
+ <th>MCD <span class="arrow-down">↓</span></th>
280
+ <th>LogF0 <span class="arrow-down">↓</span></th>
281
+ <th>SpTokDist <span class="arrow-down">↓</span></th>
282
+ <th>PESQ <span class="arrow-up">↑</span></th>
283
+ <th>UTMOS <span class="arrow-up">↑</span></th>
284
+ <th>SpBLEU <span class="arrow-up">↑</span></th>
285
+ <th>SpBERT <span class="arrow-up">↑</span></th>
286
+ </tr></thead><tbody>`;
287
+
288
+ rows.forEach(r=>{
289
+ html+=`<tr>
290
+ <td>${r.language}</td>
291
+ <td class="val">${fmt(r.wer)}</td>
292
+ <td class="val">${fmt(r.mcd)}</td>
293
+ <td class="val">${fmt(r.logf0rmse)}</td>
294
+ <td class="val">${fmt(r.speech_token_distance)}</td>
295
+ <td class="val">${fmt(r.pesq)}</td>
296
+ <td class="val">${fmt(r.utmos)}</td>
297
+ <td class="val">${fmt(r.speechbleu)}</td>
298
+ <td class="val">${fmt(r.speechbert_score)}</td>
299
+ </tr>`;
300
  });
301
+ html+=`</tbody></table>`;
302
+ document.getElementById('tts-table').innerHTML=html;
303
+ }
304
+
305
+ // --- Render SLID ---
306
+ function renderSLID() {
307
+ let html=`<table><thead><tr>
308
+ <th>Language</th>
309
+ <th>MMS-LID-1024 <span class="arrow-up">↑</span></th>
310
+ <th>Simba-SLID <span class="arrow-up">↑</span></th>
311
+ </tr></thead><tbody>`;
312
+
313
+ DATA.slid.forEach(r=>{
314
+ let m=r['MMS-LID-1024'], s=r['Simba-SLID'];
315
+ // Highlight highest score
316
+ let mS = fmt(m), sS = fmt(s);
317
+ if(m > s) mS = `<b>${mS}</b>`;
318
+ else if(s > m) sS = `<b>${sS}</b>`;
319
+
320
+ html+=`<tr><td>${r.Language}</td><td class="val">${mS}</td><td class="val">${sS}</td></tr>`;
321
+ });
322
+ html+=`</tbody></table>`;
323
+ document.getElementById('slid-table').innerHTML=html;
324
+ }
325
+
326
+ // Interaction
327
+ window.setTab=(id,btn)=>{
328
+ document.querySelectorAll('.view').forEach(e=>e.classList.remove('active'));
329
+ document.querySelectorAll('.tab-btn').forEach(e=>e.classList.remove('active'));
330
+ document.getElementById(id).classList.add('active'); btn.classList.add('active');
331
+ };
332
+ window.setASRMode=(m)=>{
333
+ asrMode=m;
334
+ document.getElementById('btn-fam').className=m==='family'?'btn btn-primary':'btn btn-secondary';
335
+ document.getElementById('btn-mod').className=m==='model'?'btn btn-primary':'btn btn-secondary';
336
+ document.getElementById('asr-select').style.display = m==='family' ? 'inline-block' : 'inline-block'; // Actually toggle dropdown contents via populate
337
+ populate('asr-select', m==='family'?DATA.metadata.families:DATA.metadata.models);
338
+ renderASR();
339
+ }
340
+ </script>
 
 
 
341
  </body>
342
  </html>