Spaces:
Running
Running
File size: 7,212 Bytes
bbc8186 7f2ce48 bbc8186 ef406e9 bbc8186 ef406e9 bbc8186 ef406e9 076f217 bbc8186 ba3c8e4 bbc8186 ba3c8e4 bbc8186 ba3c8e4 bbc8186 7f2ce48 bbc8186 7f2ce48 ef406e9 bbc8186 076f217 f53ed36 5e5e262 dcdbf5e 5e5e262 bbc8186 f201eb0 bbc8186 5e5e262 ef406e9 7f2ce48 dcdbf5e 7f2ce48 ef406e9 bbc8186 7f2ce48 bbc8186 7f2ce48 ef406e9 7f2ce48 bbc8186 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 | """
Dutch ASR Leaderboard — Gradio Space
"""
import json
from pathlib import Path
import gradio as gr
import pandas as pd
RESULTS_DIR = Path("results")
DATASET_KEYS = ["fleurs_nl", "voxpopuli_nl", "mls_nl"]
DATASET_LABELS = {
"fleurs_nl": "FLEURS",
"voxpopuli_nl": "VoxPopuli",
"mls_nl": "Multilingual LibriSpeech"
}
# Models to hide when "Show Proprietary" is OFF
PROPRIETARY_MODELS = ["ElevenLabs/scribe_v2", "voxtral-mini-2602", "Resonate-1 2026-05-22", "Murmel 2026-05-04"]
def load_results() -> list[dict]:
records = []
for path in sorted(RESULTS_DIR.glob("*.json")):
try:
with open(path) as f:
records.append(json.load(f))
except Exception as e:
print(f"Warning: could not load {path}: {e}")
return records
def build_dataframe(
records: list[dict],
sort_by: str = "average",
show_proprietary: bool = True,
datasets_visible: dict | None = None,
) -> pd.DataFrame:
rows = []
for r in records:
model_name = r.get("model_name", r.get("model_id", "?"))
# Skip proprietary models if toggle is off
if not show_proprietary and any(p in model_name for p in PROPRIETARY_MODELS):
continue
results = r.get("results", {})
params = r.get("params_billions")
row = {
"Model": model_name,
"License": r.get("license", "?"),
"Parameters (B)": f"{params}" if params is not None else "—",
}
wer_values = {}
for ds_key in DATASET_KEYS:
if datasets_visible and not datasets_visible.get(ds_key, True):
continue
label = DATASET_LABELS[ds_key]
ds_result = results.get(ds_key, {})
wer = ds_result.get("wer")
rtf = ds_result.get("rtf")
n_failed = ds_result.get("n_failed", 0)
failure_rate = ds_result.get("failure_rate_pct", 0.0)
wer_str = f"{wer:.1f}" if wer is not None else "—"
if n_failed > 0:
wer_str += f" ⚠{failure_rate:.0f}%"
row[f"{label} WER"] = wer_str
row[f"{label} RTF"] = f"{rtf:.3f}" if rtf is not None else "—"
if wer is not None:
wer_values[ds_key] = wer
# Calculate average WER
if wer_values:
row["Average WER"] = f"{sum(wer_values.values()) / len(wer_values):.1f}"
else:
row["Average WER"] = "—"
rows.append(row)
if not rows:
return pd.DataFrame()
df = pd.DataFrame(rows)
front = [c for c in ["Model", "License", "Parameters (B)", "Average WER"] if c in df.columns]
rest = [c for c in df.columns if c not in front]
df = df[front + rest]
# Sort by selected metric
if sort_by == "average":
df["_sort"] = df["Average WER"].str.extract(r"([\d.]+)")[0].astype(float, errors="ignore")
df = df.sort_values("_sort", na_position="last").drop(columns=["_sort"])
elif sort_by in DATASET_LABELS:
sort_col = f"{DATASET_LABELS[sort_by]} WER"
if sort_col in df.columns:
df["_sort"] = df[sort_col].str.extract(r"([\d.]+)")[0].astype(float, errors="ignore")
df = df.sort_values("_sort", na_position="last").drop(columns=["_sort"])
df = df.reset_index(drop=True)
return df
def refresh(sort_by: str, show_proprietary: bool, selected_datasets: list[str]):
records = load_results()
datasets_visible = {key: (DATASET_LABELS[key] in selected_datasets) for key in DATASET_KEYS}
return build_dataframe(records, sort_by, show_proprietary, datasets_visible)
ABOUT_TEXT = """
## Repository
Evaluation code and submission instructions are on GitHub: [tvosch/Dutch-ASR-leaderboard](https://github.com/tvosch/Dutch-ASR-leaderboard)
## Evaluation Setup
Local models are benchmarked on **H100 HBM2e GPUs** for consistent performance measurements.
## Metrics
**Word Error Rate (WER)** measures the percentage of words transcribed incorrectly compared to a reference transcript. It is calculated as `(substitutions + deletions + insertions) / total reference words × 100`. Lower is better. Results are normalized before scoring: lowercase, no punctuation, digits expanded to words, fillers removed.
**Real-Time Factor (RTF)** measures how fast a model transcribes relative to the audio duration. An RTF of 0.1 means 1 second of audio is processed in 100 ms. Lower is faster. Measured here at batch size 1; RTF measured via HTTP API includes network overhead.
## Datasets
| Dataset | Speech Type |
|---------|-------------|
| **FLEURS** | Read, studio quality |
| **VoxPopuli** | Formal, Parliament speech |
| **MLS** | Audiobook style |
"""
with gr.Blocks(title="Dutch ASR Leaderboard", theme=gr.themes.Default()) as demo:
gr.Markdown(
"# Dutch ASR Leaderboard\n"
"**An independent, community-driven benchmark for Dutch automatic speech recognition.** \n"
"Models are evaluated on standardized public test sets. Lower WER is better. "
"Rankings serve as a proxy for comparison, performance on your data may differ.\n\n"
"> **Note:** Some models may be benchmaxxed: trained or fine-tuned on data that overlaps "
"with these test sets. Treat results as indicative, not definitive. "
"[Submit your model on GitHub →](https://github.com/tvosch/Dutch-ASR-leaderboard)"
)
with gr.Tabs():
with gr.Tab("🏆 Leaderboard"):
with gr.Row():
sort_by = gr.Dropdown(
choices=[
("Average WER", "average"),
("FLEURS", "fleurs_nl"),
("VoxPopuli", "voxpopuli_nl"),
("MLS", "mls_nl"),
],
value="average",
label="Sort by",
scale=1,
min_width=160,
)
dataset_selector = gr.CheckboxGroup(
choices=list(DATASET_LABELS.values()),
value=list(DATASET_LABELS.values()),
label="Datasets",
scale=2,
)
show_proprietary = gr.Checkbox(
value=True,
label="Show proprietary models",
scale=1,
)
leaderboard_table = gr.Dataframe(
label="Results",
interactive=False,
wrap=True,
min_width=800,
)
# Initial load and event handlers
_inputs = [sort_by, show_proprietary, dataset_selector]
demo.load(fn=refresh, inputs=_inputs, outputs=[leaderboard_table])
sort_by.change(fn=refresh, inputs=_inputs, outputs=[leaderboard_table])
show_proprietary.change(fn=refresh, inputs=_inputs, outputs=[leaderboard_table])
dataset_selector.change(fn=refresh, inputs=_inputs, outputs=[leaderboard_table])
with gr.Tab("ℹ️ About"):
gr.Markdown(ABOUT_TEXT)
if __name__ == "__main__":
demo.launch()
|