Spaces:
Running
Running
feat: launch AVI-Bench community leaderboard
#1
by Gh0stAR - opened
- CONTRIBUTING.md +22 -0
- DEPLOYMENT.md +24 -0
- README.md +10 -5
- data/results.json +247 -0
- index.html +568 -17
- templates/result-entry.json +37 -0
- validate_results.py +204 -0
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing leaderboard results
|
| 2 |
+
|
| 3 |
+
Submit results as a pull request to this Space repository. A maintainer reviews the source and whether the record is complete and credible before merging it. The leaderboard shows the source type; a merged entry is not presented as an independent reproduction.
|
| 4 |
+
|
| 5 |
+
## Add a result
|
| 6 |
+
|
| 7 |
+
1. Copy `templates/result-entry.json` into `data/results.json` as a new object in the `entries` array.
|
| 8 |
+
2. Replace every example value, including the `null` score and sample-count placeholders. Use a unique, stable `id`; keep separate records for different model versions or evaluation runs.
|
| 9 |
+
3. Set `source.type` to `paper`, `participant`, or `maintainer`, and link the paper or result report in `source.url`. Use `paper-2606.07643` for results from the paper's benchmark setting; future benchmark releases should use their published release identifier.
|
| 10 |
+
4. Use scores on a 0–100 scale. Set `coverage.status` to `full` only when all tasks in that benchmark release were evaluated. If sample counts are known, report both counts; a full result must cover all reported samples. Partial results and records without an overall score are displayed without a rank.
|
| 11 |
+
5. Open a pull request in this Space repository. Keep the change limited to `data/results.json`; do not include examples, media, ground-truth labels, raw model responses, API keys, or other credentials.
|
| 12 |
+
|
| 13 |
+
## Required information
|
| 14 |
+
|
| 15 |
+
- Display name, provider, exact model identifier, and benchmark release.
|
| 16 |
+
- Source type and a public source link.
|
| 17 |
+
- Task coverage and any available evaluation date.
|
| 18 |
+
- Overall score for a row to be ranked. Stage, taxonomy, and task scores may still be submitted without an overall score when the source does not report one; that row remains visible without a rank.
|
| 19 |
+
|
| 20 |
+
The initial paper entries use the model labels as written in the paper. Their dated API snapshots and sample coverage were not reported in the headline table, so these fields remain unspecified rather than inferred.
|
| 21 |
+
|
| 22 |
+
The maintainer runs `python validate_results.py` before merging. A source link and complete metadata help reviewers assess credibility; the maintainer may ask for clarification or decline a record that cannot be checked.
|
DEPLOYMENT.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Deploy the leaderboard Space
|
| 2 |
+
|
| 3 |
+
This directory contains the leaderboard files for the existing `FudanCVL/AVI-Bench` Space. The app is a static HTML Space: it reads `data/results.json` in the browser and does not need an inference endpoint, server, or API key.
|
| 4 |
+
|
| 5 |
+
## First publication
|
| 6 |
+
|
| 7 |
+
1. Upload the files in this directory to the root of `https://huggingface.co/spaces/FudanCVL/AVI-Bench`, keeping `data/` and `templates/` as directories. This replaces the current starter `README.md` and `index.html`; existing `style.css` and `.gitattributes` are left alone.
|
| 8 |
+
2. Keep the Space **Public** and its SDK set to **Static**.
|
| 9 |
+
3. In the Space repository settings, make sure community pull requests and discussions are enabled.
|
| 10 |
+
4. Confirm that the Space displays the seven paper-reported model entries and that the submission guide is visible.
|
| 11 |
+
|
| 12 |
+
Hugging Face Static Spaces serve HTML directly without compute. Their repository PRs work across repository types, including Spaces. See the [Static HTML Spaces guide](https://huggingface.co/docs/hub/spaces-sdks-static) and [Pull requests and Discussions guide](https://huggingface.co/docs/hub/repositories-pull-requests-discussions).
|
| 13 |
+
|
| 14 |
+
## Reviewing updates
|
| 15 |
+
|
| 16 |
+
For each result PR, inspect the `data/results.json` diff and the linked source, check the model identifier, benchmark release, coverage, and reported metrics, then run:
|
| 17 |
+
|
| 18 |
+
```bash
|
| 19 |
+
python3 validate_results.py
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
Merge only after the source and record can be checked. A merged result retains its source label and is not described as an independent reproduction unless one was performed.
|
| 23 |
+
|
| 24 |
+
Do not accept benchmark examples, media, labels, raw model responses, or credentials in a result PR.
|
README.md
CHANGED
|
@@ -1,11 +1,16 @@
|
|
| 1 |
---
|
| 2 |
-
title: AVI
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: static
|
|
|
|
| 7 |
pinned: false
|
| 8 |
license: apache-2.0
|
| 9 |
---
|
| 10 |
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
+
title: AVI-Bench Leaderboard
|
| 3 |
+
emoji: 🏆
|
| 4 |
+
colorFrom: red
|
| 5 |
+
colorTo: yellow
|
| 6 |
sdk: static
|
| 7 |
+
app_file: index.html
|
| 8 |
pinned: false
|
| 9 |
license: apache-2.0
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# AVI-Bench Leaderboard
|
| 13 |
+
|
| 14 |
+
Community-submitted results for AVI-Bench, seeded with seven model entries from the paper's headline tables. Results are shown after a maintainer reviews and merges the pull request. The source type identifies whether a score is reported by a paper, a participant, or the maintainers; acceptance does not mean the result was independently reproduced.
|
| 15 |
+
|
| 16 |
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the score format and pull request instructions, and [`DEPLOYMENT.md`](DEPLOYMENT.md) for Space setup and maintenance.
|
data/results.json
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"schema_version": 1,
|
| 3 |
+
"entries": [
|
| 4 |
+
{
|
| 5 |
+
"id": "gemini-2-5-pro-paper-2606-07643",
|
| 6 |
+
"model_name": "Gemini-2.5-Pro",
|
| 7 |
+
"provider": "Google",
|
| 8 |
+
"model_id": "Gemini-2.5-Pro (paper label)",
|
| 9 |
+
"benchmark_version": "paper-2606.07643",
|
| 10 |
+
"source": {
|
| 11 |
+
"type": "paper",
|
| 12 |
+
"url": "https://arxiv.org/abs/2606.07643"
|
| 13 |
+
},
|
| 14 |
+
"evaluation_date": null,
|
| 15 |
+
"coverage": {
|
| 16 |
+
"status": "full",
|
| 17 |
+
"tasks_completed": 14,
|
| 18 |
+
"tasks_total": 14,
|
| 19 |
+
"samples_completed": null,
|
| 20 |
+
"samples_total": null
|
| 21 |
+
},
|
| 22 |
+
"scores": {
|
| 23 |
+
"overall": 57.21,
|
| 24 |
+
"stages": {
|
| 25 |
+
"perception": 54.58,
|
| 26 |
+
"understanding": 68.97,
|
| 27 |
+
"reasoning": 69.06,
|
| 28 |
+
"sensation": 36.22
|
| 29 |
+
},
|
| 30 |
+
"taxonomy": {
|
| 31 |
+
"l1_task": 64.2,
|
| 32 |
+
"l2_modality": 62.8,
|
| 33 |
+
"l3_stage": 57.08,
|
| 34 |
+
"l4_domain": 32.97
|
| 35 |
+
},
|
| 36 |
+
"tasks": {}
|
| 37 |
+
},
|
| 38 |
+
"notes": "Paper-reported scores. The paper table does not specify a dated API snapshot or sample coverage."
|
| 39 |
+
},
|
| 40 |
+
{
|
| 41 |
+
"id": "gemini-2-5-flash-paper-2606-07643",
|
| 42 |
+
"model_name": "Gemini-2.5-Flash",
|
| 43 |
+
"provider": "Google",
|
| 44 |
+
"model_id": "Gemini-2.5-Flash (paper label)",
|
| 45 |
+
"benchmark_version": "paper-2606.07643",
|
| 46 |
+
"source": {
|
| 47 |
+
"type": "paper",
|
| 48 |
+
"url": "https://arxiv.org/abs/2606.07643"
|
| 49 |
+
},
|
| 50 |
+
"evaluation_date": null,
|
| 51 |
+
"coverage": {
|
| 52 |
+
"status": "full",
|
| 53 |
+
"tasks_completed": 14,
|
| 54 |
+
"tasks_total": 14,
|
| 55 |
+
"samples_completed": null,
|
| 56 |
+
"samples_total": null
|
| 57 |
+
},
|
| 58 |
+
"scores": {
|
| 59 |
+
"overall": 46.02,
|
| 60 |
+
"stages": {
|
| 61 |
+
"perception": 45.97,
|
| 62 |
+
"understanding": 43.79,
|
| 63 |
+
"reasoning": 63.7,
|
| 64 |
+
"sensation": 30.63
|
| 65 |
+
},
|
| 66 |
+
"taxonomy": {
|
| 67 |
+
"l1_task": 51.15,
|
| 68 |
+
"l2_modality": 48.58,
|
| 69 |
+
"l3_stage": 40.47,
|
| 70 |
+
"l4_domain": 27.72
|
| 71 |
+
},
|
| 72 |
+
"tasks": {}
|
| 73 |
+
},
|
| 74 |
+
"notes": "Paper-reported scores. The paper table does not specify a dated API snapshot or sample coverage."
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"id": "gemini-2-flash-paper-2606-07643",
|
| 78 |
+
"model_name": "Gemini-2.0-Flash",
|
| 79 |
+
"provider": "Google",
|
| 80 |
+
"model_id": "Gemini-2.0-Flash (paper label)",
|
| 81 |
+
"benchmark_version": "paper-2606.07643",
|
| 82 |
+
"source": {
|
| 83 |
+
"type": "paper",
|
| 84 |
+
"url": "https://arxiv.org/abs/2606.07643"
|
| 85 |
+
},
|
| 86 |
+
"evaluation_date": null,
|
| 87 |
+
"coverage": {
|
| 88 |
+
"status": "full",
|
| 89 |
+
"tasks_completed": 14,
|
| 90 |
+
"tasks_total": 14,
|
| 91 |
+
"samples_completed": null,
|
| 92 |
+
"samples_total": null
|
| 93 |
+
},
|
| 94 |
+
"scores": {
|
| 95 |
+
"overall": 44.97,
|
| 96 |
+
"stages": {
|
| 97 |
+
"perception": 44.27,
|
| 98 |
+
"understanding": 42.11,
|
| 99 |
+
"reasoning": 64.03,
|
| 100 |
+
"sensation": 29.48
|
| 101 |
+
},
|
| 102 |
+
"taxonomy": {
|
| 103 |
+
"l1_task": 50.14,
|
| 104 |
+
"l2_modality": 49.21,
|
| 105 |
+
"l3_stage": 39.79,
|
| 106 |
+
"l4_domain": 27.12
|
| 107 |
+
},
|
| 108 |
+
"tasks": {}
|
| 109 |
+
},
|
| 110 |
+
"notes": "Paper-reported scores. The paper table does not specify a dated API snapshot or sample coverage."
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"id": "qwen2-5-omni-paper-2606-07643",
|
| 114 |
+
"model_name": "Qwen2.5-Omni",
|
| 115 |
+
"provider": "Alibaba Cloud",
|
| 116 |
+
"model_id": "Qwen2.5-Omni (paper label)",
|
| 117 |
+
"benchmark_version": "paper-2606.07643",
|
| 118 |
+
"source": {
|
| 119 |
+
"type": "paper",
|
| 120 |
+
"url": "https://arxiv.org/abs/2606.07643"
|
| 121 |
+
},
|
| 122 |
+
"evaluation_date": null,
|
| 123 |
+
"coverage": {
|
| 124 |
+
"status": "full",
|
| 125 |
+
"tasks_completed": 14,
|
| 126 |
+
"tasks_total": 14,
|
| 127 |
+
"samples_completed": null,
|
| 128 |
+
"samples_total": null
|
| 129 |
+
},
|
| 130 |
+
"scores": {
|
| 131 |
+
"overall": 41.33,
|
| 132 |
+
"stages": {
|
| 133 |
+
"perception": 42.81,
|
| 134 |
+
"understanding": 39.68,
|
| 135 |
+
"reasoning": 58.26,
|
| 136 |
+
"sensation": 24.59
|
| 137 |
+
},
|
| 138 |
+
"taxonomy": {
|
| 139 |
+
"l1_task": 46.92,
|
| 140 |
+
"l2_modality": 45.93,
|
| 141 |
+
"l3_stage": 37.61,
|
| 142 |
+
"l4_domain": 25.89
|
| 143 |
+
},
|
| 144 |
+
"tasks": {}
|
| 145 |
+
},
|
| 146 |
+
"notes": "Paper-reported scores. The paper table does not specify a dated API snapshot or sample coverage."
|
| 147 |
+
},
|
| 148 |
+
{
|
| 149 |
+
"id": "qwen-omni-turbo-paper-2606-07643",
|
| 150 |
+
"model_name": "Qwen-Omni-Turbo",
|
| 151 |
+
"provider": "Alibaba Cloud",
|
| 152 |
+
"model_id": "Qwen-Omni-Turbo (paper label)",
|
| 153 |
+
"benchmark_version": "paper-2606.07643",
|
| 154 |
+
"source": {
|
| 155 |
+
"type": "paper",
|
| 156 |
+
"url": "https://arxiv.org/abs/2606.07643"
|
| 157 |
+
},
|
| 158 |
+
"evaluation_date": null,
|
| 159 |
+
"coverage": {
|
| 160 |
+
"status": "full",
|
| 161 |
+
"tasks_completed": 14,
|
| 162 |
+
"tasks_total": 14,
|
| 163 |
+
"samples_completed": null,
|
| 164 |
+
"samples_total": null
|
| 165 |
+
},
|
| 166 |
+
"scores": {
|
| 167 |
+
"overall": null,
|
| 168 |
+
"stages": {},
|
| 169 |
+
"taxonomy": {
|
| 170 |
+
"l1_task": 46.5,
|
| 171 |
+
"l2_modality": 45.15,
|
| 172 |
+
"l3_stage": 37.7,
|
| 173 |
+
"l4_domain": 26.13
|
| 174 |
+
},
|
| 175 |
+
"tasks": {}
|
| 176 |
+
},
|
| 177 |
+
"notes": "Paper reports taxonomy scores only. The paper table does not specify a dated API snapshot or sample coverage."
|
| 178 |
+
},
|
| 179 |
+
{
|
| 180 |
+
"id": "gpt-4o-paper-2606-07643",
|
| 181 |
+
"model_name": "GPT-4o",
|
| 182 |
+
"provider": "OpenAI",
|
| 183 |
+
"model_id": "GPT-4o (paper label)",
|
| 184 |
+
"benchmark_version": "paper-2606.07643",
|
| 185 |
+
"source": {
|
| 186 |
+
"type": "paper",
|
| 187 |
+
"url": "https://arxiv.org/abs/2606.07643"
|
| 188 |
+
},
|
| 189 |
+
"evaluation_date": null,
|
| 190 |
+
"coverage": {
|
| 191 |
+
"status": "full",
|
| 192 |
+
"tasks_completed": 14,
|
| 193 |
+
"tasks_total": 14,
|
| 194 |
+
"samples_completed": null,
|
| 195 |
+
"samples_total": null
|
| 196 |
+
},
|
| 197 |
+
"scores": {
|
| 198 |
+
"overall": 40.68,
|
| 199 |
+
"stages": {
|
| 200 |
+
"perception": 40.45,
|
| 201 |
+
"understanding": 48.6,
|
| 202 |
+
"reasoning": 56.87,
|
| 203 |
+
"sensation": 16.81
|
| 204 |
+
},
|
| 205 |
+
"taxonomy": {
|
| 206 |
+
"l1_task": 48.64,
|
| 207 |
+
"l2_modality": 47.19,
|
| 208 |
+
"l3_stage": 41.93,
|
| 209 |
+
"l4_domain": 0.55
|
| 210 |
+
},
|
| 211 |
+
"tasks": {}
|
| 212 |
+
},
|
| 213 |
+
"notes": "Paper-reported scores. The paper table does not specify a dated API snapshot or sample coverage."
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"id": "baichuan-omni-paper-2606-07643",
|
| 217 |
+
"model_name": "Baichuan-Omni",
|
| 218 |
+
"provider": "Baichuan",
|
| 219 |
+
"model_id": "Baichuan-Omni (paper label)",
|
| 220 |
+
"benchmark_version": "paper-2606.07643",
|
| 221 |
+
"source": {
|
| 222 |
+
"type": "paper",
|
| 223 |
+
"url": "https://arxiv.org/abs/2606.07643"
|
| 224 |
+
},
|
| 225 |
+
"evaluation_date": null,
|
| 226 |
+
"coverage": {
|
| 227 |
+
"status": "full",
|
| 228 |
+
"tasks_completed": 14,
|
| 229 |
+
"tasks_total": 14,
|
| 230 |
+
"samples_completed": null,
|
| 231 |
+
"samples_total": null
|
| 232 |
+
},
|
| 233 |
+
"scores": {
|
| 234 |
+
"overall": null,
|
| 235 |
+
"stages": {},
|
| 236 |
+
"taxonomy": {
|
| 237 |
+
"l1_task": 37.35,
|
| 238 |
+
"l2_modality": 35.8,
|
| 239 |
+
"l3_stage": 30.18,
|
| 240 |
+
"l4_domain": 24.1
|
| 241 |
+
},
|
| 242 |
+
"tasks": {}
|
| 243 |
+
},
|
| 244 |
+
"notes": "Paper reports taxonomy scores only. The paper table does not specify a dated API snapshot or sample coverage."
|
| 245 |
+
}
|
| 246 |
+
]
|
| 247 |
+
}
|
index.html
CHANGED
|
@@ -1,19 +1,570 @@
|
|
| 1 |
<!doctype html>
|
| 2 |
-
<html>
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 19 |
</html>
|
|
|
|
| 1 |
<!doctype html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 6 |
+
<meta name="description" content="Community leaderboard for AVI-Bench audio-visual intelligence evaluations.">
|
| 7 |
+
<meta name="theme-color" content="#f6f1e8">
|
| 8 |
+
<title>AVI-Bench Leaderboard</title>
|
| 9 |
+
<style>
|
| 10 |
+
:root {
|
| 11 |
+
color-scheme: light;
|
| 12 |
+
--paper: #f6f1e8;
|
| 13 |
+
--paper-deep: #ece5d6;
|
| 14 |
+
--ink: #1a1a1a;
|
| 15 |
+
--muted: #6c675f;
|
| 16 |
+
--rule: #d1c7b4;
|
| 17 |
+
--accent: #8a2422;
|
| 18 |
+
--accent-soft: #f3e4de;
|
| 19 |
+
--green: #38604d;
|
| 20 |
+
--sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
| 21 |
+
--serif: Georgia, "Times New Roman", serif;
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
* { box-sizing: border-box; }
|
| 25 |
+
body {
|
| 26 |
+
margin: 0;
|
| 27 |
+
background: var(--paper);
|
| 28 |
+
color: var(--ink);
|
| 29 |
+
font-family: var(--sans);
|
| 30 |
+
font-size: 15px;
|
| 31 |
+
line-height: 1.55;
|
| 32 |
+
}
|
| 33 |
+
a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
|
| 34 |
+
a:hover { color: #5f1716; }
|
| 35 |
+
button, input, select { font: inherit; }
|
| 36 |
+
.page { width: min(1440px, 100% - 40px); margin: 0 auto; }
|
| 37 |
+
header { border-bottom: 1px solid var(--rule); }
|
| 38 |
+
.masthead {
|
| 39 |
+
min-height: 58px;
|
| 40 |
+
display: flex;
|
| 41 |
+
align-items: center;
|
| 42 |
+
justify-content: space-between;
|
| 43 |
+
gap: 16px;
|
| 44 |
+
color: var(--muted);
|
| 45 |
+
font-size: 12px;
|
| 46 |
+
letter-spacing: .12em;
|
| 47 |
+
text-transform: uppercase;
|
| 48 |
+
}
|
| 49 |
+
.brand { color: var(--ink); font-family: var(--serif); font-size: 19px; font-weight: 700; letter-spacing: 0; text-transform: none; }
|
| 50 |
+
.brand span { color: var(--accent); }
|
| 51 |
+
.hero { padding: 54px 0 40px; }
|
| 52 |
+
.eyebrow { margin: 0 0 10px; color: var(--accent); font-size: 11px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; }
|
| 53 |
+
h1, h2, h3 { font-family: var(--serif); font-weight: 500; }
|
| 54 |
+
h1 { margin: 0; font-size: clamp(36px, 6vw, 64px); letter-spacing: -.04em; line-height: 1.02; }
|
| 55 |
+
.intro { max-width: 760px; margin: 16px 0 0; color: #4c4944; font-family: var(--serif); font-size: 19px; }
|
| 56 |
+
.links { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 20px; font-size: 13px; }
|
| 57 |
+
.callout {
|
| 58 |
+
display: grid;
|
| 59 |
+
grid-template-columns: minmax(0, 1fr) auto;
|
| 60 |
+
align-items: center;
|
| 61 |
+
gap: 18px;
|
| 62 |
+
margin: 0 0 30px;
|
| 63 |
+
padding: 18px 20px;
|
| 64 |
+
border: 1px solid var(--rule);
|
| 65 |
+
background: rgba(255, 255, 255, .35);
|
| 66 |
+
}
|
| 67 |
+
.callout p { margin: 0; color: #45413b; }
|
| 68 |
+
.button-link {
|
| 69 |
+
display: inline-block;
|
| 70 |
+
border: 1px solid var(--ink);
|
| 71 |
+
padding: 9px 13px;
|
| 72 |
+
color: var(--ink);
|
| 73 |
+
font-size: 12px;
|
| 74 |
+
font-weight: 700;
|
| 75 |
+
text-decoration: none;
|
| 76 |
+
white-space: nowrap;
|
| 77 |
+
}
|
| 78 |
+
.button-link:hover { background: var(--ink); color: var(--paper); }
|
| 79 |
+
.section-heading { display: flex; align-items: end; justify-content: space-between; gap: 20px; margin: 0 0 16px; }
|
| 80 |
+
.section-heading h2 { margin: 0; font-size: 30px; letter-spacing: -.02em; }
|
| 81 |
+
#summary { color: var(--muted); font-size: 12px; text-align: right; }
|
| 82 |
+
.filters {
|
| 83 |
+
display: grid;
|
| 84 |
+
grid-template-columns: minmax(200px, 1.5fr) repeat(3, minmax(145px, .7fr));
|
| 85 |
+
gap: 10px;
|
| 86 |
+
margin-bottom: 13px;
|
| 87 |
+
}
|
| 88 |
+
.filters input, .filters select {
|
| 89 |
+
width: 100%;
|
| 90 |
+
min-height: 42px;
|
| 91 |
+
border: 1px solid var(--rule);
|
| 92 |
+
border-radius: 0;
|
| 93 |
+
background: #fffdf9;
|
| 94 |
+
color: var(--ink);
|
| 95 |
+
padding: 9px 11px;
|
| 96 |
+
}
|
| 97 |
+
.filters input:focus, .filters select:focus, button:focus-visible, a:focus-visible {
|
| 98 |
+
outline: 3px solid #c5806d;
|
| 99 |
+
outline-offset: 2px;
|
| 100 |
+
}
|
| 101 |
+
.table-shell { overflow-x: auto; border: 1px solid var(--rule); background: #fffdf9; }
|
| 102 |
+
table { width: 100%; min-width: 1120px; border-collapse: collapse; font-size: 12px; }
|
| 103 |
+
th, td { padding: 11px 12px; border-bottom: 1px solid #e9e2d5; text-align: right; white-space: nowrap; }
|
| 104 |
+
th { background: var(--paper-deep); color: #47423c; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; }
|
| 105 |
+
th:first-child, td:first-child, th:nth-child(2), td:nth-child(2), th:nth-child(3), td:nth-child(3) { text-align: left; }
|
| 106 |
+
tbody tr:last-child td { border-bottom: 0; }
|
| 107 |
+
tbody tr:hover td { background: #faf5eb; }
|
| 108 |
+
.sort-button { padding: 0; border: 0; background: none; color: inherit; font-size: inherit; font-weight: 700; letter-spacing: inherit; text-transform: inherit; cursor: pointer; }
|
| 109 |
+
.model-cell { min-width: 170px; }
|
| 110 |
+
.model-name { display: block; color: var(--ink); font-weight: 700; }
|
| 111 |
+
.model-id { display: block; max-width: 240px; overflow: hidden; color: var(--muted); font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 10px; text-overflow: ellipsis; }
|
| 112 |
+
.source-tag, .coverage-tag { display: inline-block; border: 1px solid var(--rule); padding: 2px 6px; background: #fff; color: #514b43; font-size: 10px; }
|
| 113 |
+
.source-paper { border-color: #d6b6a7; background: var(--accent-soft); color: #71312a; }
|
| 114 |
+
.coverage-full { border-color: #b6cbbd; background: #edf4ef; color: var(--green); }
|
| 115 |
+
.score { font-variant-numeric: tabular-nums; }
|
| 116 |
+
.score-overall { color: var(--accent); font-weight: 800; }
|
| 117 |
+
.details-row td { padding: 0; text-align: left; white-space: normal; }
|
| 118 |
+
details { padding: 10px 12px; }
|
| 119 |
+
summary { color: var(--accent); cursor: pointer; font-size: 11px; font-weight: 700; }
|
| 120 |
+
.detail-content { display: grid; grid-template-columns: repeat(3, minmax(150px, 1fr)); gap: 12px; padding: 13px 0 4px; }
|
| 121 |
+
.detail-block h3 { margin: 0 0 5px; font-family: var(--sans); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; }
|
| 122 |
+
.detail-block p { margin: 3px 0; color: #514b43; font-size: 11px; overflow-wrap: anywhere; }
|
| 123 |
+
.empty, .error { padding: 28px 16px; color: var(--muted); text-align: center; }
|
| 124 |
+
.error { color: #8a2422; }
|
| 125 |
+
.footnote { margin: 12px 0 40px; color: var(--muted); font-size: 11px; }
|
| 126 |
+
.contribute { margin: 42px 0 54px; padding: 26px; border-top: 2px solid var(--accent); background: var(--paper-deep); }
|
| 127 |
+
.contribute h2 { margin: 0 0 7px; font-size: 26px; }
|
| 128 |
+
.contribute p { max-width: 760px; margin: 0 0 15px; color: #4c4944; }
|
| 129 |
+
footer { border-top: 1px solid var(--rule); padding: 20px 0 28px; color: var(--muted); font-size: 11px; }
|
| 130 |
+
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
|
| 131 |
+
|
| 132 |
+
@media (max-width: 760px) {
|
| 133 |
+
.page { width: min(100% - 24px, 1440px); }
|
| 134 |
+
.hero { padding: 38px 0 28px; }
|
| 135 |
+
.callout { grid-template-columns: 1fr; }
|
| 136 |
+
.button-link { justify-self: start; }
|
| 137 |
+
.filters { grid-template-columns: 1fr 1fr; }
|
| 138 |
+
.filters input { grid-column: 1 / -1; }
|
| 139 |
+
.section-heading { align-items: start; flex-direction: column; gap: 4px; }
|
| 140 |
+
#summary { text-align: left; }
|
| 141 |
+
.detail-content { grid-template-columns: 1fr 1fr; }
|
| 142 |
+
}
|
| 143 |
+
@media (max-width: 440px) {
|
| 144 |
+
.masthead { font-size: 10px; }
|
| 145 |
+
.intro { font-size: 17px; }
|
| 146 |
+
.filters { grid-template-columns: 1fr; }
|
| 147 |
+
.filters input { grid-column: auto; }
|
| 148 |
+
.detail-content { grid-template-columns: 1fr; }
|
| 149 |
+
.contribute { padding: 20px 16px; }
|
| 150 |
+
}
|
| 151 |
+
</style>
|
| 152 |
+
</head>
|
| 153 |
+
<body>
|
| 154 |
+
<header>
|
| 155 |
+
<div class="page masthead">
|
| 156 |
+
<div class="brand">AVI<span>·</span>Bench</div>
|
| 157 |
+
<div>Audio-Visual Intelligence · Community Leaderboard</div>
|
| 158 |
+
</div>
|
| 159 |
+
</header>
|
| 160 |
+
|
| 161 |
+
<main class="page">
|
| 162 |
+
<section class="hero" aria-labelledby="page-title">
|
| 163 |
+
<p class="eyebrow">Community results</p>
|
| 164 |
+
<h1 id="page-title">AVI-Bench Leaderboard</h1>
|
| 165 |
+
<p class="intro">Compare audio-visual intelligence results across perception, understanding, reasoning, and primitive sensation. Every entry links to its reported source.</p>
|
| 166 |
+
<nav class="links" aria-label="Project links">
|
| 167 |
+
<a href="https://fudancvl.github.io/AVI-Bench/">Project page</a>
|
| 168 |
+
<a href="https://github.com/FudanCVL/AVI-Bench">Code</a>
|
| 169 |
+
<a href="https://huggingface.co/datasets/FudanCVL/AVIBench">Dataset</a>
|
| 170 |
+
<a href="https://arxiv.org/abs/2606.07643">Paper</a>
|
| 171 |
+
</nav>
|
| 172 |
+
</section>
|
| 173 |
+
|
| 174 |
+
<aside class="callout">
|
| 175 |
+
<p><strong>Contribute a result.</strong> Submit a pull request with the required model, benchmark, coverage, score, and source information. A maintainer reviews it before merge. A merged entry identifies its source; it does not imply an independent reproduction.</p>
|
| 176 |
+
<a class="button-link" href="https://huggingface.co/spaces/FudanCVL/AVI-Bench/tree/main">Submission guide</a>
|
| 177 |
+
</aside>
|
| 178 |
+
|
| 179 |
+
<section aria-labelledby="results-title">
|
| 180 |
+
<div class="section-heading">
|
| 181 |
+
<div>
|
| 182 |
+
<p class="eyebrow">Results</p>
|
| 183 |
+
<h2 id="results-title">Model comparison</h2>
|
| 184 |
+
</div>
|
| 185 |
+
<div id="summary" aria-live="polite">Loading results…</div>
|
| 186 |
+
</div>
|
| 187 |
+
|
| 188 |
+
<div class="filters" aria-label="Leaderboard filters">
|
| 189 |
+
<label class="sr-only" for="search">Search models</label>
|
| 190 |
+
<input id="search" type="search" placeholder="Search model, provider, or ID">
|
| 191 |
+
<label class="sr-only" for="benchmark-filter">Filter benchmark version</label>
|
| 192 |
+
<select id="benchmark-filter"><option value="all">All benchmark versions</option></select>
|
| 193 |
+
<label class="sr-only" for="provider-filter">Filter provider</label>
|
| 194 |
+
<select id="provider-filter"><option value="all">All providers</option></select>
|
| 195 |
+
<label class="sr-only" for="source-filter">Filter source</label>
|
| 196 |
+
<select id="source-filter"><option value="all">All sources</option></select>
|
| 197 |
+
</div>
|
| 198 |
+
|
| 199 |
+
<div class="table-shell">
|
| 200 |
+
<table aria-describedby="leaderboard-note">
|
| 201 |
+
<thead>
|
| 202 |
+
<tr>
|
| 203 |
+
<th><button class="sort-button" data-sort="rank" aria-label="Sort by rank">Rank</button></th>
|
| 204 |
+
<th><button class="sort-button" data-sort="model_name">Model</button></th>
|
| 205 |
+
<th><button class="sort-button" data-sort="source">Source</button></th>
|
| 206 |
+
<th><button class="sort-button" data-sort="benchmark_version">Benchmark</button></th>
|
| 207 |
+
<th><button class="sort-button" data-sort="coverage">Coverage</button></th>
|
| 208 |
+
<th><button class="sort-button" data-sort="overall" aria-sort="descending">Overall</button></th>
|
| 209 |
+
<th><button class="sort-button" data-sort="perception">Perception</button></th>
|
| 210 |
+
<th><button class="sort-button" data-sort="understanding">Understanding</button></th>
|
| 211 |
+
<th><button class="sort-button" data-sort="reasoning">Reasoning</button></th>
|
| 212 |
+
<th><button class="sort-button" data-sort="sensation">Sensation</button></th>
|
| 213 |
+
<th><button class="sort-button" data-sort="l1_task">L1</button></th>
|
| 214 |
+
<th><button class="sort-button" data-sort="l2_modality">L2</button></th>
|
| 215 |
+
<th><button class="sort-button" data-sort="l3_stage">L3</button></th>
|
| 216 |
+
<th><button class="sort-button" data-sort="l4_domain">L4</button></th>
|
| 217 |
+
<th><span class="sr-only">Details</span></th>
|
| 218 |
+
</tr>
|
| 219 |
+
</thead>
|
| 220 |
+
<tbody id="results-body">
|
| 221 |
+
<tr><td class="empty" colspan="15">Loading results…</td></tr>
|
| 222 |
+
</tbody>
|
| 223 |
+
</table>
|
| 224 |
+
</div>
|
| 225 |
+
<p id="leaderboard-note" class="footnote">Scores use percentage points (0–100). Full evaluations with an overall score are ranked within their benchmark version; partial evaluations and entries without an overall score remain visible without a rank. Source labels identify where a score was reported, not an official audit badge.</p>
|
| 226 |
+
</section>
|
| 227 |
+
|
| 228 |
+
<section class="contribute" aria-labelledby="contribute-title">
|
| 229 |
+
<p class="eyebrow">Open contribution</p>
|
| 230 |
+
<h2 id="contribute-title">Add a result by pull request</h2>
|
| 231 |
+
<p>Copy the result template, add one record to the results file, and open a PR in this Space repository. Include a public source link and keep the diff limited to score metadata. Do not submit benchmark samples, labels, raw model responses, or credentials.</p>
|
| 232 |
+
<a class="button-link" href="https://huggingface.co/spaces/FudanCVL/AVI-Bench/discussions">Open Space community</a>
|
| 233 |
+
<a class="button-link" href="https://huggingface.co/spaces/FudanCVL/AVI-Bench/tree/main">View files and guide</a>
|
| 234 |
+
</section>
|
| 235 |
+
</main>
|
| 236 |
+
|
| 237 |
+
<footer>
|
| 238 |
+
<div class="page">AVI-Bench © 2026. Dataset use is governed by the <a href="https://github.com/FudanCVL/AVI-Bench/blob/main/DATA_USE_POLICY.md">AVI-Bench Data Use Policy</a>.</div>
|
| 239 |
+
</footer>
|
| 240 |
+
|
| 241 |
+
<script>
|
| 242 |
+
(function () {
|
| 243 |
+
"use strict";
|
| 244 |
+
|
| 245 |
+
var SOURCE_LABELS = {
|
| 246 |
+
paper: "Paper reported",
|
| 247 |
+
participant: "Participant submission",
|
| 248 |
+
maintainer: "Maintainer evaluation"
|
| 249 |
+
};
|
| 250 |
+
var entries = [];
|
| 251 |
+
var rankById = new Map();
|
| 252 |
+
var sortKey = "overall";
|
| 253 |
+
var sortDirection = -1;
|
| 254 |
+
var body = document.getElementById("results-body");
|
| 255 |
+
var summary = document.getElementById("summary");
|
| 256 |
+
var search = document.getElementById("search");
|
| 257 |
+
var benchmarkFilter = document.getElementById("benchmark-filter");
|
| 258 |
+
var providerFilter = document.getElementById("provider-filter");
|
| 259 |
+
var sourceFilter = document.getElementById("source-filter");
|
| 260 |
+
|
| 261 |
+
function text(value) {
|
| 262 |
+
return value === null || value === undefined || value === "" ? "—" : String(value);
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
function score(value) {
|
| 266 |
+
return typeof value === "number" && Number.isFinite(value) ? value.toFixed(2) : "—";
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
function compareText(left, right) {
|
| 270 |
+
return String(left || "").localeCompare(String(right || ""), undefined, { numeric: true, sensitivity: "base" });
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
function addOption(select, value, label) {
|
| 274 |
+
var option = document.createElement("option");
|
| 275 |
+
option.value = value;
|
| 276 |
+
option.textContent = label;
|
| 277 |
+
select.appendChild(option);
|
| 278 |
+
}
|
| 279 |
+
|
| 280 |
+
function populateFilters() {
|
| 281 |
+
Array.from(new Set(entries.map(function (entry) { return entry.benchmark_version; })))
|
| 282 |
+
.sort(compareText).forEach(function (value) { addOption(benchmarkFilter, value, value); });
|
| 283 |
+
Array.from(new Set(entries.map(function (entry) { return entry.provider; })))
|
| 284 |
+
.sort(compareText).forEach(function (value) { addOption(providerFilter, value, value); });
|
| 285 |
+
Array.from(new Set(entries.map(function (entry) { return entry.source.type; })))
|
| 286 |
+
.sort(compareText).forEach(function (value) { addOption(sourceFilter, value, SOURCE_LABELS[value] || value); });
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
function buildRanks() {
|
| 290 |
+
var groups = new Map();
|
| 291 |
+
entries.filter(function (entry) {
|
| 292 |
+
return entry.coverage.status === "full" && typeof entry.scores.overall === "number";
|
| 293 |
+
}).forEach(function (entry) {
|
| 294 |
+
var version = entry.benchmark_version;
|
| 295 |
+
if (!groups.has(version)) groups.set(version, []);
|
| 296 |
+
groups.get(version).push(entry);
|
| 297 |
+
});
|
| 298 |
+
groups.forEach(function (group) {
|
| 299 |
+
group.sort(function (a, b) { return b.scores.overall - a.scores.overall || compareText(a.model_name, b.model_name); });
|
| 300 |
+
group.forEach(function (entry, index) { rankById.set(entry.id, index + 1); });
|
| 301 |
+
});
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
function matches(entry) {
|
| 305 |
+
var query = search.value.trim().toLowerCase();
|
| 306 |
+
var haystack = [entry.model_name, entry.model_id, entry.provider].join(" ").toLowerCase();
|
| 307 |
+
return (!query || haystack.indexOf(query) !== -1)
|
| 308 |
+
&& (benchmarkFilter.value === "all" || entry.benchmark_version === benchmarkFilter.value)
|
| 309 |
+
&& (providerFilter.value === "all" || entry.provider === providerFilter.value)
|
| 310 |
+
&& (sourceFilter.value === "all" || entry.source.type === sourceFilter.value);
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
function sortValue(entry, key) {
|
| 314 |
+
if (key === "rank") return rankById.has(entry.id) ? rankById.get(entry.id) : Infinity;
|
| 315 |
+
if (key === "model_name" || key === "benchmark_version" || key === "provider") return entry[key];
|
| 316 |
+
if (key === "source") return SOURCE_LABELS[entry.source.type] || entry.source.type;
|
| 317 |
+
if (key === "coverage") return entry.coverage.tasks_completed / entry.coverage.tasks_total;
|
| 318 |
+
if (key === "overall") return entry.scores.overall;
|
| 319 |
+
if (["perception", "understanding", "reasoning", "sensation"].indexOf(key) !== -1) return (entry.scores.stages || {})[key];
|
| 320 |
+
return (entry.scores.taxonomy || {})[key];
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
function compareEntries(a, b) {
|
| 324 |
+
if (sortKey !== "benchmark_version") {
|
| 325 |
+
var versionOrder = compareText(a.benchmark_version, b.benchmark_version);
|
| 326 |
+
if (versionOrder !== 0) return versionOrder;
|
| 327 |
+
}
|
| 328 |
+
var left = sortValue(a, sortKey);
|
| 329 |
+
var right = sortValue(b, sortKey);
|
| 330 |
+
if (sortKey === "rank" && (left === Infinity || right === Infinity)) {
|
| 331 |
+
if (left !== right) return left === Infinity ? 1 : -1;
|
| 332 |
+
}
|
| 333 |
+
if (left === null || left === undefined || right === null || right === undefined) {
|
| 334 |
+
if (left !== right) return left === null || left === undefined ? 1 : -1;
|
| 335 |
+
}
|
| 336 |
+
if (typeof left === "number" || typeof right === "number") {
|
| 337 |
+
left = typeof left === "number" ? left : -Infinity;
|
| 338 |
+
right = typeof right === "number" ? right : -Infinity;
|
| 339 |
+
if (left !== right) return (left - right) * sortDirection;
|
| 340 |
+
} else {
|
| 341 |
+
var textOrder = compareText(left, right);
|
| 342 |
+
if (textOrder !== 0) return textOrder * sortDirection;
|
| 343 |
+
}
|
| 344 |
+
return compareText(a.model_name, b.model_name);
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
function makeCell(value, className) {
|
| 348 |
+
var cell = document.createElement("td");
|
| 349 |
+
if (className) cell.className = className;
|
| 350 |
+
cell.textContent = value;
|
| 351 |
+
return cell;
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
function addDetailBlock(container, title, lines) {
|
| 355 |
+
var block = document.createElement("div");
|
| 356 |
+
block.className = "detail-block";
|
| 357 |
+
var heading = document.createElement("h3");
|
| 358 |
+
heading.textContent = title;
|
| 359 |
+
block.appendChild(heading);
|
| 360 |
+
lines.forEach(function (line) {
|
| 361 |
+
var paragraph = document.createElement("p");
|
| 362 |
+
paragraph.textContent = line;
|
| 363 |
+
block.appendChild(paragraph);
|
| 364 |
+
});
|
| 365 |
+
container.appendChild(block);
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
function detailRow(entry) {
|
| 369 |
+
var row = document.createElement("tr");
|
| 370 |
+
row.className = "details-row";
|
| 371 |
+
var cell = document.createElement("td");
|
| 372 |
+
cell.colSpan = 15;
|
| 373 |
+
var details = document.createElement("details");
|
| 374 |
+
var summaryLine = document.createElement("summary");
|
| 375 |
+
summaryLine.textContent = "Details and task scores";
|
| 376 |
+
details.appendChild(summaryLine);
|
| 377 |
+
var content = document.createElement("div");
|
| 378 |
+
content.className = "detail-content";
|
| 379 |
+
|
| 380 |
+
var coverage = entry.coverage;
|
| 381 |
+
var sampleCoverage = coverage.samples_total === null || coverage.samples_total === undefined
|
| 382 |
+
? "Sample count not reported"
|
| 383 |
+
: text(coverage.samples_completed) + " / " + text(coverage.samples_total) + " samples";
|
| 384 |
+
var sourceType = SOURCE_LABELS[entry.source.type] || entry.source.type;
|
| 385 |
+
addDetailBlock(content, "Record", [
|
| 386 |
+
"Model ID: " + entry.model_id,
|
| 387 |
+
"Provider: " + entry.provider,
|
| 388 |
+
"Benchmark: " + entry.benchmark_version,
|
| 389 |
+
"Evaluation date: " + text(entry.evaluation_date),
|
| 390 |
+
"Source type: " + sourceType,
|
| 391 |
+
"Coverage: " + coverage.tasks_completed + " / " + coverage.tasks_total + " tasks; " + sampleCoverage
|
| 392 |
+
]);
|
| 393 |
+
addDetailBlock(content, "Scores", [
|
| 394 |
+
"Overall: " + score(entry.scores.overall),
|
| 395 |
+
"Stages: " + Object.keys(entry.scores.stages || {}).map(function (key) {
|
| 396 |
+
return key + " " + score(entry.scores.stages[key]);
|
| 397 |
+
}).join(" · ") || "No stage scores reported",
|
| 398 |
+
"Taxonomy: " + Object.keys(entry.scores.taxonomy || {}).map(function (key) {
|
| 399 |
+
return key.toUpperCase() + " " + score(entry.scores.taxonomy[key]);
|
| 400 |
+
}).join(" · ") || "No taxonomy scores reported"
|
| 401 |
+
]);
|
| 402 |
+
var sourceBlock = document.createElement("div");
|
| 403 |
+
sourceBlock.className = "detail-block";
|
| 404 |
+
var sourceHeading = document.createElement("h3");
|
| 405 |
+
sourceHeading.textContent = "Source and notes";
|
| 406 |
+
sourceBlock.appendChild(sourceHeading);
|
| 407 |
+
var sourceLink = document.createElement("a");
|
| 408 |
+
sourceLink.href = entry.source.url;
|
| 409 |
+
sourceLink.target = "_blank";
|
| 410 |
+
sourceLink.rel = "noopener noreferrer";
|
| 411 |
+
sourceLink.textContent = "Open source";
|
| 412 |
+
sourceBlock.appendChild(sourceLink);
|
| 413 |
+
if (entry.submitter) {
|
| 414 |
+
var submitter = document.createElement("p");
|
| 415 |
+
submitter.textContent = "Submitted by: " + entry.submitter;
|
| 416 |
+
sourceBlock.appendChild(submitter);
|
| 417 |
+
}
|
| 418 |
+
if (entry.notes) {
|
| 419 |
+
var notes = document.createElement("p");
|
| 420 |
+
notes.textContent = entry.notes;
|
| 421 |
+
sourceBlock.appendChild(notes);
|
| 422 |
+
}
|
| 423 |
+
content.appendChild(sourceBlock);
|
| 424 |
+
|
| 425 |
+
var taskScores = entry.scores.tasks || {};
|
| 426 |
+
var taskLines = Object.keys(taskScores).sort(compareText).map(function (task) {
|
| 427 |
+
var value = taskScores[task];
|
| 428 |
+
if (value && typeof value === "object") {
|
| 429 |
+
return task + ": " + Object.keys(value).sort(compareText).map(function (metric) {
|
| 430 |
+
return metric + " " + score(value[metric]);
|
| 431 |
+
}).join(" · ");
|
| 432 |
+
}
|
| 433 |
+
return task + ": " + score(value);
|
| 434 |
+
});
|
| 435 |
+
if (taskLines.length) addDetailBlock(content, "Task scores", taskLines);
|
| 436 |
+
|
| 437 |
+
details.appendChild(content);
|
| 438 |
+
cell.appendChild(details);
|
| 439 |
+
row.appendChild(cell);
|
| 440 |
+
return row;
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
function render() {
|
| 444 |
+
var visible = entries.filter(matches).sort(compareEntries);
|
| 445 |
+
body.replaceChildren();
|
| 446 |
+
if (!visible.length) {
|
| 447 |
+
var emptyRow = document.createElement("tr");
|
| 448 |
+
var emptyCell = document.createElement("td");
|
| 449 |
+
emptyCell.className = "empty";
|
| 450 |
+
emptyCell.colSpan = 15;
|
| 451 |
+
emptyCell.textContent = entries.length ? "No results match these filters." : "No merged results yet. Submit a result by pull request.";
|
| 452 |
+
emptyRow.appendChild(emptyCell);
|
| 453 |
+
body.appendChild(emptyRow);
|
| 454 |
+
summary.textContent = entries.length ? "0 matching records" : "No results published yet";
|
| 455 |
+
return;
|
| 456 |
+
}
|
| 457 |
+
|
| 458 |
+
visible.forEach(function (entry) {
|
| 459 |
+
var row = document.createElement("tr");
|
| 460 |
+
var rank = rankById.get(entry.id);
|
| 461 |
+
row.appendChild(makeCell(rank ? String(rank) : "—"));
|
| 462 |
+
|
| 463 |
+
var modelCell = document.createElement("td");
|
| 464 |
+
modelCell.className = "model-cell";
|
| 465 |
+
var modelName = document.createElement("span");
|
| 466 |
+
modelName.className = "model-name";
|
| 467 |
+
modelName.textContent = entry.model_name;
|
| 468 |
+
var modelId = document.createElement("span");
|
| 469 |
+
modelId.className = "model-id";
|
| 470 |
+
modelId.textContent = entry.model_id;
|
| 471 |
+
modelCell.appendChild(modelName);
|
| 472 |
+
modelCell.appendChild(modelId);
|
| 473 |
+
row.appendChild(modelCell);
|
| 474 |
+
|
| 475 |
+
var sourceCell = document.createElement("td");
|
| 476 |
+
var sourceTag = document.createElement("span");
|
| 477 |
+
sourceTag.className = "source-tag" + (entry.source.type === "paper" ? " source-paper" : "");
|
| 478 |
+
sourceTag.textContent = SOURCE_LABELS[entry.source.type] || entry.source.type;
|
| 479 |
+
sourceCell.appendChild(sourceTag);
|
| 480 |
+
row.appendChild(sourceCell);
|
| 481 |
+
row.appendChild(makeCell(entry.benchmark_version));
|
| 482 |
+
|
| 483 |
+
var coverageCell = document.createElement("td");
|
| 484 |
+
var coverageTag = document.createElement("span");
|
| 485 |
+
coverageTag.className = "coverage-tag" + (entry.coverage.status === "full" ? " coverage-full" : "");
|
| 486 |
+
coverageTag.textContent = entry.coverage.tasks_completed + "/" + entry.coverage.tasks_total + " tasks";
|
| 487 |
+
coverageCell.appendChild(coverageTag);
|
| 488 |
+
row.appendChild(coverageCell);
|
| 489 |
+
|
| 490 |
+
row.appendChild(makeCell(score(entry.scores.overall), "score score-overall"));
|
| 491 |
+
var stages = entry.scores.stages || {};
|
| 492 |
+
["perception", "understanding", "reasoning", "sensation"].forEach(function (key) {
|
| 493 |
+
row.appendChild(makeCell(score(stages[key]), "score"));
|
| 494 |
+
});
|
| 495 |
+
var taxonomy = entry.scores.taxonomy || {};
|
| 496 |
+
["l1_task", "l2_modality", "l3_stage", "l4_domain"].forEach(function (key) {
|
| 497 |
+
row.appendChild(makeCell(score(taxonomy[key]), "score"));
|
| 498 |
+
});
|
| 499 |
+
var detailCell = document.createElement("td");
|
| 500 |
+
var detailButton = document.createElement("button");
|
| 501 |
+
detailButton.className = "sort-button";
|
| 502 |
+
detailButton.type = "button";
|
| 503 |
+
detailButton.textContent = "View";
|
| 504 |
+
detailButton.setAttribute("aria-label", "View details for " + entry.model_name);
|
| 505 |
+
detailButton.addEventListener("click", function () {
|
| 506 |
+
var next = row.nextElementSibling;
|
| 507 |
+
if (next && next.classList.contains("details-row")) {
|
| 508 |
+
next.remove();
|
| 509 |
+
} else {
|
| 510 |
+
row.after(detailRow(entry));
|
| 511 |
+
}
|
| 512 |
+
});
|
| 513 |
+
detailCell.appendChild(detailButton);
|
| 514 |
+
row.appendChild(detailCell);
|
| 515 |
+
body.appendChild(row);
|
| 516 |
+
});
|
| 517 |
+
var ranked = visible.filter(function (entry) { return rankById.has(entry.id); }).length;
|
| 518 |
+
var unranked = visible.length - ranked;
|
| 519 |
+
summary.textContent = visible.length + " records · " + ranked + " ranked · " + unranked + " unranked";
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
document.querySelectorAll(".sort-button[data-sort]").forEach(function (button) {
|
| 523 |
+
button.addEventListener("click", function () {
|
| 524 |
+
var nextKey = button.getAttribute("data-sort");
|
| 525 |
+
if (sortKey === nextKey) sortDirection *= -1;
|
| 526 |
+
else {
|
| 527 |
+
sortKey = nextKey;
|
| 528 |
+
sortDirection = nextKey === "overall" || nextKey === "rank" ? -1 : 1;
|
| 529 |
+
}
|
| 530 |
+
document.querySelectorAll(".sort-button[data-sort]").forEach(function (item) {
|
| 531 |
+
item.removeAttribute("aria-sort");
|
| 532 |
+
});
|
| 533 |
+
button.setAttribute("aria-sort", sortDirection === -1 ? "descending" : "ascending");
|
| 534 |
+
render();
|
| 535 |
+
});
|
| 536 |
+
});
|
| 537 |
+
[search, benchmarkFilter, providerFilter, sourceFilter].forEach(function (control) {
|
| 538 |
+
control.addEventListener("input", render);
|
| 539 |
+
control.addEventListener("change", render);
|
| 540 |
+
});
|
| 541 |
+
|
| 542 |
+
fetch("./data/results.json", { cache: "no-store" })
|
| 543 |
+
.then(function (response) {
|
| 544 |
+
if (!response.ok) throw new Error("Could not load leaderboard data (HTTP " + response.status + ")");
|
| 545 |
+
return response.json();
|
| 546 |
+
})
|
| 547 |
+
.then(function (data) {
|
| 548 |
+
if (!data || data.schema_version !== 1 || !Array.isArray(data.entries)) {
|
| 549 |
+
throw new Error("Leaderboard data does not match the expected schema.");
|
| 550 |
+
}
|
| 551 |
+
entries = data.entries;
|
| 552 |
+
populateFilters();
|
| 553 |
+
buildRanks();
|
| 554 |
+
render();
|
| 555 |
+
})
|
| 556 |
+
.catch(function (error) {
|
| 557 |
+
body.replaceChildren();
|
| 558 |
+
var row = document.createElement("tr");
|
| 559 |
+
var cell = document.createElement("td");
|
| 560 |
+
cell.className = "error";
|
| 561 |
+
cell.colSpan = 15;
|
| 562 |
+
cell.textContent = error.message;
|
| 563 |
+
row.appendChild(cell);
|
| 564 |
+
body.appendChild(row);
|
| 565 |
+
summary.textContent = "Results could not be loaded";
|
| 566 |
+
});
|
| 567 |
+
})();
|
| 568 |
+
</script>
|
| 569 |
+
</body>
|
| 570 |
</html>
|
templates/result-entry.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"id": "replace-with-a-unique-slug",
|
| 3 |
+
"model_name": "Display name",
|
| 4 |
+
"provider": "Provider or research group",
|
| 5 |
+
"model_id": "Exact model identifier or paper name",
|
| 6 |
+
"benchmark_version": "Benchmark release identifier",
|
| 7 |
+
"source": {
|
| 8 |
+
"type": "paper",
|
| 9 |
+
"url": "https://doi.org/..."
|
| 10 |
+
},
|
| 11 |
+
"evaluation_date": null,
|
| 12 |
+
"coverage": {
|
| 13 |
+
"status": "full",
|
| 14 |
+
"tasks_completed": 14,
|
| 15 |
+
"tasks_total": 14,
|
| 16 |
+
"samples_completed": null,
|
| 17 |
+
"samples_total": null
|
| 18 |
+
},
|
| 19 |
+
"scores": {
|
| 20 |
+
"overall": null,
|
| 21 |
+
"stages": {
|
| 22 |
+
"perception": null,
|
| 23 |
+
"understanding": null,
|
| 24 |
+
"reasoning": null,
|
| 25 |
+
"sensation": null
|
| 26 |
+
},
|
| 27 |
+
"taxonomy": {
|
| 28 |
+
"l1_task": null,
|
| 29 |
+
"l2_modality": null,
|
| 30 |
+
"l3_stage": null,
|
| 31 |
+
"l4_domain": null
|
| 32 |
+
},
|
| 33 |
+
"tasks": {}
|
| 34 |
+
},
|
| 35 |
+
"submitter": "HF username",
|
| 36 |
+
"notes": "Optional concise context. Scores use percentage points from 0 to 100."
|
| 37 |
+
}
|
validate_results.py
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Validate the public AVI-Bench leaderboard data file."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import argparse
|
| 7 |
+
import json
|
| 8 |
+
import math
|
| 9 |
+
import re
|
| 10 |
+
import sys
|
| 11 |
+
from datetime import date
|
| 12 |
+
from pathlib import Path
|
| 13 |
+
from urllib.parse import urlparse
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
ROOT = Path(__file__).resolve().parent
|
| 17 |
+
DEFAULT_DATA = ROOT / "data" / "results.json"
|
| 18 |
+
SOURCE_TYPES = {"paper", "participant", "maintainer"}
|
| 19 |
+
TOP_LEVEL_FIELDS = {
|
| 20 |
+
"id",
|
| 21 |
+
"model_name",
|
| 22 |
+
"provider",
|
| 23 |
+
"model_id",
|
| 24 |
+
"benchmark_version",
|
| 25 |
+
"source",
|
| 26 |
+
"evaluation_date",
|
| 27 |
+
"coverage",
|
| 28 |
+
"scores",
|
| 29 |
+
"submitter",
|
| 30 |
+
"notes",
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class ValidationError(ValueError):
|
| 35 |
+
"""Raised when leaderboard data fails its public schema checks."""
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def require_text(record: dict, field: str, path: str) -> str:
|
| 39 |
+
value = record.get(field)
|
| 40 |
+
if not isinstance(value, str) or not value.strip():
|
| 41 |
+
raise ValidationError(f"{path}.{field} must be a non-empty string")
|
| 42 |
+
return value.strip()
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def validate_score_values(value, path: str) -> None:
|
| 46 |
+
if value is None:
|
| 47 |
+
return
|
| 48 |
+
if isinstance(value, dict):
|
| 49 |
+
for key, child in value.items():
|
| 50 |
+
if not isinstance(key, str) or not key.strip():
|
| 51 |
+
raise ValidationError(f"{path} contains an empty metric name")
|
| 52 |
+
validate_score_values(child, f"{path}.{key}")
|
| 53 |
+
return
|
| 54 |
+
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
| 55 |
+
raise ValidationError(f"{path} must be a number or null")
|
| 56 |
+
if not math.isfinite(value) or not 0 <= value <= 100:
|
| 57 |
+
raise ValidationError(f"{path} must be between 0 and 100")
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def validate_entry(entry, index: int) -> str:
|
| 61 |
+
path = f"entries[{index}]"
|
| 62 |
+
if not isinstance(entry, dict):
|
| 63 |
+
raise ValidationError(f"{path} must be an object")
|
| 64 |
+
|
| 65 |
+
unknown = set(entry) - TOP_LEVEL_FIELDS
|
| 66 |
+
if unknown:
|
| 67 |
+
names = ", ".join(sorted(unknown))
|
| 68 |
+
raise ValidationError(f"{path} has unsupported fields: {names}")
|
| 69 |
+
|
| 70 |
+
record_id = require_text(entry, "id", path)
|
| 71 |
+
if not re.fullmatch(r"[a-zA-Z0-9][a-zA-Z0-9._-]{1,99}", record_id):
|
| 72 |
+
raise ValidationError(f"{path}.id must be a 2–100 character slug")
|
| 73 |
+
|
| 74 |
+
for field in ("model_name", "provider", "model_id", "benchmark_version"):
|
| 75 |
+
require_text(entry, field, path)
|
| 76 |
+
|
| 77 |
+
source = entry.get("source")
|
| 78 |
+
if not isinstance(source, dict):
|
| 79 |
+
raise ValidationError(f"{path}.source must be an object")
|
| 80 |
+
if set(source) != {"type", "url"}:
|
| 81 |
+
raise ValidationError(f"{path}.source must contain only type and url")
|
| 82 |
+
source_type = source.get("type")
|
| 83 |
+
if not isinstance(source_type, str) or source_type not in SOURCE_TYPES:
|
| 84 |
+
choices = ", ".join(sorted(SOURCE_TYPES))
|
| 85 |
+
raise ValidationError(f"{path}.source.type must be one of: {choices}")
|
| 86 |
+
source_url = require_text(source, "url", f"{path}.source")
|
| 87 |
+
parsed_url = urlparse(source_url)
|
| 88 |
+
if parsed_url.scheme != "https" or not parsed_url.netloc:
|
| 89 |
+
raise ValidationError(f"{path}.source.url must be an https URL")
|
| 90 |
+
|
| 91 |
+
evaluation_date = entry.get("evaluation_date")
|
| 92 |
+
if evaluation_date is not None:
|
| 93 |
+
if not isinstance(evaluation_date, str) or not re.fullmatch(
|
| 94 |
+
r"\d{4}-\d{2}-\d{2}", evaluation_date
|
| 95 |
+
):
|
| 96 |
+
raise ValidationError(f"{path}.evaluation_date must be YYYY-MM-DD or null")
|
| 97 |
+
try:
|
| 98 |
+
date.fromisoformat(evaluation_date)
|
| 99 |
+
except ValueError as exc:
|
| 100 |
+
raise ValidationError(
|
| 101 |
+
f"{path}.evaluation_date must be YYYY-MM-DD or null"
|
| 102 |
+
) from exc
|
| 103 |
+
|
| 104 |
+
coverage = entry.get("coverage")
|
| 105 |
+
if not isinstance(coverage, dict):
|
| 106 |
+
raise ValidationError(f"{path}.coverage must be an object")
|
| 107 |
+
allowed_coverage = {
|
| 108 |
+
"status", "tasks_completed", "tasks_total", "samples_completed", "samples_total"
|
| 109 |
+
}
|
| 110 |
+
if set(coverage) - allowed_coverage:
|
| 111 |
+
raise ValidationError(f"{path}.coverage has unsupported fields")
|
| 112 |
+
status = coverage.get("status")
|
| 113 |
+
if not isinstance(status, str) or status not in {"full", "partial"}:
|
| 114 |
+
raise ValidationError(f"{path}.coverage.status must be full or partial")
|
| 115 |
+
for field in ("tasks_completed", "tasks_total"):
|
| 116 |
+
count = coverage.get(field)
|
| 117 |
+
if isinstance(count, bool) or not isinstance(count, int) or count < 0:
|
| 118 |
+
raise ValidationError(f"{path}.coverage.{field} must be a non-negative integer")
|
| 119 |
+
tasks_completed = coverage["tasks_completed"]
|
| 120 |
+
tasks_total = coverage["tasks_total"]
|
| 121 |
+
if tasks_total == 0 or tasks_completed > tasks_total:
|
| 122 |
+
raise ValidationError(f"{path}.coverage task counts are inconsistent")
|
| 123 |
+
if status == "full" and tasks_completed != tasks_total:
|
| 124 |
+
raise ValidationError(f"{path} is full but does not cover every task")
|
| 125 |
+
for field in ("samples_completed", "samples_total"):
|
| 126 |
+
count = coverage.get(field)
|
| 127 |
+
if count is not None and (
|
| 128 |
+
isinstance(count, bool) or not isinstance(count, int) or count < 0
|
| 129 |
+
):
|
| 130 |
+
raise ValidationError(
|
| 131 |
+
f"{path}.coverage.{field} must be a non-negative integer or null"
|
| 132 |
+
)
|
| 133 |
+
completed_samples = coverage.get("samples_completed")
|
| 134 |
+
total_samples = coverage.get("samples_total")
|
| 135 |
+
if (completed_samples is None) != (total_samples is None):
|
| 136 |
+
raise ValidationError(
|
| 137 |
+
f"{path}.coverage must report both sample counts or neither"
|
| 138 |
+
)
|
| 139 |
+
if completed_samples is not None and total_samples is not None:
|
| 140 |
+
if completed_samples > total_samples:
|
| 141 |
+
raise ValidationError(f"{path}.coverage sample counts are inconsistent")
|
| 142 |
+
if status == "full" and completed_samples != total_samples:
|
| 143 |
+
raise ValidationError(f"{path} is full but sample coverage is incomplete")
|
| 144 |
+
if status == "partial" and tasks_completed == tasks_total:
|
| 145 |
+
if completed_samples is None or completed_samples == total_samples:
|
| 146 |
+
raise ValidationError(f"{path} is partial but reports full coverage")
|
| 147 |
+
|
| 148 |
+
scores = entry.get("scores")
|
| 149 |
+
if not isinstance(scores, dict):
|
| 150 |
+
raise ValidationError(f"{path}.scores must be an object")
|
| 151 |
+
if set(scores) - {"overall", "stages", "taxonomy", "tasks"}:
|
| 152 |
+
raise ValidationError(f"{path}.scores has unsupported fields")
|
| 153 |
+
validate_score_values(scores, f"{path}.scores")
|
| 154 |
+
|
| 155 |
+
notes = entry.get("notes")
|
| 156 |
+
if notes is not None and (not isinstance(notes, str) or len(notes) > 1000):
|
| 157 |
+
raise ValidationError(f"{path}.notes must be text of at most 1000 characters")
|
| 158 |
+
submitter = entry.get("submitter")
|
| 159 |
+
if submitter is not None and not isinstance(submitter, str):
|
| 160 |
+
raise ValidationError(f"{path}.submitter must be text or null")
|
| 161 |
+
return record_id
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def validate_file(path: Path) -> int:
|
| 165 |
+
try:
|
| 166 |
+
data = json.loads(path.read_text(encoding="utf-8"))
|
| 167 |
+
except OSError as exc:
|
| 168 |
+
raise ValidationError(f"cannot read {path}: {exc}") from exc
|
| 169 |
+
except json.JSONDecodeError as exc:
|
| 170 |
+
raise ValidationError(f"invalid JSON at line {exc.lineno}, column {exc.colno}") from exc
|
| 171 |
+
|
| 172 |
+
if not isinstance(data, dict) or set(data) != {"schema_version", "entries"}:
|
| 173 |
+
raise ValidationError("root must contain exactly schema_version and entries")
|
| 174 |
+
if type(data["schema_version"]) is not int or data["schema_version"] != 1:
|
| 175 |
+
raise ValidationError("schema_version must be 1")
|
| 176 |
+
entries = data["entries"]
|
| 177 |
+
if not isinstance(entries, list):
|
| 178 |
+
raise ValidationError("entries must be an array")
|
| 179 |
+
|
| 180 |
+
seen = set()
|
| 181 |
+
for index, entry in enumerate(entries):
|
| 182 |
+
record_id = validate_entry(entry, index)
|
| 183 |
+
if record_id in seen:
|
| 184 |
+
raise ValidationError(f"duplicate entry id: {record_id}")
|
| 185 |
+
seen.add(record_id)
|
| 186 |
+
return len(entries)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
def main() -> int:
|
| 190 |
+
parser = argparse.ArgumentParser(description=__doc__)
|
| 191 |
+
parser.add_argument("path", nargs="?", type=Path, default=DEFAULT_DATA)
|
| 192 |
+
args = parser.parse_args()
|
| 193 |
+
|
| 194 |
+
try:
|
| 195 |
+
count = validate_file(args.path)
|
| 196 |
+
except ValidationError as exc:
|
| 197 |
+
print(f"Invalid leaderboard data: {exc}", file=sys.stderr)
|
| 198 |
+
return 1
|
| 199 |
+
print(f"Valid leaderboard data: {count} entr{'y' if count == 1 else 'ies'}")
|
| 200 |
+
return 0
|
| 201 |
+
|
| 202 |
+
|
| 203 |
+
if __name__ == "__main__":
|
| 204 |
+
raise SystemExit(main())
|