David Pomerenke
		
	commited on
		
		
					Commit 
							
							·
						
						2c21cf7
	
1
								Parent(s):
							
							b6b84c7
								
Basic backend setup with FastApi but without actual filtering
Browse files- evals/app.py +0 -993
- evals/backend.py +46 -0
- evals/countries.py +4 -3
- evals/main.py +1 -120
- evals/tables.py +100 -0
- frontend/package.json +2 -1
- frontend/public/results.json +0 -0
- frontend/src/App.js +7 -4
- frontend/src/components/LanguageTable.js +2 -4
- frontend/src/components/ModelTable.js +1 -2
- pyproject.toml +4 -5
- results.json +0 -0
- uv.lock +8 -367
    	
        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 | 
            -
                        "Translation": round(lang["mt_chrf"], 3)
         | 
| 239 | 
            -
                        if lang["mt_chrf"] is not None
         | 
| 240 | 
            -
                        else "N/A",
         | 
| 241 | 
            -
                        "Classification": 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 Recognition": round(lang["asr_chrf"], 3) if lang["asr_wer"] is not None else "N/A",
         | 
| 248 | 
            -
                        "CommonVoice": 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  | 
| 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 | 
            -
                 | 
|  | 
|  | |
| 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( | 
| 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('/ | 
|  | |
|  | |
|  | |
| 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  | 
| 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={ | 
| 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={ | 
| 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 | 
            -
                " | 
| 9 | 
            -
                " | 
| 10 | 
            -
                "language-data>=1.3.0",
         | 
| 11 | 
             
                "pandas>=2.2.3",
         | 
| 12 | 
            -
                " | 
| 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 = " | 
| 973 | 
            -
                { name = " | 
| 974 | 
            -
                { name = "language-data" },
         | 
| 975 | 
             
                { name = "pandas" },
         | 
| 976 | 
            -
                { name = " | 
| 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 = " | 
| 1003 | 
            -
                { name = " | 
| 1004 | 
            -
                { name = "language-data", specifier = ">=1.3.0" },
         | 
| 1005 | 
             
                { name = "pandas", specifier = ">=2.2.3" },
         | 
| 1006 | 
            -
                { name = " | 
| 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"
         | 
