David Pomerenke commited on
Commit
2c21cf7
·
1 Parent(s): b6b84c7

Basic backend setup with FastApi but without actual filtering

Browse files
evals/app.py DELETED
@@ -1,993 +0,0 @@
1
- import json
2
- from functools import partial
3
-
4
- import gradio as gr
5
- import pandas as pd
6
- import plotly.express as px
7
- import plotly.graph_objects as go
8
- import pycountry
9
- from gradio_rangeslider import RangeSlider
10
- from tqdm import tqdm
11
-
12
- with open("results.json") as f:
13
- languages = json.load(f)
14
-
15
- languages_with_scores = [lang for lang in languages if lang["t2t_score"] is not None]
16
-
17
- # Global constants for metric mappings
18
- METRICS = {
19
- "t2t": [
20
- {
21
- "display_name": "Overall Text-to-Text Performance",
22
- "field_name": "t2t_score",
23
- "label": "Overall Score",
24
- "explanation": """
25
- **Overall Score for Text-to-Text Performance**: A weighted combination of all metrics, providing a holistic view of model performance across different language tasks.
26
- Higher scores indicate better overall language capabilities.
27
- """,
28
- },
29
- {
30
- "display_name": "Translation (BLEU)",
31
- "field_name": "mt_bleu",
32
- "label": "BLEU Score",
33
- "explanation": """
34
- **Translation BLEU**: BiLingual Evaluation Understudy (BLEU) measures how similar AI-generated translations are to human reference translations.
35
- It calculates n-gram precision and applies a brevity penalty. Scores range from 0 to 1, with higher values indicating better translation quality.
36
- """,
37
- },
38
- {
39
- "display_name": "Translation (ChrF)",
40
- "field_name": "mt_chrf",
41
- "label": "ChrF Score",
42
- "explanation": """
43
- **Translation ChrF**: Character n-gram F-score evaluates translations at the character level rather than word level.
44
- This metric is particularly valuable for morphologically rich languages and can better capture partial word matches.
45
- Higher scores (0-1) indicate better translations.
46
- """,
47
- },
48
- {
49
- "display_name": "Classification (Accuracy)",
50
- "field_name": "cls_acc",
51
- "label": "Classification Accuracy",
52
- "explanation": """
53
- **Classification Accuracy**: Measures how accurately models can classify text into predefined categories.
54
- This evaluates a model's understanding of content and context across different languages.
55
- Reported as a percentage where higher values indicate better classification performance.
56
- """,
57
- },
58
- {
59
- "display_name": "Masked Language Modeling (ChrF)",
60
- "field_name": "mlm_chrf",
61
- "label": "MLM ChrF Score",
62
- "explanation": """
63
- **Masked Language Modeling ChrF**: Evaluates how well models can predict masked (hidden) portions of text.
64
- This tests a model's understanding of language structure and semantics by measuring the character-level similarity
65
- between predicted and actual text. Higher scores indicate better language understanding.
66
- """,
67
- },
68
- ],
69
- "s2t": [
70
- {
71
- "display_name": "Overall Speech-to-Text Performance",
72
- "field_name": "s2t_score",
73
- "label": "Overall Score",
74
- "explanation": """
75
- **Overall Score for Speech-to-Text Performance**: A weighted combination of all metrics, providing a holistic view of model performance across different language tasks.
76
- Higher scores indicate better overall language capabilities.
77
- """,
78
- },
79
- {
80
- "display_name": "Automatic Speech Recognition (WER)",
81
- "field_name": "asr_wer",
82
- "label": "WER",
83
- "explanation": """
84
- **Automatic Speech Recognition Word Error Rate**: Measures the accuracy of speech-to-text transcription.
85
- It calculates the minimum number of word edits (insertions, deletions, substitutions) needed to transform the
86
- transcription into the reference text, divided by the number of words in the reference.
87
- Lower scores indicate better performance, with 0 being perfect transcription.
88
- """,
89
- },
90
- {
91
- "display_name": "Automatic Speech Recognition (ChrF)",
92
- "field_name": "asr_chrf",
93
- "label": "ChrF",
94
- "explanation": """
95
- **Automatic Speech Recognition ChrF**: Character n-gram F-score evaluates translations at the character level rather than word level.
96
- This metric is particularly valuable for morphologically rich languages and can better capture partial word matches.
97
- Higher scores (0-1) indicate better translations.
98
- """,
99
- },
100
- ],
101
- }
102
-
103
-
104
- def mean(lst):
105
- return sum(lst) / len(lst)
106
-
107
-
108
- def create_leaderboard_df(model_type, metric=None):
109
- metric = metric or METRICS[model_type][0]
110
- _model_type = {"t2t": "text-to-text", "s2t": "speech-to-text"}[model_type]
111
- models = {
112
- score["model"]
113
- for lang in languages_with_scores
114
- for score in lang["scores"]
115
- if score["model_type"] == _model_type
116
- }
117
- model_scores = [
118
- {"model": score["model"], metric["field_name"]: score[metric["field_name"]]}
119
- for lang in languages_with_scores
120
- for score in lang["scores"]
121
- for model in models
122
- if score["model"] == model
123
- ]
124
- df = (
125
- pd.DataFrame(model_scores)
126
- .groupby("model")
127
- .agg({metric["field_name"]: ["mean", "count"]})
128
- .reset_index()
129
- )
130
- # Flatten the multi-level column names
131
- df.columns = df.columns.map(
132
- lambda x: f"{x[0]}_{x[1]}" if isinstance(x, tuple) else x
133
- )
134
- df = df.rename(
135
- columns={
136
- f"{metric['field_name']}_mean": metric["label"],
137
- f"{metric['field_name']}_count": "Languages Tested",
138
- "model_": "Model",
139
- }
140
- )
141
- df[metric["label"]] = df[metric["label"]].round(3)
142
- df = df.sort_values(metric["label"], ascending=False)
143
- df["Rank"] = range(1, len(df) + 1)
144
- df["Rank"] = df["Rank"].apply(
145
- lambda x: "🥇" if x == 1 else "🥈" if x == 2 else "🥉" if x == 3 else str(x)
146
- )
147
- df = df[["Rank", "Model", metric["label"]]]
148
- return gr.DataFrame(
149
- value=df,
150
- label="Model Leaderboard",
151
- show_search=False,
152
- datatype=["number", "markdown", "number"],
153
- )
154
-
155
-
156
- def create_model_comparison_plot(metric):
157
- top_languages = sorted(
158
- languages_with_scores, key=lambda x: x["speakers"], reverse=True
159
- )[:10]
160
-
161
- # Create appropriate title and y-axis label based on metric
162
- title = f"{metric['display_name']} by Model and Language"
163
- y_label = metric["label"]
164
-
165
- # Flatten the data for the selected metric
166
- scores_flat = []
167
- for lang in top_languages:
168
- for score in lang["scores"]:
169
- # Get the value directly using the field name
170
- if metric["field_name"] not in score:
171
- continue
172
- value = score[metric["field_name"]]
173
- if value is not None:
174
- scores_flat.append(
175
- {
176
- "language": lang["language_name"],
177
- "model": score["model"],
178
- "value": value,
179
- }
180
- )
181
-
182
- df = pd.DataFrame(scores_flat)
183
- fig = px.bar(df, x="language", y="value", color="model", barmode="group")
184
- fig.update_layout(
185
- title=title,
186
- xaxis_title=None,
187
- yaxis_title=y_label,
188
- barmode="group",
189
- height=500,
190
- legend=dict(
191
- orientation="h", # horizontal orientation
192
- yanchor="bottom",
193
- y=-0.3, # position below plot
194
- xanchor="center",
195
- x=0.5, # center horizontally
196
- ),
197
- )
198
- return fig
199
-
200
-
201
- def create_language_stats_df(metric):
202
- # Create a list to store flattened data
203
- flat_data = []
204
-
205
- for lang in languages:
206
- # Find the best model and its BLEU score
207
- best_model = (
208
- max(
209
- lang["scores"] or [{"t2t_score": None, "model": None}],
210
- key=lambda x: x.get("t2t_score", 0),
211
- )
212
- if lang["t2t_score"] is not None
213
- else None
214
- )
215
-
216
- model = best_model["model"] if best_model else None
217
- model_name = model.split("/")[-1] if model else "N/A"
218
- model_link = (
219
- f"<a href='https://openrouter.ai/{model}' style='text-decoration: none; color: inherit;'>{model_name}</a>"
220
- if model
221
- else "N/A"
222
- )
223
- commonvoice_link = (
224
- f"<!--{lang['commonvoice_hours']:07} (for sorting)--> <a href='https://commonvoice.mozilla.org/{lang['commonvoice_locale']}/speak' style='text-decoration: none; color: inherit;'>🎙️ {round(lang['commonvoice_hours'])}h</a>"
225
- if lang["commonvoice_hours"]
226
- else "N/A"
227
- )
228
- language_link = f"<a href='/{lang['bcp_47']}' style='text-decoration: none; font-weight: bold;'>{lang['language_name']}</a>"
229
-
230
- row = {
231
- "Language": language_link,
232
- "Speakers (M)": round(lang["speakers"] / 1_000_000, 1),
233
- # "Models Tested": len(lang["scores"]),
234
- # "Overall": round(lang["overall_score"], 3)
235
- # if lang["overall_score"] is not None
236
- # else "N/A",
237
- "Best Model": model_link,
238
- "Trans­la­ti­on": round(lang["mt_chrf"], 3)
239
- if lang["mt_chrf"] is not None
240
- else "N/A",
241
- "Classi­fi­ca­ti­on": round(lang["cls_acc"], 3)
242
- if lang["cls_acc"] is not None
243
- else "N/A",
244
- "Masked Language Modeling": round(lang["mlm_chrf"], 3)
245
- if lang["mlm_chrf"] is not None
246
- else "N/A",
247
- "Speech Reco­gni­ti­on": round(lang["asr_chrf"], 3) if lang["asr_wer"] is not None else "N/A",
248
- "Common­Voice": commonvoice_link,
249
- }
250
- flat_data.append(row)
251
-
252
- df = pd.DataFrame(flat_data)
253
- return gr.DataFrame(
254
- value=df,
255
- label="Language Results",
256
- show_search="search",
257
- pinned_columns=1,
258
- column_widths=[
259
- "100px",
260
- "100px",
261
- # "100px",
262
- # "100px",
263
- "200px", # Best Model
264
- "100px", # MT
265
- "100px", # CLS
266
- "100px", # MLM
267
- "100px", # ASR
268
- "100px", # Common Voice
269
- ],
270
- datatype=[
271
- "markdown", # Language
272
- "number", # Speakers
273
- # "number", # Models Tested
274
- # "number", # Overall
275
- "markdown", # Best Model
276
- "number", # Translation
277
- "number", # Classification
278
- "number", # MLM
279
- "number", # ASR
280
- "markdown", # CommonVoice Hours
281
- ],
282
- )
283
-
284
-
285
- def create_scatter_plot(metric):
286
- # Create a list to store data for the scatter plot
287
- scatter_data = []
288
- for lang in languages_with_scores:
289
- if lang["speakers"] < 100_000:
290
- continue
291
- # Calculate average score for this metric across all models
292
- scores = [
293
- score[metric["field_name"]]
294
- for score in lang["scores"]
295
- if metric["field_name"] in score and score[metric["field_name"]] is not None
296
- ]
297
- if scores: # Only include if we have valid scores
298
- avg_score = sum(scores) / len(scores)
299
- scatter_data.append(
300
- {
301
- "language": lang["language_name"],
302
- "speakers": lang["speakers"],
303
- "score": avg_score,
304
- "family": lang["language_family"],
305
- }
306
- )
307
-
308
- fig = go.Figure()
309
- x_vals = [data["speakers"] / 1_000_000 for data in scatter_data]
310
- y_vals = [data["score"] for data in scatter_data]
311
- s_vals = [data["speakers"] / 20_000_000 for data in scatter_data]
312
- color_pallette = [
313
- "LightSkyBlue",
314
- "LightGreen",
315
- "LightCoral",
316
- "LightPink",
317
- "LightGoldenRodYellow",
318
- "LightGray",
319
- "LightSalmon",
320
- "LightSeaGreen",
321
- ]
322
- color_mapping = {
323
- family: color
324
- for family, color in zip(
325
- sorted(set(data["family"] for data in scatter_data)), color_pallette
326
- )
327
- }
328
- c_vals = [color_mapping.get(data["family"], "LightGray") for data in scatter_data]
329
- labels = [data["language"] for data in scatter_data]
330
- hover_template = f"<b>%{{text}}</b><br>Speakers: %{{x:.1f}}M<br>{metric['label']}: %{{y:.3f}}<extra></extra>"
331
- fig.add_trace(
332
- go.Scatter(
333
- x=x_vals,
334
- y=y_vals,
335
- marker=dict(size=s_vals, color=c_vals),
336
- mode="markers+text",
337
- text=labels,
338
- textposition="top center",
339
- hovertemplate=hover_template,
340
- )
341
- )
342
- fig.update_layout(
343
- title=None,
344
- xaxis_title="Number of Speakers (Millions)",
345
- yaxis_title=metric["label"],
346
- height=500,
347
- showlegend=False,
348
- )
349
- fig.update_xaxes(type="log")
350
- return fig
351
-
352
-
353
- def format_number(n):
354
- """Format number with K/M suffix"""
355
- if n >= 1_000_000:
356
- return f"{n/1_000_000:.1f}M"
357
- elif n >= 1_000:
358
- return f"{n/1_000:.0f}K"
359
- return str(n)
360
-
361
-
362
- def get_population_data():
363
- import xml.etree.ElementTree as ET
364
-
365
- from language_data.util import data_filename
366
-
367
- filename = data_filename("supplementalData.xml")
368
- root = ET.fromstring(open(filename).read())
369
- territories = root.findall("./territoryInfo/territory")
370
-
371
- data = {}
372
- for territory in territories:
373
- t_code = territory.attrib["type"]
374
- t_population = float(territory.attrib["population"])
375
- data[t_code] = t_population
376
- return data
377
-
378
-
379
- # Helper functions for visualization
380
- def make_black_bar(value, max_width=10):
381
- filled = int(value * max_width)
382
- return "⬛️" * filled + "⬜️" * (max_width - filled)
383
-
384
-
385
- def make_colored_bar(score, max_width=10):
386
- """Create a colored bar using Unicode blocks based on normalized score
387
- 🟦 for high values (>0.35)
388
- 🟨 for medium values (0.25-0.35)
389
- 🟥 for low values (<0.25)
390
- ⬜ for empty space
391
-
392
- This function handles both normalization and bar creation.
393
- """
394
-
395
- # Create the bar based on normalized value
396
- filled = int(score * max_width)
397
- filled = max(0, min(filled, max_width))
398
- empty = max_width - filled
399
-
400
- if score > 0.35:
401
- return "🟦" * filled + "⬜" * empty
402
- elif score > 0.25:
403
- return "🟨" * filled + "⬜" * empty
404
- else:
405
- return "🟥" * filled + "⬜" * empty
406
-
407
-
408
- def create_world_map(metric):
409
- # Collect all country data
410
- population_data = get_population_data()
411
- country_data = {}
412
- for lang in languages:
413
- # Skip languages without the required data
414
- if "population" not in lang or lang[metric["field_name"]] is None:
415
- continue
416
-
417
- for country_code, speakers in lang["population"].items():
418
- try:
419
- # Convert alpha_2 (2-letter) to alpha_3 (3-letter) code
420
- country = pycountry.countries.get(alpha_2=country_code)
421
- if country is None:
422
- continue
423
-
424
- iso3_code = country.alpha_3
425
- if iso3_code not in country_data:
426
- country_data[iso3_code] = {
427
- "total_speakers": 0,
428
- "population": population_data.get(country_code, 0),
429
- "weighted_score_sum": 0,
430
- "languages": [],
431
- }
432
-
433
- country_data[iso3_code]["total_speakers"] += speakers
434
- country_data[iso3_code]["weighted_score_sum"] += (
435
- speakers * lang[metric["field_name"]]
436
- )
437
- country_data[iso3_code]["languages"].append(
438
- {
439
- "name": lang["language_name"],
440
- "speakers": speakers,
441
- "score": lang[metric["field_name"]],
442
- }
443
- )
444
- except (KeyError, AttributeError):
445
- # Skip invalid or unrecognized country codes
446
- continue
447
-
448
- # Calculate final weighted averages and prepare hover text
449
- countries = []
450
- scores = []
451
- hover_texts = []
452
-
453
- for country_code, data in country_data.items():
454
- weighted_avg = data["weighted_score_sum"] / data["total_speakers"] if data["total_speakers"] > 0 else None
455
-
456
- try:
457
- country_name = pycountry.countries.get(alpha_3=country_code).name
458
- except AttributeError:
459
- country_name = country_code
460
-
461
- # Sort languages by number of speakers
462
- langs = sorted(data["languages"], key=lambda x: x["speakers"], reverse=True)
463
-
464
- # Take top 5 languages and summarize the rest
465
- main_langs = langs[:5]
466
- other_langs = langs[5:]
467
-
468
- # Create language rows with bars
469
- lang_rows = []
470
- for lang in main_langs:
471
- percentage = (lang["speakers"] / data["population"]) * 100
472
- speaker_bar = make_black_bar(percentage / 100)
473
-
474
- # Use the integrated make_colored_bar function directly
475
- score_bar = make_colored_bar(lang["score"])
476
-
477
- lang_rows.append(
478
- f"<b>{lang['name']}</b><br>"
479
- f"{speaker_bar} {format_number(lang['speakers'])} speakers<br>"
480
- f"{score_bar} {lang['score']:.3f} {metric['label']}<br>"
481
- )
482
-
483
- # Add summary for other languages if any
484
- if other_langs:
485
- other_speakers = sum(lang["speakers"] for lang in other_langs)
486
- other_percentage = (other_speakers / data["population"]) * 100
487
- other_avg_score = sum(lang["score"] for lang in other_langs) / len(
488
- other_langs
489
- )
490
-
491
- speaker_bar = make_black_bar(other_percentage / 100)
492
-
493
- # Use the integrated make_colored_bar function directly
494
- score_bar = make_colored_bar(other_avg_score)
495
-
496
- lang_rows.append(
497
- f"<b>+{len(other_langs)} other languages</b><br>"
498
- f"{speaker_bar} {format_number(other_speakers)} speakers<br>"
499
- f"{score_bar} {other_avg_score:.3f} {metric['label']}<br>"
500
- )
501
-
502
- hover_text = f"<b>{country_name}</b><br><br>" f"{'<br>'.join(lang_rows)}"
503
-
504
- countries.append(country_code)
505
- scores.append(weighted_avg)
506
- hover_texts.append(hover_text)
507
-
508
- fig = go.Figure(
509
- data=go.Choropleth(
510
- locations=countries,
511
- locationmode="ISO-3",
512
- z=scores,
513
- text=hover_texts,
514
- hoverinfo="text",
515
- colorscale=[[0, "#ff9999"], [1, "#99ccff"]],
516
- colorbar=dict(
517
- title=metric["label"],
518
- orientation="h", # horizontal orientation
519
- y=-0.2, # position below map
520
- yanchor="bottom",
521
- len=0.5, # length of colorbar
522
- x=0.5, # center horizontally
523
- xanchor="center",
524
- thickness=20, # make it a bit thicker when horizontal
525
- ),
526
- )
527
- )
528
-
529
- fig.update_layout(
530
- title=dict(
531
- text=f"{metric['display_name']} by Country", x=0.5, xanchor="center"
532
- ),
533
- geo=dict(
534
- showframe=True,
535
- showcoastlines=True,
536
- projection_type="equal earth",
537
- showland=True,
538
- landcolor="#f8f9fa",
539
- coastlinecolor="#e0e0e0",
540
- countrycolor="#e0e0e0",
541
- ),
542
- height=600,
543
- margin=dict(l=0, r=0, t=30, b=0),
544
- paper_bgcolor="white",
545
- hoverlabel=dict(
546
- bgcolor="beige",
547
- font_size=12,
548
- ),
549
- )
550
-
551
- return fig
552
-
553
-
554
- def create_metric_selector(model_type):
555
- match model_type:
556
- case "t2t":
557
- choices = [m["display_name"] for m in METRICS["t2t"]]
558
- case "s2t":
559
- choices = [m["display_name"] for m in METRICS["s2t"]]
560
- return gr.Dropdown(
561
- choices=choices, value=choices[0], label="Select Metric", interactive=True
562
- )
563
-
564
-
565
- def create_metric_explanation(metric):
566
- return gr.Markdown(metric["explanation"], container=True)
567
-
568
- css="""
569
- .radio-group .wrap {
570
- display: grid !important;
571
- grid-template-columns: 1fr 1fr;
572
- }
573
-
574
- .nav-holder {display: none;}
575
-
576
- .share-link {
577
- display: inline-flex;
578
- align-items: center;
579
- background-color: #f0f0f0;
580
- border-radius: 8px;
581
- padding: 8px 12px;
582
- margin: 10px 0;
583
- font-family: monospace;
584
- transition: all 0.2s ease;
585
- cursor: pointer;
586
- text-decoration: none;
587
- color: #333;
588
- }
589
-
590
- .share-link:hover {
591
- background-color: #e0e0e0;
592
- }
593
-
594
- .share-link .icon {
595
- margin-left: 8px;
596
- }
597
-
598
- .title-row {
599
- display: flex;
600
- align-items: center;
601
- justify-content: space-between;
602
- margin-bottom: 1rem;
603
- }
604
-
605
- .title-row h2 {
606
- margin: 0;
607
- }
608
- """
609
-
610
-
611
- shortcut_js = """
612
- <script>
613
- // Handle URL parameters for direct language access
614
- const params = new URLSearchParams(window.location.search);
615
- const lang = params.get("lang");
616
-
617
- if (lang) {
618
- window.location.href = "/" + lang;
619
- }
620
-
621
- // Function to copy link to clipboard
622
- const copyLinkToClipboard = (link) => {
623
- navigator.clipboard.writeText(link);
624
- console.log("Copied link to clipboard: " + link);
625
- }
626
-
627
- const redirect_to_lang = lang_descriptor => {
628
- lang_code = lang_descriptor.split("(")[1].split(")")[0];
629
- console.log("redirecting to /" + lang_code);
630
- window.location.href = "/" + lang_code;
631
- }
632
-
633
- const empty_search = () => {
634
- console.log("empty search");
635
- document.getElementById("search-dropdown").value = "";
636
- }
637
- </script>
638
- """
639
-
640
-
641
- # Create the visualization components
642
- with gr.Blocks(title="AI Language Proficiency Benchmark", css=css, head=shortcut_js) as demo:
643
- language_choices = [
644
- f"{lang['language_name']} ({lang['bcp_47']})" for lang in languages
645
- ]
646
- models = {score["model"] for lang in languages for score in lang["scores"]}
647
- search = gr.Dropdown(
648
- choices=language_choices, # + list(models),
649
- value="Search for Language or Model",
650
- allow_custom_value=True,
651
- interactive=True,
652
- container=False,
653
- elem_id="search-dropdown"
654
- )
655
- search.focus(fn=lambda x: None, inputs=search, outputs=None, js="(x) => {empty_search()}")
656
- search.change(fn=lambda x: None, inputs=search, outputs=None, js="(x) => {redirect_to_lang(x)}")
657
- gr.Markdown("# AI Language Proficiency Benchmark")
658
- gr.Markdown("Comparing language proficiency across different models and languages.")
659
- with gr.Row():
660
- start_model_type = "Text-to-Text"
661
- model_type = gr.Radio(
662
- choices=["Text-to-Text", "Speech-to-Text"],
663
- value=start_model_type,
664
- label="Select Model Type",
665
- interactive=True,
666
- elem_classes="radio-group",
667
- )
668
- start_metric = METRICS["t2t"][0]
669
- metric = gr.Dropdown(
670
- choices=[metric["display_name"] for metric in METRICS["t2t"]],
671
- value=start_metric["display_name"],
672
- label="Main task and metric to display in figures and map",
673
- interactive=True,
674
- )
675
- with gr.Row():
676
- with gr.Column():
677
- with gr.Accordion("Model Filters", open=False):
678
- model_licenses = gr.CheckboxGroup(
679
- choices=["open source", "commercial"],
680
- value=["open source", "commercial"],
681
- label="Filter by Model License",
682
- interactive=True,
683
- )
684
- model_sizes = RangeSlider(
685
- minimum=0,
686
- maximum=1000,
687
- value=(0, 1000),
688
- label="Filter by Model Size (in Billion Parameters)",
689
- interactive=True,
690
- )
691
- with gr.Column():
692
- with gr.Accordion("Language Filters", open=False):
693
- unit_of_analysis = gr.Radio(
694
- choices=["Languages", "Language Families", "Regions"],
695
- value="Languages",
696
- label="Select Unit of Analysis",
697
- interactive=True,
698
- )
699
- family_filter = gr.CheckboxGroup(
700
- choices=[
701
- "Indo-European",
702
- "Sino-Tibetan",
703
- "Afro-Asiatic",
704
- "Dravidian",
705
- "Uralic",
706
- "Austronesian",
707
- "Other",
708
- ],
709
- value=[
710
- "Indo-European",
711
- "Sino-Tibetan",
712
- "Afro-Asiatic",
713
- "Dravidian",
714
- "Uralic",
715
- "Austronesian",
716
- "Other",
717
- ],
718
- label="Filter by Language Family",
719
- interactive=True,
720
- )
721
- speakers_filter = RangeSlider(
722
- minimum=0,
723
- maximum=100_000_000,
724
- value=(0, 100_000_000),
725
- label="Filter by Number of Speakers",
726
- interactive=True,
727
- )
728
-
729
- gr.Markdown("## Model Comparison")
730
- leaderboard_df = create_leaderboard_df("t2t", start_metric)
731
-
732
- model_comparison_plot = gr.Plot(
733
- value=create_model_comparison_plot(start_metric),
734
- label="Model Comparison",
735
- )
736
-
737
- gr.Markdown("## Language Stats")
738
- create_language_stats_df(start_metric)
739
- scatter_plot = gr.Plot(
740
- value=create_scatter_plot(start_metric),
741
- label="Speaker Population vs. Metric",
742
- )
743
- world_map = gr.Plot(
744
- value=create_world_map(start_metric),
745
- label="World Map",
746
- container=False,
747
- elem_classes="fullwidth-plot",
748
- )
749
-
750
- def update_model_type(model_type_choice):
751
- model_type = {"Text-to-Text": "t2t", "Speech-to-Text": "s2t"}[model_type_choice]
752
- return create_metric_selector(model_type), create_leaderboard_df(model_type)
753
-
754
- model_type.change(
755
- fn=update_model_type,
756
- inputs=model_type,
757
- outputs=[metric, leaderboard_df],
758
- )
759
-
760
- def update_component(fn, model_type_choice, metric_choice):
761
- model_type = {"Text-to-Text": "t2t", "Speech-to-Text": "s2t"}[model_type_choice]
762
- metric = [m for m in METRICS[model_type] if m["display_name"] == metric_choice][
763
- 0
764
- ]
765
- return fn(metric)
766
- metric.change(
767
- fn=partial(update_component, create_model_comparison_plot),
768
- inputs=[model_type, metric],
769
- outputs=model_comparison_plot,
770
- )
771
- metric.change(
772
- fn=partial(update_component, create_scatter_plot),
773
- inputs=[model_type, metric],
774
- outputs=scatter_plot,
775
- )
776
- metric.change(
777
- fn=partial(update_component, create_world_map),
778
- inputs=[model_type, metric],
779
- outputs=world_map,
780
- )
781
-
782
- with gr.Accordion("Methodology", open=False):
783
- gr.Markdown(
784
- """
785
- ### Benchmark Data
786
- We use the [FLORES+](https://huggingface.co/datasets/openlanguagedata/flores_plus) dataset for evaluation, which contains parallel text in over 200 languages, as well as topic labels for each sentence. Where FLORES+ includes multiple scripts for one language, we use only the most common one.
787
-
788
- Population and speaker data and language code resolution are from Unicode [CLDR](https://github.com/unicode-org/cldr) via the [langcodes](https://github.com/rspeer/langcodes) package.
789
-
790
- ### AI Models
791
- We use [OpenRouter](https://openrouter.ai/) to access all relevant AI models via a unified API.
792
-
793
- ### Evaluation Tasks
794
- Our benchmark includes three core tasks to assess different aspects of language understanding:
795
-
796
- 1. **Machine Translation**: Models translate text _from_ the evaluated language _to_ a fixed set of target languages. The set of target languages is representative of global speaker populations. Performance is measured using:
797
- - [BLEU Score](https://huggingface.co/metrics/bleu): Measures n-gram precision with a brevity penalty
798
- - [ChrF Score](https://huggingface.co/metrics/chrf): Character-level F-score that better captures morphological variations
799
-
800
- 2. **Text Classification**: Models classify text into predefined topics after being shown examples. We:
801
- - Group sentences by URL into paragraphs with the same topic
802
- - Use the 5 most common topics, encoded as numbers rather than English labels
803
- - Provide 5 examples of each topic as few-shot examples
804
- - Test the model's ability to classify new text
805
- - Report accuracy as the primary metric
806
-
807
- 3. **Masked Language Modeling**: Models predict missing portions of text (marked with `<mask>`). We:
808
- - Mask approximately 5% of each sentence at a random position
809
- - Provide 10 examples of complete sentences paired with masked versions in a few-shot setting
810
- - Evaluate predictions using ChrF score against the original text
811
-
812
- The overall performance score combines metrics from all tasks to provide a holistic assessment of model capabilities across languages.
813
- """
814
- )
815
-
816
-
817
- for lang in tqdm(languages[:20], desc="Generating pages"):
818
- with demo.route(lang['language_name'], f"/{lang['bcp_47']}"):
819
- gr.Button("← Back to Main Dashboard", link="/")
820
- url = f"hf.co/spaces/datenlaborbmz/ai-language-monitor?lang={lang['bcp_47']}"
821
- gr.Markdown(
822
- f'''
823
- <div class="title-row">
824
- <h2>{lang['language_name']}</h2>
825
- <div class="share-link" onclick="copyLinkToClipboard('{url}')">{url}<span class="icon">📋</span></div>
826
- </div>
827
- ''',
828
- sanitize_html=False
829
- )
830
-
831
- # Language overview section
832
- with gr.Row():
833
- with gr.Column(scale=2):
834
- gr.Markdown(f"""
835
- ## Language Overview
836
- - **Native name**: {lang.get('native_name', 'N/A')}
837
- - **Language family**: {lang.get('language_family', 'N/A')}
838
- - **BCP-47 code**: `{lang['bcp_47']}`
839
- - **ISO 639-3 code**: `{lang.get('iso_639_3', 'N/A')}`
840
- - **Number of speakers**: {format_number(lang['speakers'])}
841
- - **Script**: {lang.get('script', 'N/A')}
842
- - **CommonVoice hours**: {round(lang.get('commonvoice_hours', 0) or 0)}
843
- """)
844
-
845
- # Resource links
846
- resource_links = []
847
- if lang.get('commonvoice_locale'):
848
- resource_links.append(f"[CommonVoice Dataset](https://commonvoice.mozilla.org/{lang['commonvoice_locale']})")
849
- if lang.get('wikipedia_code'):
850
- resource_links.append(f"[Wikipedia](https://{lang['wikipedia_code']}.wikipedia.org)")
851
- if lang.get('bcp_47'):
852
- resource_links.append(f"[FLORES+ Dataset](https://huggingface.co/datasets/openlanguagedata/flores_plus/viewer/all/{lang['bcp_47']})")
853
-
854
- if resource_links:
855
- gr.Markdown("### Resources\n" + "\n".join(resource_links))
856
-
857
- with gr.Column(scale=3):
858
- # Create a mini-map showing where the language is spoken
859
- country_data = {}
860
- if "population" in lang:
861
- for country_code, speakers in lang["population"].items():
862
- try:
863
- country = pycountry.countries.get(alpha_2=country_code)
864
- if country:
865
- country_data[country.alpha_3] = speakers / lang["speakers"]
866
- except (KeyError, AttributeError):
867
- continue
868
-
869
- locations = list(country_data.keys())
870
- values = list(country_data.values())
871
-
872
- if locations:
873
- fig = go.Figure(data=go.Choropleth(
874
- locations=locations,
875
- z=values,
876
- locationmode="ISO-3",
877
- colorscale="Blues",
878
- marker_line_color='white',
879
- marker_line_width=0.5,
880
- colorbar_title="Speaker %"
881
- ))
882
-
883
- fig.update_layout(
884
- title_text=f"Distribution of {lang['language_name']} Speakers",
885
- geo=dict(
886
- showframe=False,
887
- showcoastlines=True,
888
- projection_type='natural earth'
889
- ),
890
- height=300,
891
- margin={"r":0,"t":30,"l":0,"b":0}
892
- )
893
-
894
- gr.Plot(value=fig)
895
- else:
896
- gr.Markdown("*Geographic data not available*")
897
-
898
- # Performance metrics section
899
- gr.Markdown("## AI Model Performance")
900
-
901
- with gr.Row():
902
- with gr.Column():
903
- # Create metrics dashboard for this language
904
- metrics_data = []
905
- for metric_key, display_name in [
906
- ("t2t_score", "Overall Text Performance"),
907
- ("mt_bleu", "Translation (BLEU)"),
908
- ("mt_chrf", "Translation (ChrF)"),
909
- ("cls_acc", "Classification"),
910
- ("mlm_chrf", "Masked Language Modeling"),
911
- ("s2t_score", "Overall Speech Performance"),
912
- ("asr_wer", "Speech Recognition (WER)"),
913
- ("asr_chrf", "Speech Recognition (ChrF)")
914
- ]:
915
- if metric_key in lang and lang[metric_key] is not None:
916
- value = lang[metric_key]
917
- color = "green" if value > 0.5 else "orange" if value > 0.25 else "red"
918
-
919
- # For WER, lower is better, so invert the color logic
920
- if metric_key == "asr_wer":
921
- color = "green" if value < 0.3 else "orange" if value < 0.6 else "red"
922
-
923
- metrics_data.append({
924
- "Metric": display_name,
925
- "Value": round(value, 3),
926
- "Visual": make_colored_bar(value if metric_key != "asr_wer" else 1 - value)
927
- })
928
-
929
- if metrics_data:
930
- gr.DataFrame(
931
- pd.DataFrame(metrics_data),
932
- label=f"Performance Metrics for {lang['language_name']}",
933
- show_search=False
934
- )
935
- else:
936
- gr.Markdown("*No performance metrics available*")
937
-
938
- # Model comparison table
939
- gr.Markdown("## Model Comparison")
940
-
941
- with gr.Row():
942
- models_data = []
943
- for score in lang["scores"]:
944
- if score.get("t2t_score") is not None:
945
- model_name = score["model"].split("/")[-1]
946
- models_data.append({
947
- "Model": model_name,
948
- "Overall": round(score.get("t2t_score", 0), 3),
949
- "Translation": round(score.get("mt_chrf", 0), 3),
950
- "Classification": round(score.get("cls_acc", 0), 3),
951
- "Lang Model": round(score.get("mlm_chrf", 0), 3),
952
- "Speech": round(score.get("asr_chrf", 0), 3) if "asr_chrf" in score else "N/A"
953
- })
954
-
955
- if models_data:
956
- df = pd.DataFrame(models_data).sort_values("Overall", ascending=False)
957
- gr.DataFrame(
958
- df,
959
- label=f"Model Performance on {lang['language_name']}",
960
- show_search=False
961
- )
962
- else:
963
- gr.Markdown("*No model comparison data available*")
964
-
965
- # Performance comparison with similar languages
966
- if lang.get("language_family"):
967
- gr.Markdown("## Comparison with Related Languages")
968
-
969
- # Find related languages
970
- related_langs = [l for l in languages if l.get("language_family") == lang["language_family"] and l["t2t_score"] is not None]
971
- related_langs = sorted(related_langs, key=lambda x: x["t2t_score"], reverse=True)[:10]
972
-
973
- if len(related_langs) > 1:
974
- lang_names = [l["language_name"] for l in related_langs]
975
- t2t_scores = [l["t2t_score"] for l in related_langs]
976
-
977
- fig = px.bar(
978
- x=lang_names,
979
- y=t2t_scores,
980
- labels={"x": "Language", "y": "Text-to-Text Score"},
981
- title=f"Performance Across {lang['language_family']} Languages"
982
- )
983
-
984
- # Highlight the current language
985
- for i, name in enumerate(lang_names):
986
- if name == lang["language_name"]:
987
- fig.data[0].marker.color = ["lightblue"] * i + ["orange"] + ["lightblue"] * (len(lang_names) - i - 1)
988
-
989
- fig.update_layout(height=400)
990
- gr.Plot(value=fig)
991
-
992
-
993
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
evals/backend.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ import uvicorn
6
+ from fastapi import FastAPI
7
+ from fastapi.middleware.cors import CORSMiddleware
8
+ from fastapi.middleware.gzip import GZipMiddleware
9
+ from fastapi.responses import JSONResponse
10
+ from fastapi.staticfiles import StaticFiles
11
+ from languages import languages
12
+ from models import models
13
+ from tables import aggregate, make_country_table, make_language_table, make_model_table
14
+
15
+ app = FastAPI()
16
+
17
+ app.add_middleware(CORSMiddleware, allow_origins=["*"])
18
+ app.add_middleware(GZipMiddleware, minimum_size=1000)
19
+
20
+ with open("results.json", "r") as f:
21
+ results = json.load(f)
22
+
23
+
24
+ def serialize(df):
25
+ return df.replace({np.nan: None}).to_dict(orient="records")
26
+
27
+
28
+ @app.post("/api/data")
29
+ def data():
30
+ _, lang_results, model_results, task_results = aggregate(results)
31
+ model_table = make_model_table(model_results, models)
32
+ language_table = make_language_table(lang_results, languages)
33
+ datasets_df = pd.read_json("data/datasets.json")
34
+ countries = make_country_table(language_table)
35
+ all_tables = {
36
+ "model_table": serialize(model_table),
37
+ "language_table": serialize(language_table),
38
+ "dataset_table": serialize(datasets_df),
39
+ "countries": serialize(countries),
40
+ }
41
+ return JSONResponse(content=all_tables)
42
+
43
+ app.mount("/", StaticFiles(directory="frontend/public", html=True), name="frontend")
44
+
45
+ if __name__ == "__main__":
46
+ uvicorn.run(app, host="0.0.0.0", port=8000)
evals/countries.py CHANGED
@@ -2,7 +2,7 @@ import re
2
  import xml.etree.ElementTree as ET
3
  from collections import defaultdict
4
 
5
- import pycountry
6
  from language_data.population_data import LANGUAGE_SPEAKING_POPULATION
7
  from language_data.util import data_filename
8
 
@@ -38,7 +38,7 @@ def make_country_table(language_table):
38
  "name": lang.language_name,
39
  "bcp_47": lang.bcp_47,
40
  "population": speaker_pop,
41
- "score": lang.average,
42
  }
43
  )
44
  for country, languages in countries.items():
@@ -51,4 +51,5 @@ def make_country_table(language_table):
51
  "score": score,
52
  "languages": languages,
53
  }
54
- return countries
 
 
2
  import xml.etree.ElementTree as ET
3
  from collections import defaultdict
4
 
5
+ import pandas as pd
6
  from language_data.population_data import LANGUAGE_SPEAKING_POPULATION
7
  from language_data.util import data_filename
8
 
 
38
  "name": lang.language_name,
39
  "bcp_47": lang.bcp_47,
40
  "population": speaker_pop,
41
+ "score": lang.average if not pd.isna(lang.average) else 0,
42
  }
43
  )
44
  for country, languages in countries.items():
 
51
  "score": score,
52
  "languages": languages,
53
  }
54
+ countries = [{"iso2": country, **data} for country, data in countries.items()]
55
+ return pd.DataFrame(countries)
evals/main.py CHANGED
@@ -2,8 +2,6 @@ import asyncio
2
  import json
3
 
4
  import numpy as np
5
- import pandas as pd
6
- from countries import make_country_table
7
  from languages import languages
8
  from models import model_fast, models
9
  from rich import print
@@ -38,128 +36,11 @@ async def evaluate():
38
  return await tqdm_asyncio.gather(*results, miniters=1)
39
 
40
 
41
- def aggregate(results):
42
- results = pd.DataFrame([r for rs in results for r in rs])
43
- results = (
44
- results.groupby(["model", "bcp_47", "task", "metric"]).mean().reset_index()
45
- )
46
- lang_results = (
47
- results.groupby(["bcp_47", "task", "metric"])
48
- .agg({"score": "mean", "model": "nunique"})
49
- .reset_index()
50
- )
51
- lang_results = pd.merge(languages, lang_results, on="bcp_47", how="outer")
52
- model_results = (
53
- results.groupby(["model", "task", "metric"])
54
- .agg({"score": "mean", "bcp_47": "nunique"})
55
- .reset_index()
56
- )
57
- task_results = (
58
- results.groupby(["task", "metric"])
59
- .agg({"score": "mean", "bcp_47": "nunique", "model": "nunique"})
60
- .reset_index()
61
- )
62
- return results, lang_results, model_results, task_results
63
-
64
-
65
- def mean(lst):
66
- return sum(lst) / len(lst) if lst else None
67
-
68
-
69
- def fmt_name(s):
70
- return (
71
- " ".join(w.capitalize() for w in s.split("-"))
72
- .replace("Gpt", "GPT")
73
- .replace("ai", "AI")
74
- )
75
-
76
-
77
- def serialize(df):
78
- return df.replace({np.nan: None}).to_dict(orient="records")
79
-
80
-
81
- def make_model_table(df):
82
- df["task_metric"] = df["task"] + "_" + df["metric"]
83
- df = df.drop(columns=["task", "metric"])
84
- task_metrics = df["task_metric"].unique()
85
- df = df.pivot(index="model", columns="task_metric", values="score").fillna(0)
86
- df["average"] = df[task_metrics].mean(axis=1)
87
- df = df.sort_values(by="average", ascending=False).reset_index()
88
- for row in [*task_metrics, "average"]:
89
- df[row] = df[row].round(2)
90
- df = pd.merge(df, models, left_on="model", right_on="id", how="left")
91
- df["creation_date"] = df["creation_date"].dt.strftime("%Y-%m-%d")
92
- df["provider"] = df["model"].str.split("/").str[0].apply(fmt_name)
93
- df["model"] = df["model"].str.split("/").str[1].apply(fmt_name)
94
- df["rank"] = df.index + 1
95
- df = df[
96
- [
97
- "rank",
98
- "provider",
99
- "model",
100
- "hf_id",
101
- "creation_date",
102
- "size",
103
- "type",
104
- "license",
105
- "average",
106
- *task_metrics,
107
- ]
108
- ]
109
- return df
110
-
111
-
112
- def make_language_table(df):
113
- df["task_metric"] = df["task"] + "_" + df["metric"]
114
- df = df.drop(columns=["task", "metric"])
115
- task_metrics = df["task_metric"].unique()
116
- df = (
117
- df.pivot(index="bcp_47", columns="task_metric", values="score")
118
- .fillna(0)
119
- .reset_index()
120
- )
121
- df["average"] = df[task_metrics].mean(axis=1)
122
- for row in [*task_metrics, "average"]:
123
- df[row] = df[row].round(2)
124
- df = pd.merge(languages, df, on="bcp_47", how="outer")
125
- df = df.sort_values(by="speakers", ascending=False)
126
- df = df[
127
- [
128
- "bcp_47",
129
- "language_name",
130
- "autonym",
131
- "speakers",
132
- "family",
133
- "average",
134
- "in_benchmark",
135
- *task_metrics,
136
- ]
137
- ]
138
- return df
139
-
140
 
141
  async def main():
142
  results = await evaluate()
143
- results, lang_results, model_results, task_results = aggregate(results)
144
- all_results = {
145
- "tasks": serialize(task_results),
146
- "models": serialize(model_results),
147
- "languages": serialize(lang_results),
148
- "scores": serialize(results),
149
- }
150
  with open("results.json", "w") as f:
151
- json.dump(all_results, f, indent=2, ensure_ascii=False)
152
-
153
- datasets_df = pd.read_json("data/datasets.json")
154
- language_table = make_language_table(lang_results)
155
- all_tables = {
156
- "model_table": serialize(make_model_table(model_results)),
157
- "language_table": serialize(language_table),
158
- "dataset_table": serialize(datasets_df),
159
- "countries": make_country_table(language_table),
160
- }
161
- with open("frontend/public/results.json", "w") as f:
162
- json.dump(all_tables, f, indent=2, ensure_ascii=False)
163
 
164
 
165
  if __name__ == "__main__":
 
2
  import json
3
 
4
  import numpy as np
 
 
5
  from languages import languages
6
  from models import model_fast, models
7
  from rich import print
 
36
  return await tqdm_asyncio.gather(*results, miniters=1)
37
 
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  async def main():
41
  results = await evaluate()
 
 
 
 
 
 
 
42
  with open("results.json", "w") as f:
43
+ json.dump(results, f, indent=2, ensure_ascii=False)
 
 
 
 
 
 
 
 
 
 
 
44
 
45
 
46
  if __name__ == "__main__":
evals/tables.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import pandas as pd
2
+ from countries import make_country_table
3
+
4
+ make_country_table = make_country_table
5
+
6
+
7
+ def aggregate(results):
8
+ results = pd.DataFrame([r for rs in results for r in rs])
9
+ results = (
10
+ results.groupby(["model", "bcp_47", "task", "metric"]).mean().reset_index()
11
+ )
12
+ lang_results = (
13
+ results.groupby(["bcp_47", "task", "metric"])
14
+ .agg({"score": "mean", "model": "nunique"})
15
+ .reset_index()
16
+ )
17
+ # lang_results = pd.merge(languages, lang_results, on="bcp_47", how="outer")
18
+ model_results = (
19
+ results.groupby(["model", "task", "metric"])
20
+ .agg({"score": "mean", "bcp_47": "nunique"})
21
+ .reset_index()
22
+ )
23
+ task_results = (
24
+ results.groupby(["task", "metric"])
25
+ .agg({"score": "mean", "bcp_47": "nunique", "model": "nunique"})
26
+ .reset_index()
27
+ )
28
+ return results, lang_results, model_results, task_results
29
+
30
+
31
+ def mean(lst):
32
+ return sum(lst) / len(lst) if lst else None
33
+
34
+
35
+ def fmt_name(s):
36
+ return (
37
+ " ".join(w.capitalize() for w in s.split("-"))
38
+ .replace("Gpt", "GPT")
39
+ .replace("ai", "AI")
40
+ )
41
+
42
+
43
+ def make_model_table(df, models):
44
+ df["task_metric"] = df["task"] + "_" + df["metric"]
45
+ df = df.drop(columns=["task", "metric"])
46
+ task_metrics = df["task_metric"].unique()
47
+ df = df.pivot(index="model", columns="task_metric", values="score").fillna(0)
48
+ df["average"] = df[task_metrics].mean(axis=1)
49
+ df = df.sort_values(by="average", ascending=False).reset_index()
50
+ for row in [*task_metrics, "average"]:
51
+ df[row] = df[row].round(2)
52
+ df = pd.merge(df, models, left_on="model", right_on="id", how="left")
53
+ df["creation_date"] = df["creation_date"].dt.strftime("%Y-%m-%d")
54
+ df["provider"] = df["model"].str.split("/").str[0].apply(fmt_name)
55
+ df["model"] = df["model"].str.split("/").str[1].apply(fmt_name)
56
+ df["rank"] = df.index + 1
57
+ df = df[
58
+ [
59
+ "rank",
60
+ "provider",
61
+ "model",
62
+ "hf_id",
63
+ "creation_date",
64
+ "size",
65
+ "type",
66
+ "license",
67
+ "average",
68
+ *task_metrics,
69
+ ]
70
+ ]
71
+ return df
72
+
73
+
74
+ def make_language_table(df, languages):
75
+ df["task_metric"] = df["task"] + "_" + df["metric"]
76
+ df = df.drop(columns=["task", "metric"])
77
+ task_metrics = df["task_metric"].unique()
78
+ df = (
79
+ df.pivot(index="bcp_47", columns="task_metric", values="score")
80
+ .fillna(0)
81
+ .reset_index()
82
+ )
83
+ df["average"] = df[task_metrics].mean(axis=1)
84
+ for row in [*task_metrics, "average"]:
85
+ df[row] = df[row].round(2)
86
+ df = pd.merge(languages, df, on="bcp_47", how="outer")
87
+ df = df.sort_values(by="speakers", ascending=False)
88
+ df = df[
89
+ [
90
+ "bcp_47",
91
+ "language_name",
92
+ "autonym",
93
+ "speakers",
94
+ "family",
95
+ "average",
96
+ "in_benchmark",
97
+ *task_metrics,
98
+ ]
99
+ ]
100
+ return df
frontend/package.json CHANGED
@@ -40,5 +40,6 @@
40
  "last 1 firefox version",
41
  "last 1 safari version"
42
  ]
43
- }
 
44
  }
 
40
  "last 1 firefox version",
41
  "last 1 safari version"
42
  ]
43
+ },
44
+ "proxy": "http://localhost:8000"
45
  }
frontend/public/results.json DELETED
The diff for this file is too large to render. See raw diff
 
frontend/src/App.js CHANGED
@@ -26,7 +26,10 @@ function App () {
26
  size: { value: null, matchMode: FilterMatchMode.BETWEEN }
27
  })
28
  useEffect(() => {
29
- fetch('/results.json')
 
 
 
30
  .then(response => {
31
  if (!response.ok) {
32
  throw new Error('Network response was not ok')
@@ -41,7 +44,7 @@ function App () {
41
  setError(err.message)
42
  setLoading(false)
43
  })
44
- }, [])
45
 
46
  useEffect(() => {
47
  if (data) {
@@ -150,7 +153,7 @@ function App () {
150
  }}
151
  >
152
  <ModelTable
153
- data={data}
154
  filters={modelFilters}
155
  setFilters={setModelFilters}
156
  />
@@ -162,7 +165,7 @@ function App () {
162
  }}
163
  >
164
  <LanguageTable
165
- data={data}
166
  filters={languageFilters}
167
  setFilters={setLanguageFilters}
168
  />
 
26
  size: { value: null, matchMode: FilterMatchMode.BETWEEN }
27
  })
28
  useEffect(() => {
29
+ fetch('/api/data', {
30
+ method: 'POST',
31
+ // body: JSON.stringify({ modelFilters, languageFilters }),
32
+ })
33
  .then(response => {
34
  if (!response.ok) {
35
  throw new Error('Network response was not ok')
 
44
  setError(err.message)
45
  setLoading(false)
46
  })
47
+ }, [modelFilters, languageFilters])
48
 
49
  useEffect(() => {
50
  if (data) {
 
153
  }}
154
  >
155
  <ModelTable
156
+ data={data.model_table}
157
  filters={modelFilters}
158
  setFilters={setModelFilters}
159
  />
 
165
  }}
166
  >
167
  <LanguageTable
168
+ data={data.language_table}
169
  filters={languageFilters}
170
  setFilters={setLanguageFilters}
171
  />
frontend/src/components/LanguageTable.js CHANGED
@@ -7,9 +7,7 @@ import { Slider } from 'primereact/slider'
7
  import ScoreField from './ScoreField'
8
 
9
  const LanguageTable = ({ data, filters, setFilters }) => {
10
- const table = data.language_table
11
-
12
- const families = [...new Set(table.map(item => item.family))].slice(0, 10)
13
  families.push("Other")
14
  const familyRowFilterTemplate = options => {
15
  return (
@@ -120,7 +118,7 @@ const LanguageTable = ({ data, filters, setFilters }) => {
120
 
121
  return (
122
  <DataTable
123
- value={table}
124
  header={<>Languages</>}
125
  sortField='speakers'
126
  removableSort
 
7
  import ScoreField from './ScoreField'
8
 
9
  const LanguageTable = ({ data, filters, setFilters }) => {
10
+ const families = [...new Set(data.map(item => item.family))].slice(0, 10)
 
 
11
  families.push("Other")
12
  const familyRowFilterTemplate = options => {
13
  return (
 
118
 
119
  return (
120
  <DataTable
121
+ value={data}
122
  header={<>Languages</>}
123
  sortField='speakers'
124
  removableSort
frontend/src/components/ModelTable.js CHANGED
@@ -8,7 +8,6 @@ import { Slider } from 'primereact/slider'
8
  import ScoreField from './ScoreField'
9
 
10
  const ModelTable = ({ data, filters, setFilters }) => {
11
- const table = data.model_table
12
  const rankBodyTemplate = rowData => {
13
  return <Medal rank={rowData.rank} />
14
  }
@@ -125,7 +124,7 @@ const ModelTable = ({ data, filters, setFilters }) => {
125
 
126
  return (
127
  <DataTable
128
- value={table}
129
  header={<>AI Models</>}
130
  sortField='average'
131
  removableSort
 
8
  import ScoreField from './ScoreField'
9
 
10
  const ModelTable = ({ data, filters, setFilters }) => {
 
11
  const rankBodyTemplate = rowData => {
12
  return <Medal rank={rowData.rank} />
13
  }
 
124
 
125
  return (
126
  <DataTable
127
+ value={data}
128
  header={<>AI Models</>}
129
  sortField='average'
130
  removableSort
pyproject.toml CHANGED
@@ -5,12 +5,10 @@ description = "Add your description here"
5
  readme = "README.md"
6
  requires-python = ">=3.10"
7
  dependencies = [
8
- "gradio-rangeslider>=0.0.8",
9
- "gradio>=5.16.2",
10
- "language-data>=1.3.0",
11
  "pandas>=2.2.3",
12
- "plotly>=6.0.0",
13
- "pycountry>=24.6.1",
14
  ]
15
 
16
  [tool.uv]
@@ -23,6 +21,7 @@ dev-dependencies = [
23
  "jiwer>=3.1.0",
24
  "joblib>=1.4.2",
25
  "langcodes>=3.5.0",
 
26
  "openai>=1.52.2",
27
  "protobuf>=5.28.3",
28
  "python-dotenv>=1.0.1",
 
5
  readme = "README.md"
6
  requires-python = ">=3.10"
7
  dependencies = [
8
+ "fastapi>=0.115.8",
9
+ "uvicorn>=0.34.0",
 
10
  "pandas>=2.2.3",
11
+ "numpy>=2.1.2",
 
12
  ]
13
 
14
  [tool.uv]
 
21
  "jiwer>=3.1.0",
22
  "joblib>=1.4.2",
23
  "langcodes>=3.5.0",
24
+ "language-data>=1.3.0",
25
  "openai>=1.52.2",
26
  "protobuf>=5.28.3",
27
  "python-dotenv>=1.0.1",
results.json CHANGED
The diff for this file is too large to render. See raw diff
 
uv.lock CHANGED
@@ -7,15 +7,6 @@ resolution-markers = [
7
  "python_full_version >= '3.13'",
8
  ]
9
 
10
- [[package]]
11
- name = "aiofiles"
12
- version = "23.2.1"
13
- source = { registry = "https://pypi.org/simple" }
14
- sdist = { url = "https://files.pythonhosted.org/packages/af/41/cfed10bc64d774f497a86e5ede9248e1d062db675504b41c320954d99641/aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a", size = 32072 }
15
- wheels = [
16
- { url = "https://files.pythonhosted.org/packages/c5/19/5af6804c4cc0fed83f47bff6e413a98a36618e7d40185cd36e69737f3b0e/aiofiles-23.2.1-py3-none-any.whl", hash = "sha256:19297512c647d4b27a2cf7c34caa7e405c0d60b5560618a29a9fe027b18b0107", size = 15727 },
17
- ]
18
-
19
  [[package]]
20
  name = "aiohappyeyeballs"
21
  version = "2.4.3"
@@ -165,46 +156,6 @@ wheels = [
165
  { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 },
166
  ]
167
 
168
- [[package]]
169
- name = "audioop-lts"
170
- version = "0.2.1"
171
- source = { registry = "https://pypi.org/simple" }
172
- sdist = { url = "https://files.pythonhosted.org/packages/dd/3b/69ff8a885e4c1c42014c2765275c4bd91fe7bc9847e9d8543dbcbb09f820/audioop_lts-0.2.1.tar.gz", hash = "sha256:e81268da0baa880431b68b1308ab7257eb33f356e57a5f9b1f915dfb13dd1387", size = 30204 }
173
- wheels = [
174
- { url = "https://files.pythonhosted.org/packages/01/91/a219253cc6e92db2ebeaf5cf8197f71d995df6f6b16091d1f3ce62cb169d/audioop_lts-0.2.1-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd1345ae99e17e6910f47ce7d52673c6a1a70820d78b67de1b7abb3af29c426a", size = 46252 },
175
- { url = "https://files.pythonhosted.org/packages/ec/f6/3cb21e0accd9e112d27cee3b1477cd04dafe88675c54ad8b0d56226c1e0b/audioop_lts-0.2.1-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:e175350da05d2087e12cea8e72a70a1a8b14a17e92ed2022952a4419689ede5e", size = 27183 },
176
- { url = "https://files.pythonhosted.org/packages/ea/7e/f94c8a6a8b2571694375b4cf94d3e5e0f529e8e6ba280fad4d8c70621f27/audioop_lts-0.2.1-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:4a8dd6a81770f6ecf019c4b6d659e000dc26571b273953cef7cd1d5ce2ff3ae6", size = 26726 },
177
- { url = "https://files.pythonhosted.org/packages/ef/f8/a0e8e7a033b03fae2b16bc5aa48100b461c4f3a8a38af56d5ad579924a3a/audioop_lts-0.2.1-cp313-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cd3c0b6f2ca25c7d2b1c3adeecbe23e65689839ba73331ebc7d893fcda7ffe", size = 80718 },
178
- { url = "https://files.pythonhosted.org/packages/8f/ea/a98ebd4ed631c93b8b8f2368862cd8084d75c77a697248c24437c36a6f7e/audioop_lts-0.2.1-cp313-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff3f97b3372c97782e9c6d3d7fdbe83bce8f70de719605bd7ee1839cd1ab360a", size = 88326 },
179
- { url = "https://files.pythonhosted.org/packages/33/79/e97a9f9daac0982aa92db1199339bd393594d9a4196ad95ae088635a105f/audioop_lts-0.2.1-cp313-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a351af79edefc2a1bd2234bfd8b339935f389209943043913a919df4b0f13300", size = 80539 },
180
- { url = "https://files.pythonhosted.org/packages/b2/d3/1051d80e6f2d6f4773f90c07e73743a1e19fcd31af58ff4e8ef0375d3a80/audioop_lts-0.2.1-cp313-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2aeb6f96f7f6da80354330470b9134d81b4cf544cdd1c549f2f45fe964d28059", size = 78577 },
181
- { url = "https://files.pythonhosted.org/packages/7a/1d/54f4c58bae8dc8c64a75071c7e98e105ddaca35449376fcb0180f6e3c9df/audioop_lts-0.2.1-cp313-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c589f06407e8340e81962575fcffbba1e92671879a221186c3d4662de9fe804e", size = 82074 },
182
- { url = "https://files.pythonhosted.org/packages/36/89/2e78daa7cebbea57e72c0e1927413be4db675548a537cfba6a19040d52fa/audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:fbae5d6925d7c26e712f0beda5ed69ebb40e14212c185d129b8dfbfcc335eb48", size = 84210 },
183
- { url = "https://files.pythonhosted.org/packages/a5/57/3ff8a74df2ec2fa6d2ae06ac86e4a27d6412dbb7d0e0d41024222744c7e0/audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_i686.whl", hash = "sha256:d2d5434717f33117f29b5691fbdf142d36573d751716249a288fbb96ba26a281", size = 85664 },
184
- { url = "https://files.pythonhosted.org/packages/16/01/21cc4e5878f6edbc8e54be4c108d7cb9cb6202313cfe98e4ece6064580dd/audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:f626a01c0a186b08f7ff61431c01c055961ee28769591efa8800beadd27a2959", size = 93255 },
185
- { url = "https://files.pythonhosted.org/packages/3e/28/7f7418c362a899ac3b0bf13b1fde2d4ffccfdeb6a859abd26f2d142a1d58/audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:05da64e73837f88ee5c6217d732d2584cf638003ac72df124740460531e95e47", size = 87760 },
186
- { url = "https://files.pythonhosted.org/packages/6d/d8/577a8be87dc7dd2ba568895045cee7d32e81d85a7e44a29000fe02c4d9d4/audioop_lts-0.2.1-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:56b7a0a4dba8e353436f31a932f3045d108a67b5943b30f85a5563f4d8488d77", size = 84992 },
187
- { url = "https://files.pythonhosted.org/packages/ef/9a/4699b0c4fcf89936d2bfb5425f55f1a8b86dff4237cfcc104946c9cd9858/audioop_lts-0.2.1-cp313-abi3-win32.whl", hash = "sha256:6e899eb8874dc2413b11926b5fb3857ec0ab55222840e38016a6ba2ea9b7d5e3", size = 26059 },
188
- { url = "https://files.pythonhosted.org/packages/3a/1c/1f88e9c5dd4785a547ce5fd1eb83fff832c00cc0e15c04c1119b02582d06/audioop_lts-0.2.1-cp313-abi3-win_amd64.whl", hash = "sha256:64562c5c771fb0a8b6262829b9b4f37a7b886c01b4d3ecdbae1d629717db08b4", size = 30412 },
189
- { url = "https://files.pythonhosted.org/packages/c4/e9/c123fd29d89a6402ad261516f848437472ccc602abb59bba522af45e281b/audioop_lts-0.2.1-cp313-abi3-win_arm64.whl", hash = "sha256:c45317debeb64002e980077642afbd977773a25fa3dfd7ed0c84dccfc1fafcb0", size = 23578 },
190
- { url = "https://files.pythonhosted.org/packages/7a/99/bb664a99561fd4266687e5cb8965e6ec31ba4ff7002c3fce3dc5ef2709db/audioop_lts-0.2.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:3827e3fce6fee4d69d96a3d00cd2ab07f3c0d844cb1e44e26f719b34a5b15455", size = 46827 },
191
- { url = "https://files.pythonhosted.org/packages/c4/e3/f664171e867e0768ab982715e744430cf323f1282eb2e11ebfb6ee4c4551/audioop_lts-0.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:161249db9343b3c9780ca92c0be0d1ccbfecdbccac6844f3d0d44b9c4a00a17f", size = 27479 },
192
- { url = "https://files.pythonhosted.org/packages/a6/0d/2a79231ff54eb20e83b47e7610462ad6a2bea4e113fae5aa91c6547e7764/audioop_lts-0.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5b7b4ff9de7a44e0ad2618afdc2ac920b91f4a6d3509520ee65339d4acde5abf", size = 27056 },
193
- { url = "https://files.pythonhosted.org/packages/86/46/342471398283bb0634f5a6df947806a423ba74b2e29e250c7ec0e3720e4f/audioop_lts-0.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72e37f416adb43b0ced93419de0122b42753ee74e87070777b53c5d2241e7fab", size = 87802 },
194
- { url = "https://files.pythonhosted.org/packages/56/44/7a85b08d4ed55517634ff19ddfbd0af05bf8bfd39a204e4445cd0e6f0cc9/audioop_lts-0.2.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:534ce808e6bab6adb65548723c8cbe189a3379245db89b9d555c4210b4aaa9b6", size = 95016 },
195
- { url = "https://files.pythonhosted.org/packages/a8/2a/45edbca97ea9ee9e6bbbdb8d25613a36e16a4d1e14ae01557392f15cc8d3/audioop_lts-0.2.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2de9b6fb8b1cf9f03990b299a9112bfdf8b86b6987003ca9e8a6c4f56d39543", size = 87394 },
196
- { url = "https://files.pythonhosted.org/packages/14/ae/832bcbbef2c510629593bf46739374174606e25ac7d106b08d396b74c964/audioop_lts-0.2.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f24865991b5ed4b038add5edbf424639d1358144f4e2a3e7a84bc6ba23e35074", size = 84874 },
197
- { url = "https://files.pythonhosted.org/packages/26/1c/8023c3490798ed2f90dfe58ec3b26d7520a243ae9c0fc751ed3c9d8dbb69/audioop_lts-0.2.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bdb3b7912ccd57ea53197943f1bbc67262dcf29802c4a6df79ec1c715d45a78", size = 88698 },
198
- { url = "https://files.pythonhosted.org/packages/2c/db/5379d953d4918278b1f04a5a64b2c112bd7aae8f81021009da0dcb77173c/audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:120678b208cca1158f0a12d667af592e067f7a50df9adc4dc8f6ad8d065a93fb", size = 90401 },
199
- { url = "https://files.pythonhosted.org/packages/99/6e/3c45d316705ab1aec2e69543a5b5e458d0d112a93d08994347fafef03d50/audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:54cd4520fc830b23c7d223693ed3e1b4d464997dd3abc7c15dce9a1f9bd76ab2", size = 91864 },
200
- { url = "https://files.pythonhosted.org/packages/08/58/6a371d8fed4f34debdb532c0b00942a84ebf3e7ad368e5edc26931d0e251/audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:d6bd20c7a10abcb0fb3d8aaa7508c0bf3d40dfad7515c572014da4b979d3310a", size = 98796 },
201
- { url = "https://files.pythonhosted.org/packages/ee/77/d637aa35497e0034ff846fd3330d1db26bc6fd9dd79c406e1341188b06a2/audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:f0ed1ad9bd862539ea875fb339ecb18fcc4148f8d9908f4502df28f94d23491a", size = 94116 },
202
- { url = "https://files.pythonhosted.org/packages/1a/60/7afc2abf46bbcf525a6ebc0305d85ab08dc2d1e2da72c48dbb35eee5b62c/audioop_lts-0.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e1af3ff32b8c38a7d900382646e91f2fc515fd19dea37e9392275a5cbfdbff63", size = 91520 },
203
- { url = "https://files.pythonhosted.org/packages/65/6d/42d40da100be1afb661fd77c2b1c0dfab08af1540df57533621aea3db52a/audioop_lts-0.2.1-cp313-cp313t-win32.whl", hash = "sha256:f51bb55122a89f7a0817d7ac2319744b4640b5b446c4c3efcea5764ea99ae509", size = 26482 },
204
- { url = "https://files.pythonhosted.org/packages/01/09/f08494dca79f65212f5b273aecc5a2f96691bf3307cac29acfcf84300c01/audioop_lts-0.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:f0f2f336aa2aee2bce0b0dcc32bbba9178995454c7b979cf6ce086a8801e14c7", size = 30780 },
205
- { url = "https://files.pythonhosted.org/packages/5d/35/be73b6015511aa0173ec595fc579133b797ad532996f2998fd6b8d1bbe6b/audioop_lts-0.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:78bfb3703388c780edf900be66e07de5a3d4105ca8e8720c5c4d67927e0b15d0", size = 23918 },
206
- ]
207
-
208
  [[package]]
209
  name = "bert-score"
210
  version = "0.3.13"
@@ -500,15 +451,6 @@ wheels = [
500
  { url = "https://files.pythonhosted.org/packages/8f/7d/2d6ce181d7a5f51dedb8c06206cbf0ec026a99bf145edd309f9e17c3282f/fastapi-0.115.8-py3-none-any.whl", hash = "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf", size = 94814 },
501
  ]
502
 
503
- [[package]]
504
- name = "ffmpy"
505
- version = "0.5.0"
506
- source = { registry = "https://pypi.org/simple" }
507
- sdist = { url = "https://files.pythonhosted.org/packages/4d/66/5697a7421c418ccbfae87b7e6503b480070f7cb16c25c77201afc6246348/ffmpy-0.5.0.tar.gz", hash = "sha256:277e131f246d18e9dcfee9bb514c50749031c43582ce5ef82c57b51e3d3955c3", size = 5523 }
508
- wheels = [
509
- { url = "https://files.pythonhosted.org/packages/53/5d/65f40bd333463b3230b3a72d93873caaf49b0cbb5228598fafb75fcc5357/ffmpy-0.5.0-py3-none-any.whl", hash = "sha256:df3799cf5816daa56d4959a023630ee53c6768b66009dae6d131519ba4b80233", size = 6008 },
510
- ]
511
-
512
  [[package]]
513
  name = "filelock"
514
  version = "3.16.1"
@@ -640,73 +582,6 @@ http = [
640
  { name = "aiohttp" },
641
  ]
642
 
643
- [[package]]
644
- name = "gradio"
645
- version = "5.16.2"
646
- source = { registry = "https://pypi.org/simple" }
647
- dependencies = [
648
- { name = "aiofiles" },
649
- { name = "anyio" },
650
- { name = "audioop-lts", marker = "python_full_version >= '3.13'" },
651
- { name = "fastapi" },
652
- { name = "ffmpy" },
653
- { name = "gradio-client" },
654
- { name = "httpx" },
655
- { name = "huggingface-hub" },
656
- { name = "jinja2" },
657
- { name = "markupsafe" },
658
- { name = "numpy" },
659
- { name = "orjson" },
660
- { name = "packaging" },
661
- { name = "pandas" },
662
- { name = "pillow" },
663
- { name = "pydantic" },
664
- { name = "pydub" },
665
- { name = "python-multipart" },
666
- { name = "pyyaml" },
667
- { name = "ruff", marker = "sys_platform != 'emscripten'" },
668
- { name = "safehttpx" },
669
- { name = "semantic-version" },
670
- { name = "starlette", marker = "sys_platform != 'emscripten'" },
671
- { name = "tomlkit" },
672
- { name = "typer", marker = "sys_platform != 'emscripten'" },
673
- { name = "typing-extensions" },
674
- { name = "urllib3", marker = "sys_platform == 'emscripten'" },
675
- { name = "uvicorn", marker = "sys_platform != 'emscripten'" },
676
- ]
677
- wheels = [
678
- { url = "https://files.pythonhosted.org/packages/3a/1b/bd78e5d128589f28dfe76ddd587702489fabb58bdd3fbc6d09b16e5d948a/gradio-5.16.2-py3-none-any.whl", hash = "sha256:b13180c9a0a7370bdda6a326d85f659768ba97a822a7d5790b52ae4c6bccc343", size = 62206160 },
679
- ]
680
-
681
- [[package]]
682
- name = "gradio-client"
683
- version = "1.7.1"
684
- source = { registry = "https://pypi.org/simple" }
685
- dependencies = [
686
- { name = "fsspec" },
687
- { name = "httpx" },
688
- { name = "huggingface-hub" },
689
- { name = "packaging" },
690
- { name = "typing-extensions" },
691
- { name = "websockets" },
692
- ]
693
- sdist = { url = "https://files.pythonhosted.org/packages/f2/98/434f4eff6eabf625e71ac69a5909864984b53b2f2c9e3a9c772bebbfae84/gradio_client-1.7.1.tar.gz", hash = "sha256:6ecd3a537c6c076cb1b351c2d7ce5906070d2e1b3181163609bfa4a4c4f3040e", size = 320142 }
694
- wheels = [
695
- { url = "https://files.pythonhosted.org/packages/16/52/4fe9dfc2239e7b748ad8dc3b80ad8755f5c9378432715193586c3ab74bf9/gradio_client-1.7.1-py3-none-any.whl", hash = "sha256:d7737bc473a2093549c06004379c42f0a3510a98095cf7cea9033837e252149f", size = 321994 },
696
- ]
697
-
698
- [[package]]
699
- name = "gradio-rangeslider"
700
- version = "0.0.8"
701
- source = { registry = "https://pypi.org/simple" }
702
- dependencies = [
703
- { name = "gradio" },
704
- ]
705
- sdist = { url = "https://files.pythonhosted.org/packages/88/93/aa1723076cc1056279e43f46d804f663c794f2e098c0650d150b46372f62/gradio_rangeslider-0.0.8.tar.gz", hash = "sha256:414fd4b093d4327cc86c51b4e81e53df19664023f95bed95e3ecc03071fa1ea0", size = 1263683 }
706
- wheels = [
707
- { url = "https://files.pythonhosted.org/packages/54/44/14f759678a76ffbd6e3fe8852a4f758bc5ad51b379c67b5d167cfde752f6/gradio_rangeslider-0.0.8-py3-none-any.whl", hash = "sha256:3728c44e58ec1bff0bdf236cc84f12b183fbd596fb4714d8b797585a0515f89e", size = 1224388 },
708
- ]
709
-
710
  [[package]]
711
  name = "h11"
712
  version = "0.14.0"
@@ -969,12 +844,10 @@ name = "languagebench"
969
  version = "0.1.0"
970
  source = { virtual = "." }
971
  dependencies = [
972
- { name = "gradio" },
973
- { name = "gradio-rangeslider" },
974
- { name = "language-data" },
975
  { name = "pandas" },
976
- { name = "plotly" },
977
- { name = "pycountry" },
978
  ]
979
 
980
  [package.dev-dependencies]
@@ -987,6 +860,7 @@ dev = [
987
  { name = "jiwer" },
988
  { name = "joblib" },
989
  { name = "langcodes" },
 
990
  { name = "openai" },
991
  { name = "protobuf" },
992
  { name = "python-dotenv" },
@@ -999,12 +873,10 @@ dev = [
999
 
1000
  [package.metadata]
1001
  requires-dist = [
1002
- { name = "gradio", specifier = ">=5.16.2" },
1003
- { name = "gradio-rangeslider", specifier = ">=0.0.8" },
1004
- { name = "language-data", specifier = ">=1.3.0" },
1005
  { name = "pandas", specifier = ">=2.2.3" },
1006
- { name = "plotly", specifier = ">=6.0.0" },
1007
- { name = "pycountry", specifier = ">=24.6.1" },
1008
  ]
1009
 
1010
  [package.metadata.requires-dev]
@@ -1017,6 +889,7 @@ dev = [
1017
  { name = "jiwer", specifier = ">=3.1.0" },
1018
  { name = "joblib", specifier = ">=1.4.2" },
1019
  { name = "langcodes", specifier = ">=3.5.0" },
 
1020
  { name = "openai", specifier = ">=1.52.2" },
1021
  { name = "protobuf", specifier = ">=5.28.3" },
1022
  { name = "python-dotenv", specifier = ">=1.0.1" },
@@ -1164,18 +1037,6 @@ wheels = [
1164
  { url = "https://files.pythonhosted.org/packages/27/40/5f9eb8b73030cc4b0d6817176e66079a62a2ddd9d5530da54f8011473428/marisa_trie-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:aa7cd17e1c690ce96c538b2f4aae003d9a498e65067dd433c52dd069009951d4", size = 149035 },
1165
  ]
1166
 
1167
- [[package]]
1168
- name = "markdown-it-py"
1169
- version = "3.0.0"
1170
- source = { registry = "https://pypi.org/simple" }
1171
- dependencies = [
1172
- { name = "mdurl" },
1173
- ]
1174
- sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
1175
- wheels = [
1176
- { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
1177
- ]
1178
-
1179
  [[package]]
1180
  name = "markupsafe"
1181
  version = "2.1.5"
@@ -1262,15 +1123,6 @@ wheels = [
1262
  { url = "https://files.pythonhosted.org/packages/01/8a/760f7fce66b39f447ad160800619d0bd5d0936d2b4633587116534a4afe0/matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", size = 9093770 },
1263
  ]
1264
 
1265
- [[package]]
1266
- name = "mdurl"
1267
- version = "0.1.2"
1268
- source = { registry = "https://pypi.org/simple" }
1269
- sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
1270
- wheels = [
1271
- { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
1272
- ]
1273
-
1274
  [[package]]
1275
  name = "mpmath"
1276
  version = "1.3.0"
@@ -1370,15 +1222,6 @@ wheels = [
1370
  { url = "https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", size = 133351 },
1371
  ]
1372
 
1373
- [[package]]
1374
- name = "narwhals"
1375
- version = "1.27.1"
1376
- source = { registry = "https://pypi.org/simple" }
1377
- sdist = { url = "https://files.pythonhosted.org/packages/5a/d6/1dadff863b95e4ec74eaba7979278e446699532136c74183a398778b1949/narwhals-1.27.1.tar.gz", hash = "sha256:68505d0cee1e6c00382ac8b65e922f8b694a11cbe482a057fa63139de8d0ea03", size = 251670 }
1378
- wheels = [
1379
- { url = "https://files.pythonhosted.org/packages/ed/ea/dc14822a0a75e027562f081eb638417b1b7845e1e01dd85c5b6573ebf1b2/narwhals-1.27.1-py3-none-any.whl", hash = "sha256:71e4a126007886e3dd9d71d0d5921ebd2e8c1f9be9c405fe11850ece2b066c59", size = 308837 },
1380
- ]
1381
-
1382
  [[package]]
1383
  name = "networkx"
1384
  version = "3.4.2"
@@ -1587,66 +1430,6 @@ wheels = [
1587
  { url = "https://files.pythonhosted.org/packages/55/4c/906b5b32c4c01402ac3b4c3fc28f601443ac5c6f13c84a95dd178c8d545d/openai-1.52.2-py3-none-any.whl", hash = "sha256:57e9e37bc407f39bb6ec3a27d7e8fb9728b2779936daa1fcf95df17d3edfaccc", size = 386947 },
1588
  ]
1589
 
1590
- [[package]]
1591
- name = "orjson"
1592
- version = "3.10.15"
1593
- source = { registry = "https://pypi.org/simple" }
1594
- sdist = { url = "https://files.pythonhosted.org/packages/ae/f9/5dea21763eeff8c1590076918a446ea3d6140743e0e36f58f369928ed0f4/orjson-3.10.15.tar.gz", hash = "sha256:05ca7fe452a2e9d8d9d706a2984c95b9c2ebc5db417ce0b7a49b91d50642a23e", size = 5282482 }
1595
- wheels = [
1596
- { url = "https://files.pythonhosted.org/packages/52/09/e5ff18ad009e6f97eb7edc5f67ef98b3ce0c189da9c3eaca1f9587cd4c61/orjson-3.10.15-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:552c883d03ad185f720d0c09583ebde257e41b9521b74ff40e08b7dec4559c04", size = 249532 },
1597
- { url = "https://files.pythonhosted.org/packages/bd/b8/a75883301fe332bd433d9b0ded7d2bb706ccac679602c3516984f8814fb5/orjson-3.10.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:616e3e8d438d02e4854f70bfdc03a6bcdb697358dbaa6bcd19cbe24d24ece1f8", size = 125229 },
1598
- { url = "https://files.pythonhosted.org/packages/83/4b/22f053e7a364cc9c685be203b1e40fc5f2b3f164a9b2284547504eec682e/orjson-3.10.15-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c2c79fa308e6edb0ffab0a31fd75a7841bf2a79a20ef08a3c6e3b26814c8ca8", size = 150148 },
1599
- { url = "https://files.pythonhosted.org/packages/63/64/1b54fc75ca328b57dd810541a4035fe48c12a161d466e3cf5b11a8c25649/orjson-3.10.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cb85490aa6bf98abd20607ab5c8324c0acb48d6da7863a51be48505646c814", size = 139748 },
1600
- { url = "https://files.pythonhosted.org/packages/5e/ff/ff0c5da781807bb0a5acd789d9a7fbcb57f7b0c6e1916595da1f5ce69f3c/orjson-3.10.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763dadac05e4e9d2bc14938a45a2d0560549561287d41c465d3c58aec818b164", size = 154559 },
1601
- { url = "https://files.pythonhosted.org/packages/4e/9a/11e2974383384ace8495810d4a2ebef5f55aacfc97b333b65e789c9d362d/orjson-3.10.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a330b9b4734f09a623f74a7490db713695e13b67c959713b78369f26b3dee6bf", size = 130349 },
1602
- { url = "https://files.pythonhosted.org/packages/2d/c4/dd9583aea6aefee1b64d3aed13f51d2aadb014028bc929fe52936ec5091f/orjson-3.10.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a61a4622b7ff861f019974f73d8165be1bd9a0855e1cad18ee167acacabeb061", size = 138514 },
1603
- { url = "https://files.pythonhosted.org/packages/53/3e/dcf1729230654f5c5594fc752de1f43dcf67e055ac0d300c8cdb1309269a/orjson-3.10.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:acd271247691574416b3228db667b84775c497b245fa275c6ab90dc1ffbbd2b3", size = 130940 },
1604
- { url = "https://files.pythonhosted.org/packages/e8/2b/b9759fe704789937705c8a56a03f6c03e50dff7df87d65cba9a20fec5282/orjson-3.10.15-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4759b109c37f635aa5c5cc93a1b26927bfde24b254bcc0e1149a9fada253d2d", size = 414713 },
1605
- { url = "https://files.pythonhosted.org/packages/a7/6b/b9dfdbd4b6e20a59238319eb203ae07c3f6abf07eef909169b7a37ae3bba/orjson-3.10.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e992fd5cfb8b9f00bfad2fd7a05a4299db2bbe92e6440d9dd2fab27655b3182", size = 141028 },
1606
- { url = "https://files.pythonhosted.org/packages/7c/b5/40f5bbea619c7caf75eb4d652a9821875a8ed04acc45fe3d3ef054ca69fb/orjson-3.10.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f95fb363d79366af56c3f26b71df40b9a583b07bbaaf5b317407c4d58497852e", size = 129715 },
1607
- { url = "https://files.pythonhosted.org/packages/38/60/2272514061cbdf4d672edbca6e59c7e01cd1c706e881427d88f3c3e79761/orjson-3.10.15-cp310-cp310-win32.whl", hash = "sha256:f9875f5fea7492da8ec2444839dcc439b0ef298978f311103d0b7dfd775898ab", size = 142473 },
1608
- { url = "https://files.pythonhosted.org/packages/11/5d/be1490ff7eafe7fef890eb4527cf5bcd8cfd6117f3efe42a3249ec847b60/orjson-3.10.15-cp310-cp310-win_amd64.whl", hash = "sha256:17085a6aa91e1cd70ca8533989a18b5433e15d29c574582f76f821737c8d5806", size = 133564 },
1609
- { url = "https://files.pythonhosted.org/packages/7a/a2/21b25ce4a2c71dbb90948ee81bd7a42b4fbfc63162e57faf83157d5540ae/orjson-3.10.15-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c4cc83960ab79a4031f3119cc4b1a1c627a3dc09df125b27c4201dff2af7eaa6", size = 249533 },
1610
- { url = "https://files.pythonhosted.org/packages/b2/85/2076fc12d8225698a51278009726750c9c65c846eda741e77e1761cfef33/orjson-3.10.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddbeef2481d895ab8be5185f2432c334d6dec1f5d1933a9c83014d188e102cef", size = 125230 },
1611
- { url = "https://files.pythonhosted.org/packages/06/df/a85a7955f11274191eccf559e8481b2be74a7c6d43075d0a9506aa80284d/orjson-3.10.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9e590a0477b23ecd5b0ac865b1b907b01b3c5535f5e8a8f6ab0e503efb896334", size = 150148 },
1612
- { url = "https://files.pythonhosted.org/packages/37/b3/94c55625a29b8767c0eed194cb000b3787e3c23b4cdd13be17bae6ccbb4b/orjson-3.10.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6be38bd103d2fd9bdfa31c2720b23b5d47c6796bcb1d1b598e3924441b4298d", size = 139749 },
1613
- { url = "https://files.pythonhosted.org/packages/53/ba/c608b1e719971e8ddac2379f290404c2e914cf8e976369bae3cad88768b1/orjson-3.10.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff4f6edb1578960ed628a3b998fa54d78d9bb3e2eb2cfc5c2a09732431c678d0", size = 154558 },
1614
- { url = "https://files.pythonhosted.org/packages/b2/c4/c1fb835bb23ad788a39aa9ebb8821d51b1c03588d9a9e4ca7de5b354fdd5/orjson-3.10.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0482b21d0462eddd67e7fce10b89e0b6ac56570424662b685a0d6fccf581e13", size = 130349 },
1615
- { url = "https://files.pythonhosted.org/packages/78/14/bb2b48b26ab3c570b284eb2157d98c1ef331a8397f6c8bd983b270467f5c/orjson-3.10.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bb5cc3527036ae3d98b65e37b7986a918955f85332c1ee07f9d3f82f3a6899b5", size = 138513 },
1616
- { url = "https://files.pythonhosted.org/packages/4a/97/d5b353a5fe532e92c46467aa37e637f81af8468aa894cd77d2ec8a12f99e/orjson-3.10.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d569c1c462912acdd119ccbf719cf7102ea2c67dd03b99edcb1a3048651ac96b", size = 130942 },
1617
- { url = "https://files.pythonhosted.org/packages/b5/5d/a067bec55293cca48fea8b9928cfa84c623be0cce8141d47690e64a6ca12/orjson-3.10.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:1e6d33efab6b71d67f22bf2962895d3dc6f82a6273a965fab762e64fa90dc399", size = 414717 },
1618
- { url = "https://files.pythonhosted.org/packages/6f/9a/1485b8b05c6b4c4db172c438cf5db5dcfd10e72a9bc23c151a1137e763e0/orjson-3.10.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c33be3795e299f565681d69852ac8c1bc5c84863c0b0030b2b3468843be90388", size = 141033 },
1619
- { url = "https://files.pythonhosted.org/packages/f8/d2/fc67523656e43a0c7eaeae9007c8b02e86076b15d591e9be11554d3d3138/orjson-3.10.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:eea80037b9fae5339b214f59308ef0589fc06dc870578b7cce6d71eb2096764c", size = 129720 },
1620
- { url = "https://files.pythonhosted.org/packages/79/42/f58c7bd4e5b54da2ce2ef0331a39ccbbaa7699b7f70206fbf06737c9ed7d/orjson-3.10.15-cp311-cp311-win32.whl", hash = "sha256:d5ac11b659fd798228a7adba3e37c010e0152b78b1982897020a8e019a94882e", size = 142473 },
1621
- { url = "https://files.pythonhosted.org/packages/00/f8/bb60a4644287a544ec81df1699d5b965776bc9848d9029d9f9b3402ac8bb/orjson-3.10.15-cp311-cp311-win_amd64.whl", hash = "sha256:cf45e0214c593660339ef63e875f32ddd5aa3b4adc15e662cdb80dc49e194f8e", size = 133570 },
1622
- { url = "https://files.pythonhosted.org/packages/66/85/22fe737188905a71afcc4bf7cc4c79cd7f5bbe9ed1fe0aac4ce4c33edc30/orjson-3.10.15-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9d11c0714fc85bfcf36ada1179400862da3288fc785c30e8297844c867d7505a", size = 249504 },
1623
- { url = "https://files.pythonhosted.org/packages/48/b7/2622b29f3afebe938a0a9037e184660379797d5fd5234e5998345d7a5b43/orjson-3.10.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dba5a1e85d554e3897fa9fe6fbcff2ed32d55008973ec9a2b992bd9a65d2352d", size = 125080 },
1624
- { url = "https://files.pythonhosted.org/packages/ce/8f/0b72a48f4403d0b88b2a41450c535b3e8989e8a2d7800659a967efc7c115/orjson-3.10.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7723ad949a0ea502df656948ddd8b392780a5beaa4c3b5f97e525191b102fff0", size = 150121 },
1625
- { url = "https://files.pythonhosted.org/packages/06/ec/acb1a20cd49edb2000be5a0404cd43e3c8aad219f376ac8c60b870518c03/orjson-3.10.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6fd9bc64421e9fe9bd88039e7ce8e58d4fead67ca88e3a4014b143cec7684fd4", size = 139796 },
1626
- { url = "https://files.pythonhosted.org/packages/33/e1/f7840a2ea852114b23a52a1c0b2bea0a1ea22236efbcdb876402d799c423/orjson-3.10.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dadba0e7b6594216c214ef7894c4bd5f08d7c0135f4dd0145600be4fbcc16767", size = 154636 },
1627
- { url = "https://files.pythonhosted.org/packages/fa/da/31543337febd043b8fa80a3b67de627669b88c7b128d9ad4cc2ece005b7a/orjson-3.10.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48f59114fe318f33bbaee8ebeda696d8ccc94c9e90bc27dbe72153094e26f41", size = 130621 },
1628
- { url = "https://files.pythonhosted.org/packages/ed/78/66115dc9afbc22496530d2139f2f4455698be444c7c2475cb48f657cefc9/orjson-3.10.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:035fb83585e0f15e076759b6fedaf0abb460d1765b6a36f48018a52858443514", size = 138516 },
1629
- { url = "https://files.pythonhosted.org/packages/22/84/cd4f5fb5427ffcf823140957a47503076184cb1ce15bcc1165125c26c46c/orjson-3.10.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d13b7fe322d75bf84464b075eafd8e7dd9eae05649aa2a5354cfa32f43c59f17", size = 130762 },
1630
- { url = "https://files.pythonhosted.org/packages/93/1f/67596b711ba9f56dd75d73b60089c5c92057f1130bb3a25a0f53fb9a583b/orjson-3.10.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7066b74f9f259849629e0d04db6609db4cf5b973248f455ba5d3bd58a4daaa5b", size = 414700 },
1631
- { url = "https://files.pythonhosted.org/packages/7c/0c/6a3b3271b46443d90efb713c3e4fe83fa8cd71cda0d11a0f69a03f437c6e/orjson-3.10.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:88dc3f65a026bd3175eb157fea994fca6ac7c4c8579fc5a86fc2114ad05705b7", size = 141077 },
1632
- { url = "https://files.pythonhosted.org/packages/3b/9b/33c58e0bfc788995eccd0d525ecd6b84b40d7ed182dd0751cd4c1322ac62/orjson-3.10.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b342567e5465bd99faa559507fe45e33fc76b9fb868a63f1642c6bc0735ad02a", size = 129898 },
1633
- { url = "https://files.pythonhosted.org/packages/01/c1/d577ecd2e9fa393366a1ea0a9267f6510d86e6c4bb1cdfb9877104cac44c/orjson-3.10.15-cp312-cp312-win32.whl", hash = "sha256:0a4f27ea5617828e6b58922fdbec67b0aa4bb844e2d363b9244c47fa2180e665", size = 142566 },
1634
- { url = "https://files.pythonhosted.org/packages/ed/eb/a85317ee1732d1034b92d56f89f1de4d7bf7904f5c8fb9dcdd5b1c83917f/orjson-3.10.15-cp312-cp312-win_amd64.whl", hash = "sha256:ef5b87e7aa9545ddadd2309efe6824bd3dd64ac101c15dae0f2f597911d46eaa", size = 133732 },
1635
- { url = "https://files.pythonhosted.org/packages/06/10/fe7d60b8da538e8d3d3721f08c1b7bff0491e8fa4dd3bf11a17e34f4730e/orjson-3.10.15-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:bae0e6ec2b7ba6895198cd981b7cca95d1487d0147c8ed751e5632ad16f031a6", size = 249399 },
1636
- { url = "https://files.pythonhosted.org/packages/6b/83/52c356fd3a61abd829ae7e4366a6fe8e8863c825a60d7ac5156067516edf/orjson-3.10.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f93ce145b2db1252dd86af37d4165b6faa83072b46e3995ecc95d4b2301b725a", size = 125044 },
1637
- { url = "https://files.pythonhosted.org/packages/55/b2/d06d5901408e7ded1a74c7c20d70e3a127057a6d21355f50c90c0f337913/orjson-3.10.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7c203f6f969210128af3acae0ef9ea6aab9782939f45f6fe02d05958fe761ef9", size = 150066 },
1638
- { url = "https://files.pythonhosted.org/packages/75/8c/60c3106e08dc593a861755781c7c675a566445cc39558677d505878d879f/orjson-3.10.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8918719572d662e18b8af66aef699d8c21072e54b6c82a3f8f6404c1f5ccd5e0", size = 139737 },
1639
- { url = "https://files.pythonhosted.org/packages/6a/8c/ae00d7d0ab8a4490b1efeb01ad4ab2f1982e69cc82490bf8093407718ff5/orjson-3.10.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f71eae9651465dff70aa80db92586ad5b92df46a9373ee55252109bb6b703307", size = 154804 },
1640
- { url = "https://files.pythonhosted.org/packages/22/86/65dc69bd88b6dd254535310e97bc518aa50a39ef9c5a2a5d518e7a223710/orjson-3.10.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e117eb299a35f2634e25ed120c37c641398826c2f5a3d3cc39f5993b96171b9e", size = 130583 },
1641
- { url = "https://files.pythonhosted.org/packages/bb/00/6fe01ededb05d52be42fabb13d93a36e51f1fd9be173bd95707d11a8a860/orjson-3.10.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13242f12d295e83c2955756a574ddd6741c81e5b99f2bef8ed8d53e47a01e4b7", size = 138465 },
1642
- { url = "https://files.pythonhosted.org/packages/db/2f/4cc151c4b471b0cdc8cb29d3eadbce5007eb0475d26fa26ed123dca93b33/orjson-3.10.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7946922ada8f3e0b7b958cc3eb22cfcf6c0df83d1fe5521b4a100103e3fa84c8", size = 130742 },
1643
- { url = "https://files.pythonhosted.org/packages/9f/13/8a6109e4b477c518498ca37963d9c0eb1508b259725553fb53d53b20e2ea/orjson-3.10.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b7155eb1623347f0f22c38c9abdd738b287e39b9982e1da227503387b81b34ca", size = 414669 },
1644
- { url = "https://files.pythonhosted.org/packages/22/7b/1d229d6d24644ed4d0a803de1b0e2df832032d5beda7346831c78191b5b2/orjson-3.10.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:208beedfa807c922da4e81061dafa9c8489c6328934ca2a562efa707e049e561", size = 141043 },
1645
- { url = "https://files.pythonhosted.org/packages/cc/d3/6dc91156cf12ed86bed383bcb942d84d23304a1e57b7ab030bf60ea130d6/orjson-3.10.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eca81f83b1b8c07449e1d6ff7074e82e3fd6777e588f1a6632127f286a968825", size = 129826 },
1646
- { url = "https://files.pythonhosted.org/packages/b3/38/c47c25b86f6996f1343be721b6ea4367bc1c8bc0fc3f6bbcd995d18cb19d/orjson-3.10.15-cp313-cp313-win32.whl", hash = "sha256:c03cd6eea1bd3b949d0d007c8d57049aa2b39bd49f58b4b2af571a5d3833d890", size = 142542 },
1647
- { url = "https://files.pythonhosted.org/packages/27/f1/1d7ec15b20f8ce9300bc850de1e059132b88990e46cd0ccac29cbf11e4f9/orjson-3.10.15-cp313-cp313-win_amd64.whl", hash = "sha256:fd56a26a04f6ba5fb2045b0acc487a63162a958ed837648c5781e1fe3316cfbf", size = 133444 },
1648
- ]
1649
-
1650
  [[package]]
1651
  name = "packaging"
1652
  version = "24.1"
@@ -1771,19 +1554,6 @@ wheels = [
1771
  { url = "https://files.pythonhosted.org/packages/ec/3d/c32a51d848401bd94cabb8767a39621496491ee7cd5199856b77da9b18ad/pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316", size = 2567508 },
1772
  ]
1773
 
1774
- [[package]]
1775
- name = "plotly"
1776
- version = "6.0.0"
1777
- source = { registry = "https://pypi.org/simple" }
1778
- dependencies = [
1779
- { name = "narwhals" },
1780
- { name = "packaging" },
1781
- ]
1782
- sdist = { url = "https://files.pythonhosted.org/packages/9c/80/761c14012d6daf18e12b6d1e4f6b218e999bcceb694d7a9b180154f9e4db/plotly-6.0.0.tar.gz", hash = "sha256:c4aad38b8c3d65e4a5e7dd308b084143b9025c2cc9d5317fc1f1d30958db87d3", size = 8111782 }
1783
- wheels = [
1784
- { url = "https://files.pythonhosted.org/packages/0e/77/a946f38b57fb88e736c71fbdd737a1aebd27b532bda0779c137f357cf5fc/plotly-6.0.0-py3-none-any.whl", hash = "sha256:f708871c3a9349a68791ff943a5781b1ec04de7769ea69068adcd9202e57653a", size = 14805949 },
1785
- ]
1786
-
1787
  [[package]]
1788
  name = "portalocker"
1789
  version = "2.10.1"
@@ -1925,15 +1695,6 @@ wheels = [
1925
  { url = "https://files.pythonhosted.org/packages/92/a2/81c1dd744b322c0c548f793deb521bf23500806d754128ddf6f978736dff/pyarrow-18.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b46591222c864e7da7faa3b19455196416cd8355ff6c2cc2e65726a760a3c420", size = 40006508 },
1926
  ]
1927
 
1928
- [[package]]
1929
- name = "pycountry"
1930
- version = "24.6.1"
1931
- source = { registry = "https://pypi.org/simple" }
1932
- sdist = { url = "https://files.pythonhosted.org/packages/76/57/c389fa68c50590881a75b7883eeb3dc15e9e73a0fdc001cdd45c13290c92/pycountry-24.6.1.tar.gz", hash = "sha256:b61b3faccea67f87d10c1f2b0fc0be714409e8fcdcc1315613174f6466c10221", size = 6043910 }
1933
- wheels = [
1934
- { url = "https://files.pythonhosted.org/packages/b1/ec/1fb891d8a2660716aadb2143235481d15ed1cbfe3ad669194690b0604492/pycountry-24.6.1-py3-none-any.whl", hash = "sha256:f1a4fb391cd7214f8eefd39556d740adcc233c778a27f8942c8dca351d6ce06f", size = 6335189 },
1935
- ]
1936
-
1937
  [[package]]
1938
  name = "pydantic"
1939
  version = "2.9.2"
@@ -2015,24 +1776,6 @@ wheels = [
2015
  { url = "https://files.pythonhosted.org/packages/a9/f9/b6bcaf874f410564a78908739c80861a171788ef4d4f76f5009656672dfe/pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", size = 1920344 },
2016
  ]
2017
 
2018
- [[package]]
2019
- name = "pydub"
2020
- version = "0.25.1"
2021
- source = { registry = "https://pypi.org/simple" }
2022
- sdist = { url = "https://files.pythonhosted.org/packages/fe/9a/e6bca0eed82db26562c73b5076539a4a08d3cffd19c3cc5913a3e61145fd/pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f", size = 38326 }
2023
- wheels = [
2024
- { url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327 },
2025
- ]
2026
-
2027
- [[package]]
2028
- name = "pygments"
2029
- version = "2.19.1"
2030
- source = { registry = "https://pypi.org/simple" }
2031
- sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
2032
- wheels = [
2033
- { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
2034
- ]
2035
-
2036
  [[package]]
2037
  name = "pyparsing"
2038
  version = "3.2.0"
@@ -2063,15 +1806,6 @@ wheels = [
2063
  { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
2064
  ]
2065
 
2066
- [[package]]
2067
- name = "python-multipart"
2068
- version = "0.0.20"
2069
- source = { registry = "https://pypi.org/simple" }
2070
- sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 }
2071
- wheels = [
2072
- { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 },
2073
- ]
2074
-
2075
  [[package]]
2076
  name = "pytz"
2077
  version = "2024.2"
@@ -2321,45 +2055,6 @@ wheels = [
2321
  { url = "https://files.pythonhosted.org/packages/79/f3/2b3a6dc5986303b3dd1bbbcf482022acb2583c428cd23f0b6d37b1a1a519/responses-0.18.0-py3-none-any.whl", hash = "sha256:15c63ad16de13ee8e7182d99c9334f64fd81f1ee79f90748d527c28f7ca9dd51", size = 38735 },
2322
  ]
2323
 
2324
- [[package]]
2325
- name = "rich"
2326
- version = "13.9.4"
2327
- source = { registry = "https://pypi.org/simple" }
2328
- dependencies = [
2329
- { name = "markdown-it-py" },
2330
- { name = "pygments" },
2331
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
2332
- ]
2333
- sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
2334
- wheels = [
2335
- { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
2336
- ]
2337
-
2338
- [[package]]
2339
- name = "ruff"
2340
- version = "0.9.7"
2341
- source = { registry = "https://pypi.org/simple" }
2342
- sdist = { url = "https://files.pythonhosted.org/packages/39/8b/a86c300359861b186f18359adf4437ac8e4c52e42daa9eedc731ef9d5b53/ruff-0.9.7.tar.gz", hash = "sha256:643757633417907510157b206e490c3aa11cab0c087c912f60e07fbafa87a4c6", size = 3669813 }
2343
- wheels = [
2344
- { url = "https://files.pythonhosted.org/packages/b1/f3/3a1d22973291226df4b4e2ff70196b926b6f910c488479adb0eeb42a0d7f/ruff-0.9.7-py3-none-linux_armv6l.whl", hash = "sha256:99d50def47305fe6f233eb8dabfd60047578ca87c9dcb235c9723ab1175180f4", size = 11774588 },
2345
- { url = "https://files.pythonhosted.org/packages/8e/c9/b881f4157b9b884f2994fd08ee92ae3663fb24e34b0372ac3af999aa7fc6/ruff-0.9.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d59105ae9c44152c3d40a9c40d6331a7acd1cdf5ef404fbe31178a77b174ea66", size = 11746848 },
2346
- { url = "https://files.pythonhosted.org/packages/14/89/2f546c133f73886ed50a3d449e6bf4af27d92d2f960a43a93d89353f0945/ruff-0.9.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f313b5800483770bd540cddac7c90fc46f895f427b7820f18fe1822697f1fec9", size = 11177525 },
2347
- { url = "https://files.pythonhosted.org/packages/d7/93/6b98f2c12bf28ab9def59c50c9c49508519c5b5cfecca6de871cf01237f6/ruff-0.9.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:042ae32b41343888f59c0a4148f103208bf6b21c90118d51dc93a68366f4e903", size = 11996580 },
2348
- { url = "https://files.pythonhosted.org/packages/8e/3f/b3fcaf4f6d875e679ac2b71a72f6691a8128ea3cb7be07cbb249f477c061/ruff-0.9.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:87862589373b33cc484b10831004e5e5ec47dc10d2b41ba770e837d4f429d721", size = 11525674 },
2349
- { url = "https://files.pythonhosted.org/packages/f0/48/33fbf18defb74d624535d5d22adcb09a64c9bbabfa755bc666189a6b2210/ruff-0.9.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a17e1e01bee0926d351a1ee9bc15c445beae888f90069a6192a07a84af544b6b", size = 12739151 },
2350
- { url = "https://files.pythonhosted.org/packages/63/b5/7e161080c5e19fa69495cbab7c00975ef8a90f3679caa6164921d7f52f4a/ruff-0.9.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:7c1f880ac5b2cbebd58b8ebde57069a374865c73f3bf41f05fe7a179c1c8ef22", size = 13416128 },
2351
- { url = "https://files.pythonhosted.org/packages/4e/c8/b5e7d61fb1c1b26f271ac301ff6d9de5e4d9a9a63f67d732fa8f200f0c88/ruff-0.9.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e63fc20143c291cab2841dbb8260e96bafbe1ba13fd3d60d28be2c71e312da49", size = 12870858 },
2352
- { url = "https://files.pythonhosted.org/packages/da/cb/2a1a8e4e291a54d28259f8fc6a674cd5b8833e93852c7ef5de436d6ed729/ruff-0.9.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91ff963baed3e9a6a4eba2a02f4ca8eaa6eba1cc0521aec0987da8d62f53cbef", size = 14786046 },
2353
- { url = "https://files.pythonhosted.org/packages/ca/6c/c8f8a313be1943f333f376d79724260da5701426c0905762e3ddb389e3f4/ruff-0.9.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88362e3227c82f63eaebf0b2eff5b88990280fb1ecf7105523883ba8c3aaf6fb", size = 12550834 },
2354
- { url = "https://files.pythonhosted.org/packages/9d/ad/f70cf5e8e7c52a25e166bdc84c082163c9c6f82a073f654c321b4dff9660/ruff-0.9.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:0372c5a90349f00212270421fe91874b866fd3626eb3b397ede06cd385f6f7e0", size = 11961307 },
2355
- { url = "https://files.pythonhosted.org/packages/52/d5/4f303ea94a5f4f454daf4d02671b1fbfe2a318b5fcd009f957466f936c50/ruff-0.9.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d76b8ab60e99e6424cd9d3d923274a1324aefce04f8ea537136b8398bbae0a62", size = 11612039 },
2356
- { url = "https://files.pythonhosted.org/packages/eb/c8/bd12a23a75603c704ce86723be0648ba3d4ecc2af07eecd2e9fa112f7e19/ruff-0.9.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0c439bdfc8983e1336577f00e09a4e7a78944fe01e4ea7fe616d00c3ec69a3d0", size = 12168177 },
2357
- { url = "https://files.pythonhosted.org/packages/cc/57/d648d4f73400fef047d62d464d1a14591f2e6b3d4a15e93e23a53c20705d/ruff-0.9.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:115d1f15e8fdd445a7b4dc9a30abae22de3f6bcabeb503964904471691ef7606", size = 12610122 },
2358
- { url = "https://files.pythonhosted.org/packages/49/79/acbc1edd03ac0e2a04ae2593555dbc9990b34090a9729a0c4c0cf20fb595/ruff-0.9.7-py3-none-win32.whl", hash = "sha256:e9ece95b7de5923cbf38893f066ed2872be2f2f477ba94f826c8defdd6ec6b7d", size = 9988751 },
2359
- { url = "https://files.pythonhosted.org/packages/6d/95/67153a838c6b6ba7a2401241fd8a00cd8c627a8e4a0491b8d853dedeffe0/ruff-0.9.7-py3-none-win_amd64.whl", hash = "sha256:3770fe52b9d691a15f0b87ada29c45324b2ace8f01200fb0c14845e499eb0c2c", size = 11002987 },
2360
- { url = "https://files.pythonhosted.org/packages/63/6a/aca01554949f3a401991dc32fe22837baeaccb8a0d868256cbb26a029778/ruff-0.9.7-py3-none-win_arm64.whl", hash = "sha256:b075a700b2533feb7a01130ff656a4ec0d5f340bb540ad98759b8401c32c2037", size = 10177763 },
2361
- ]
2362
-
2363
  [[package]]
2364
  name = "sacrebleu"
2365
  version = "2.4.3"
@@ -2377,18 +2072,6 @@ wheels = [
2377
  { url = "https://files.pythonhosted.org/packages/15/d8/e51d35bc863caa19ddeae48dfb890581a19326973ad1c9fa5dcfc63310f7/sacrebleu-2.4.3-py3-none-any.whl", hash = "sha256:a976fd6998d8ced267a722120ec7fc47083c8e9745d8808ccee6424464a0aa31", size = 103964 },
2378
  ]
2379
 
2380
- [[package]]
2381
- name = "safehttpx"
2382
- version = "0.1.6"
2383
- source = { registry = "https://pypi.org/simple" }
2384
- dependencies = [
2385
- { name = "httpx" },
2386
- ]
2387
- sdist = { url = "https://files.pythonhosted.org/packages/67/4c/19db75e6405692b2a96af8f06d1258f8aa7290bdc35ac966f03e207f6d7f/safehttpx-0.1.6.tar.gz", hash = "sha256:b356bfc82cee3a24c395b94a2dbeabbed60aff1aa5fa3b5fe97c4f2456ebce42", size = 9987 }
2388
- wheels = [
2389
- { url = "https://files.pythonhosted.org/packages/4d/c0/1108ad9f01567f66b3154063605b350b69c3c9366732e09e45f9fd0d1deb/safehttpx-0.1.6-py3-none-any.whl", hash = "sha256:407cff0b410b071623087c63dd2080c3b44dc076888d8c5823c00d1e58cb381c", size = 8692 },
2390
- ]
2391
-
2392
  [[package]]
2393
  name = "safetensors"
2394
  version = "0.4.5"
@@ -2450,15 +2133,6 @@ wheels = [
2450
  { url = "https://files.pythonhosted.org/packages/19/46/5d11dc300feaad285c2f1bd784ff3f689f5e0ab6be49aaf568f3a77019eb/safetensors-0.4.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:21742b391b859e67b26c0b2ac37f52c9c0944a879a25ad2f9f9f3cd61e7fda8f", size = 606660 },
2451
  ]
2452
 
2453
- [[package]]
2454
- name = "semantic-version"
2455
- version = "2.10.0"
2456
- source = { registry = "https://pypi.org/simple" }
2457
- sdist = { url = "https://files.pythonhosted.org/packages/7d/31/f2289ce78b9b473d582568c234e104d2a342fd658cc288a7553d83bb8595/semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c", size = 52289 }
2458
- wheels = [
2459
- { url = "https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177", size = 15552 },
2460
- ]
2461
-
2462
  [[package]]
2463
  name = "sentencepiece"
2464
  version = "0.2.0"
@@ -2500,15 +2174,6 @@ wheels = [
2500
  { url = "https://files.pythonhosted.org/packages/90/12/282ee9bce8b58130cb762fbc9beabd531549952cac11fc56add11dcb7ea0/setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd", size = 1251070 },
2501
  ]
2502
 
2503
- [[package]]
2504
- name = "shellingham"
2505
- version = "1.5.4"
2506
- source = { registry = "https://pypi.org/simple" }
2507
- sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
2508
- wheels = [
2509
- { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
2510
- ]
2511
-
2512
  [[package]]
2513
  name = "six"
2514
  version = "1.16.0"
@@ -2650,15 +2315,6 @@ wheels = [
2650
  { url = "https://files.pythonhosted.org/packages/d4/f2/ea998aaf69966a87f92e31db7cba887125994bb9cd9a4dfcc83ac202d446/tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f40df5e0294a95131cc5f0e0eb91fe86d88837abfbee46b9b3610b09860195a7", size = 9300207 },
2651
  ]
2652
 
2653
- [[package]]
2654
- name = "tomlkit"
2655
- version = "0.13.2"
2656
- source = { registry = "https://pypi.org/simple" }
2657
- sdist = { url = "https://files.pythonhosted.org/packages/b1/09/a439bec5888f00a54b8b9f05fa94d7f901d6735ef4e55dcec9bc37b5d8fa/tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79", size = 192885 }
2658
- wheels = [
2659
- { url = "https://files.pythonhosted.org/packages/f9/b6/a447b5e4ec71e13871be01ba81f5dfc9d0af7e473da256ff46bc0e24026f/tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde", size = 37955 },
2660
- ]
2661
-
2662
  [[package]]
2663
  name = "torch"
2664
  version = "2.5.1"
@@ -2747,21 +2403,6 @@ wheels = [
2747
  { url = "https://files.pythonhosted.org/packages/78/eb/65f5ba83c2a123f6498a3097746607e5b2f16add29e36765305e4ac7fdd8/triton-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8182f42fd8080a7d39d666814fa36c5e30cc00ea7eeeb1a2983dbb4c99a0fdc", size = 209551444 },
2748
  ]
2749
 
2750
- [[package]]
2751
- name = "typer"
2752
- version = "0.15.1"
2753
- source = { registry = "https://pypi.org/simple" }
2754
- dependencies = [
2755
- { name = "click" },
2756
- { name = "rich" },
2757
- { name = "shellingham" },
2758
- { name = "typing-extensions" },
2759
- ]
2760
- sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/dca7b219718afd37a0068f4f2530a727c2b74a8b6e8e0c0080a4c0de4fcd/typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a", size = 99789 }
2761
- wheels = [
2762
- { url = "https://files.pythonhosted.org/packages/d0/cc/0a838ba5ca64dc832aa43f727bd586309846b0ffb2ce52422543e6075e8a/typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", size = 44908 },
2763
- ]
2764
-
2765
  [[package]]
2766
  name = "typing-extensions"
2767
  version = "4.12.2"
 
7
  "python_full_version >= '3.13'",
8
  ]
9
 
 
 
 
 
 
 
 
 
 
10
  [[package]]
11
  name = "aiohappyeyeballs"
12
  version = "2.4.3"
 
156
  { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 },
157
  ]
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  [[package]]
160
  name = "bert-score"
161
  version = "0.3.13"
 
451
  { url = "https://files.pythonhosted.org/packages/8f/7d/2d6ce181d7a5f51dedb8c06206cbf0ec026a99bf145edd309f9e17c3282f/fastapi-0.115.8-py3-none-any.whl", hash = "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf", size = 94814 },
452
  ]
453
 
 
 
 
 
 
 
 
 
 
454
  [[package]]
455
  name = "filelock"
456
  version = "3.16.1"
 
582
  { name = "aiohttp" },
583
  ]
584
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  [[package]]
586
  name = "h11"
587
  version = "0.14.0"
 
844
  version = "0.1.0"
845
  source = { virtual = "." }
846
  dependencies = [
847
+ { name = "fastapi" },
848
+ { name = "numpy" },
 
849
  { name = "pandas" },
850
+ { name = "uvicorn" },
 
851
  ]
852
 
853
  [package.dev-dependencies]
 
860
  { name = "jiwer" },
861
  { name = "joblib" },
862
  { name = "langcodes" },
863
+ { name = "language-data" },
864
  { name = "openai" },
865
  { name = "protobuf" },
866
  { name = "python-dotenv" },
 
873
 
874
  [package.metadata]
875
  requires-dist = [
876
+ { name = "fastapi", specifier = ">=0.115.8" },
877
+ { name = "numpy", specifier = ">=2.1.2" },
 
878
  { name = "pandas", specifier = ">=2.2.3" },
879
+ { name = "uvicorn", specifier = ">=0.34.0" },
 
880
  ]
881
 
882
  [package.metadata.requires-dev]
 
889
  { name = "jiwer", specifier = ">=3.1.0" },
890
  { name = "joblib", specifier = ">=1.4.2" },
891
  { name = "langcodes", specifier = ">=3.5.0" },
892
+ { name = "language-data", specifier = ">=1.3.0" },
893
  { name = "openai", specifier = ">=1.52.2" },
894
  { name = "protobuf", specifier = ">=5.28.3" },
895
  { name = "python-dotenv", specifier = ">=1.0.1" },
 
1037
  { url = "https://files.pythonhosted.org/packages/27/40/5f9eb8b73030cc4b0d6817176e66079a62a2ddd9d5530da54f8011473428/marisa_trie-1.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:aa7cd17e1c690ce96c538b2f4aae003d9a498e65067dd433c52dd069009951d4", size = 149035 },
1038
  ]
1039
 
 
 
 
 
 
 
 
 
 
 
 
 
1040
  [[package]]
1041
  name = "markupsafe"
1042
  version = "2.1.5"
 
1123
  { url = "https://files.pythonhosted.org/packages/01/8a/760f7fce66b39f447ad160800619d0bd5d0936d2b4633587116534a4afe0/matplotlib-3.9.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5816b1e1fe8c192cbc013f8f3e3368ac56fbecf02fb41b8f8559303f24c5015e", size = 9093770 },
1124
  ]
1125
 
 
 
 
 
 
 
 
 
 
1126
  [[package]]
1127
  name = "mpmath"
1128
  version = "1.3.0"
 
1222
  { url = "https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", size = 133351 },
1223
  ]
1224
 
 
 
 
 
 
 
 
 
 
1225
  [[package]]
1226
  name = "networkx"
1227
  version = "3.4.2"
 
1430
  { url = "https://files.pythonhosted.org/packages/55/4c/906b5b32c4c01402ac3b4c3fc28f601443ac5c6f13c84a95dd178c8d545d/openai-1.52.2-py3-none-any.whl", hash = "sha256:57e9e37bc407f39bb6ec3a27d7e8fb9728b2779936daa1fcf95df17d3edfaccc", size = 386947 },
1431
  ]
1432
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1433
  [[package]]
1434
  name = "packaging"
1435
  version = "24.1"
 
1554
  { url = "https://files.pythonhosted.org/packages/ec/3d/c32a51d848401bd94cabb8767a39621496491ee7cd5199856b77da9b18ad/pillow-11.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:224aaa38177597bb179f3ec87eeefcce8e4f85e608025e9cfac60de237ba6316", size = 2567508 },
1555
  ]
1556
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1557
  [[package]]
1558
  name = "portalocker"
1559
  version = "2.10.1"
 
1695
  { url = "https://files.pythonhosted.org/packages/92/a2/81c1dd744b322c0c548f793deb521bf23500806d754128ddf6f978736dff/pyarrow-18.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:b46591222c864e7da7faa3b19455196416cd8355ff6c2cc2e65726a760a3c420", size = 40006508 },
1696
  ]
1697
 
 
 
 
 
 
 
 
 
 
1698
  [[package]]
1699
  name = "pydantic"
1700
  version = "2.9.2"
 
1776
  { url = "https://files.pythonhosted.org/packages/a9/f9/b6bcaf874f410564a78908739c80861a171788ef4d4f76f5009656672dfe/pydantic_core-2.23.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9a5bce9d23aac8f0cf0836ecfc033896aa8443b501c58d0602dbfd5bd5b37753", size = 1920344 },
1777
  ]
1778
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1779
  [[package]]
1780
  name = "pyparsing"
1781
  version = "3.2.0"
 
1806
  { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
1807
  ]
1808
 
 
 
 
 
 
 
 
 
 
1809
  [[package]]
1810
  name = "pytz"
1811
  version = "2024.2"
 
2055
  { url = "https://files.pythonhosted.org/packages/79/f3/2b3a6dc5986303b3dd1bbbcf482022acb2583c428cd23f0b6d37b1a1a519/responses-0.18.0-py3-none-any.whl", hash = "sha256:15c63ad16de13ee8e7182d99c9334f64fd81f1ee79f90748d527c28f7ca9dd51", size = 38735 },
2056
  ]
2057
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2058
  [[package]]
2059
  name = "sacrebleu"
2060
  version = "2.4.3"
 
2072
  { url = "https://files.pythonhosted.org/packages/15/d8/e51d35bc863caa19ddeae48dfb890581a19326973ad1c9fa5dcfc63310f7/sacrebleu-2.4.3-py3-none-any.whl", hash = "sha256:a976fd6998d8ced267a722120ec7fc47083c8e9745d8808ccee6424464a0aa31", size = 103964 },
2073
  ]
2074
 
 
 
 
 
 
 
 
 
 
 
 
 
2075
  [[package]]
2076
  name = "safetensors"
2077
  version = "0.4.5"
 
2133
  { url = "https://files.pythonhosted.org/packages/19/46/5d11dc300feaad285c2f1bd784ff3f689f5e0ab6be49aaf568f3a77019eb/safetensors-0.4.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:21742b391b859e67b26c0b2ac37f52c9c0944a879a25ad2f9f9f3cd61e7fda8f", size = 606660 },
2134
  ]
2135
 
 
 
 
 
 
 
 
 
 
2136
  [[package]]
2137
  name = "sentencepiece"
2138
  version = "0.2.0"
 
2174
  { url = "https://files.pythonhosted.org/packages/90/12/282ee9bce8b58130cb762fbc9beabd531549952cac11fc56add11dcb7ea0/setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd", size = 1251070 },
2175
  ]
2176
 
 
 
 
 
 
 
 
 
 
2177
  [[package]]
2178
  name = "six"
2179
  version = "1.16.0"
 
2315
  { url = "https://files.pythonhosted.org/packages/d4/f2/ea998aaf69966a87f92e31db7cba887125994bb9cd9a4dfcc83ac202d446/tokenizers-0.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f40df5e0294a95131cc5f0e0eb91fe86d88837abfbee46b9b3610b09860195a7", size = 9300207 },
2316
  ]
2317
 
 
 
 
 
 
 
 
 
 
2318
  [[package]]
2319
  name = "torch"
2320
  version = "2.5.1"
 
2403
  { url = "https://files.pythonhosted.org/packages/78/eb/65f5ba83c2a123f6498a3097746607e5b2f16add29e36765305e4ac7fdd8/triton-3.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8182f42fd8080a7d39d666814fa36c5e30cc00ea7eeeb1a2983dbb4c99a0fdc", size = 209551444 },
2404
  ]
2405
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2406
  [[package]]
2407
  name = "typing-extensions"
2408
  version = "4.12.2"