Spaces:
Running
Running
Make leaderboard score-first with statistical intervals
Browse files
README.md
CHANGED
|
@@ -20,9 +20,11 @@ executable culinary answer keys without a human or model judge.
|
|
| 20 |
[Dataset](https://huggingface.co/datasets/josefchen/flavourbench) ·
|
| 21 |
[Source and reproduction](https://github.com/josefchen/flavourbench)
|
| 22 |
|
| 23 |
-
The Space presents the complete 20-model, 32-task public release
|
| 24 |
-
|
| 25 |
-
|
|
|
|
|
|
|
| 26 |
|
| 27 |
## Local launch
|
| 28 |
|
|
|
|
| 20 |
[Dataset](https://huggingface.co/datasets/josefchen/flavourbench) ·
|
| 21 |
[Source and reproduction](https://github.com/josefchen/flavourbench)
|
| 22 |
|
| 23 |
+
The Space presents the complete 20-model, 32-task public release. Its primary table contains only
|
| 24 |
+
FlavourBench Score, correct count, Wilson 95% interval, and parsed-answer count. Equal scores share
|
| 25 |
+
a score rank. Epicure-assisted results remain available in the model and pair views as a secondary
|
| 26 |
+
execution diagnostic. The Space does not call models or Epicure at runtime; the checked-in release
|
| 27 |
+
JSON is the sole data source.
|
| 28 |
|
| 29 |
## Local launch
|
| 30 |
|
app.py
CHANGED
|
@@ -136,11 +136,24 @@ body, .gradio-container {
|
|
| 136 |
}
|
| 137 |
.fb-rail {
|
| 138 |
background: var(--fb-code);
|
| 139 |
-
height:
|
| 140 |
position: relative;
|
| 141 |
}
|
| 142 |
-
.fb-rail-base {
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
.fb-rail-score {
|
| 145 |
color: var(--fb-muted);
|
| 146 |
font-family: "IBM Plex Mono", ui-monospace, monospace;
|
|
@@ -249,24 +262,47 @@ OBSERVATION_INDEX = {
|
|
| 249 |
}
|
| 250 |
|
| 251 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 252 |
def _short_name(display_name: str) -> str:
|
| 253 |
return display_name.split(": ", 1)[-1].replace(" Pro", "")
|
| 254 |
|
| 255 |
|
| 256 |
def _frontier_html() -> str:
|
| 257 |
rows = []
|
| 258 |
-
for model in
|
| 259 |
-
|
| 260 |
-
|
|
|
|
| 261 |
rows.append(
|
| 262 |
"<div class='fb-rail-row'>"
|
| 263 |
f"<div class='fb-rail-label' title='{html.escape(model['display_name'])}'>"
|
| 264 |
f"{html.escape(_short_name(model['display_name']))}</div>"
|
| 265 |
"<div class='fb-rail'>"
|
| 266 |
-
f"<span class='fb-rail-
|
| 267 |
-
f"<span class='fb-rail-
|
| 268 |
"</div>"
|
| 269 |
-
f"<div class='fb-rail-score'>{
|
| 270 |
"</div>"
|
| 271 |
)
|
| 272 |
return "".join(rows)
|
|
@@ -281,20 +317,20 @@ def _hero_html() -> str:
|
|
| 281 |
<h1>Culinary reasoning without a model judge.</h1>
|
| 282 |
<p class="fb-dek">FlavourBench scores 20 current language-model endpoints against answer
|
| 283 |
keys compiled by Epicure.
|
| 284 |
-
<strong>Blue
|
| 285 |
Open any pair to inspect the prompt, answers, tool trace, and hashes.</p>
|
| 286 |
<div class="fb-stats">
|
| 287 |
<div class="fb-stat"><strong>{counts["models"]}</strong><span>models</span></div>
|
| 288 |
<div class="fb-stat"><strong>{counts["tasks"]}</strong><span>tasks</span></div>
|
| 289 |
-
<div class="fb-stat"><strong>{counts["
|
| 290 |
-
<div class="fb-stat"><strong>{counts["
|
| 291 |
</div>
|
| 292 |
</section>
|
| 293 |
-
<section class="fb-frontier" aria-label="FlavourBench Score
|
| 294 |
-
<div class="fb-frontier-head"><strong>FlavourBench Score
|
| 295 |
{_frontier_html()}
|
| 296 |
-
<div class="fb-note">One
|
| 297 |
-
|
| 298 |
</section>
|
| 299 |
</div>
|
| 300 |
"""
|
|
@@ -302,19 +338,21 @@ def _hero_html() -> str:
|
|
| 302 |
|
| 303 |
def _leaderboard_frame() -> pd.DataFrame:
|
| 304 |
rows = []
|
| 305 |
-
for model in
|
| 306 |
off = model["conditions"]["epicure_off"]
|
| 307 |
-
|
| 308 |
-
observed = int(off["normal_completions"]) + int(on["normal_completions"])
|
| 309 |
rows.append(
|
| 310 |
{
|
| 311 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
"Model": model["display_name"],
|
| 313 |
-
"
|
| 314 |
-
"
|
| 315 |
-
"
|
| 316 |
-
"
|
| 317 |
-
"Backend": model["execution_backend"],
|
| 318 |
}
|
| 319 |
)
|
| 320 |
return pd.DataFrame(rows)
|
|
@@ -332,9 +370,9 @@ def _model_detail(model_name: str) -> tuple[str, pd.DataFrame]:
|
|
| 332 |
<span>Wilson 95%: {off["wilson_95"][0] * 100:.1f}% to {off["wilson_95"][1] * 100:.1f}%</span>
|
| 333 |
</div>
|
| 334 |
<div class="fb-condition good">
|
| 335 |
-
<small>
|
| 336 |
<strong>{on["accuracy_percent"]:.3g}%</strong>
|
| 337 |
-
<span>
|
| 338 |
</div>
|
| 339 |
</div>
|
| 340 |
"""
|
|
@@ -482,7 +520,7 @@ with gr.Blocks(title="FlavourBench · Frontier culinary reasoning benchmark") as
|
|
| 482 |
<div class="fb-section-title">
|
| 483 |
<div class="fb-kicker">Automated exact-choice track</div>
|
| 484 |
<h2>The complete public benchmark</h2>
|
| 485 |
-
<p>
|
| 486 |
</div>
|
| 487 |
"""
|
| 488 |
)
|
|
@@ -492,12 +530,15 @@ with gr.Blocks(title="FlavourBench · Frontier culinary reasoning benchmark") as
|
|
| 492 |
wrap=True,
|
| 493 |
show_search="filter",
|
| 494 |
show_row_numbers=False,
|
| 495 |
-
column_widths=[55,
|
| 496 |
)
|
| 497 |
gr.Markdown(
|
| 498 |
-
"**Reading the table.**
|
| 499 |
-
"
|
| 500 |
-
"
|
|
|
|
|
|
|
|
|
|
| 501 |
)
|
| 502 |
|
| 503 |
with gr.Tab("Model fingerprint"):
|
|
@@ -600,10 +641,11 @@ with gr.Blocks(title="FlavourBench · Frontier culinary reasoning benchmark") as
|
|
| 600 |
<div class="fb-method-grid">
|
| 601 |
<div>
|
| 602 |
<h3>Scoring contract</h3>
|
| 603 |
-
<p><strong>FlavourBench Score</strong> is
|
| 604 |
-
all 32 tasks
|
| 605 |
-
|
| 606 |
-
|
|
|
|
| 607 |
<p>Tasks cover substitution, composition, cookability, and evidence. Every expected
|
| 608 |
answer is derived from a fixed read-only Epicure operation.</p>
|
| 609 |
<h3>Public records</h3>
|
|
|
|
| 136 |
}
|
| 137 |
.fb-rail {
|
| 138 |
background: var(--fb-code);
|
| 139 |
+
height: 12px;
|
| 140 |
position: relative;
|
| 141 |
}
|
| 142 |
+
.fb-rail-base {
|
| 143 |
+
background: var(--fb-blue);
|
| 144 |
+
bottom: 0;
|
| 145 |
+
height: 7px;
|
| 146 |
+
left: 0;
|
| 147 |
+
position: absolute;
|
| 148 |
+
}
|
| 149 |
+
.fb-rail-ci {
|
| 150 |
+
border-left: 1px solid var(--fb-muted);
|
| 151 |
+
border-right: 1px solid var(--fb-muted);
|
| 152 |
+
border-top: 2px solid var(--fb-muted);
|
| 153 |
+
height: 4px;
|
| 154 |
+
position: absolute;
|
| 155 |
+
top: 0;
|
| 156 |
+
}
|
| 157 |
.fb-rail-score {
|
| 158 |
color: var(--fb-muted);
|
| 159 |
font-family: "IBM Plex Mono", ui-monospace, monospace;
|
|
|
|
| 262 |
}
|
| 263 |
|
| 264 |
|
| 265 |
+
def _score_display_models() -> list[dict[str, Any]]:
|
| 266 |
+
return sorted(
|
| 267 |
+
MODELS,
|
| 268 |
+
key=lambda model: (
|
| 269 |
+
-float(model["conditions"]["epicure_off"]["accuracy_percent"]),
|
| 270 |
+
str(model["display_name"]).casefold(),
|
| 271 |
+
),
|
| 272 |
+
)
|
| 273 |
+
|
| 274 |
+
|
| 275 |
+
DISPLAY_MODELS = _score_display_models()
|
| 276 |
+
SCORE_RANKS: dict[str, int] = {}
|
| 277 |
+
_previous_score: float | None = None
|
| 278 |
+
_current_rank = 0
|
| 279 |
+
for _position, _model in enumerate(DISPLAY_MODELS, start=1):
|
| 280 |
+
_score = float(_model["conditions"]["epicure_off"]["accuracy_percent"])
|
| 281 |
+
if _previous_score is None or _score != _previous_score:
|
| 282 |
+
_current_rank = _position
|
| 283 |
+
_previous_score = _score
|
| 284 |
+
SCORE_RANKS[str(_model["model_id"])] = _current_rank
|
| 285 |
+
|
| 286 |
+
|
| 287 |
def _short_name(display_name: str) -> str:
|
| 288 |
return display_name.split(": ", 1)[-1].replace(" Pro", "")
|
| 289 |
|
| 290 |
|
| 291 |
def _frontier_html() -> str:
|
| 292 |
rows = []
|
| 293 |
+
for model in DISPLAY_MODELS[:12]:
|
| 294 |
+
condition = model["conditions"]["epicure_off"]
|
| 295 |
+
score = float(condition["accuracy_percent"])
|
| 296 |
+
lower, upper = (100 * float(value) for value in condition["wilson_95"])
|
| 297 |
rows.append(
|
| 298 |
"<div class='fb-rail-row'>"
|
| 299 |
f"<div class='fb-rail-label' title='{html.escape(model['display_name'])}'>"
|
| 300 |
f"{html.escape(_short_name(model['display_name']))}</div>"
|
| 301 |
"<div class='fb-rail'>"
|
| 302 |
+
f"<span class='fb-rail-ci' style='left:{lower:.3f}%;width:{upper - lower:.3f}%'></span>"
|
| 303 |
+
f"<span class='fb-rail-base' style='width:{score:.3f}%'></span>"
|
| 304 |
"</div>"
|
| 305 |
+
f"<div class='fb-rail-score'>{score:.0f}</div>"
|
| 306 |
"</div>"
|
| 307 |
)
|
| 308 |
return "".join(rows)
|
|
|
|
| 317 |
<h1>Culinary reasoning without a model judge.</h1>
|
| 318 |
<p class="fb-dek">FlavourBench scores 20 current language-model endpoints against answer
|
| 319 |
keys compiled by Epicure.
|
| 320 |
+
<strong>Blue is the FlavourBench Score. Gray shows its Wilson 95% interval.</strong>
|
| 321 |
Open any pair to inspect the prompt, answers, tool trace, and hashes.</p>
|
| 322 |
<div class="fb-stats">
|
| 323 |
<div class="fb-stat"><strong>{counts["models"]}</strong><span>models</span></div>
|
| 324 |
<div class="fb-stat"><strong>{counts["tasks"]}</strong><span>tasks</span></div>
|
| 325 |
+
<div class="fb-stat"><strong>{counts["models"] * counts["tasks"]}</strong><span>score cells</span></div>
|
| 326 |
+
<div class="fb-stat"><strong>{counts["families"]}</strong><span>task families</span></div>
|
| 327 |
</div>
|
| 328 |
</section>
|
| 329 |
+
<section class="fb-frontier" aria-label="FlavourBench Score with Wilson intervals">
|
| 330 |
+
<div class="fb-frontier-head"><strong>FlavourBench Score</strong><span>Top 12 · score and Wilson 95%</span></div>
|
| 331 |
{_frontier_html()}
|
| 332 |
+
<div class="fb-note">One answer equals 3.125 points. The score is exact for these 32 tasks;
|
| 333 |
+
overlapping intervals mean nearby rows are not a definitive general ordering.</div>
|
| 334 |
</section>
|
| 335 |
</div>
|
| 336 |
"""
|
|
|
|
| 338 |
|
| 339 |
def _leaderboard_frame() -> pd.DataFrame:
|
| 340 |
rows = []
|
| 341 |
+
for model in DISPLAY_MODELS:
|
| 342 |
off = model["conditions"]["epicure_off"]
|
| 343 |
+
lower, upper = (100 * float(value) for value in off["wilson_95"])
|
|
|
|
| 344 |
rows.append(
|
| 345 |
{
|
| 346 |
+
"Score rank": (
|
| 347 |
+
SCORE_RANKS[str(model["model_id"])]
|
| 348 |
+
if int(off["parseable_answers"]) > 0
|
| 349 |
+
else "DNF"
|
| 350 |
+
),
|
| 351 |
"Model": model["display_name"],
|
| 352 |
+
"FlavourBench Score": f"{off['accuracy_percent']:.3g}%",
|
| 353 |
+
"Correct": f"{off['correct']}/32",
|
| 354 |
+
"Wilson 95%": f"{lower:.1f}% to {upper:.1f}%",
|
| 355 |
+
"Parsed answers": f"{off['parseable_answers']}/32",
|
|
|
|
| 356 |
}
|
| 357 |
)
|
| 358 |
return pd.DataFrame(rows)
|
|
|
|
| 370 |
<span>Wilson 95%: {off["wilson_95"][0] * 100:.1f}% to {off["wilson_95"][1] * 100:.1f}%</span>
|
| 371 |
</div>
|
| 372 |
<div class="fb-condition good">
|
| 373 |
+
<small>Named-operation diagnostic</small>
|
| 374 |
<strong>{on["accuracy_percent"]:.3g}%</strong>
|
| 375 |
+
<span>Expected ceiling; never a ranking input</span>
|
| 376 |
</div>
|
| 377 |
</div>
|
| 378 |
"""
|
|
|
|
| 520 |
<div class="fb-section-title">
|
| 521 |
<div class="fb-kicker">Automated exact-choice track</div>
|
| 522 |
<h2>The complete public benchmark</h2>
|
| 523 |
+
<p>Score rank follows only the FlavourBench Score on the fixed 32-task panel.</p>
|
| 524 |
</div>
|
| 525 |
"""
|
| 526 |
)
|
|
|
|
| 530 |
wrap=True,
|
| 531 |
show_search="filter",
|
| 532 |
show_row_numbers=False,
|
| 533 |
+
column_widths=[55, 280, 130, 85, 175, 155],
|
| 534 |
)
|
| 535 |
gr.Markdown(
|
| 536 |
+
"**Reading the table.** The score is exact for this fixed panel. The Wilson interval "
|
| 537 |
+
"is a descriptive sampling indicator, not proof about all culinary reasoning. "
|
| 538 |
+
"Equal scores share a score rank, and leading intervals overlap, so nearby rows "
|
| 539 |
+
"should be treated as a close score group. "
|
| 540 |
+
"Parsed answers keeps answer-contract failures visible. Epicure-assisted results "
|
| 541 |
+
"remain available in Model fingerprint and Pair Lens, but they do not affect rank."
|
| 542 |
)
|
| 543 |
|
| 544 |
with gr.Tab("Model fingerprint"):
|
|
|
|
| 641 |
<div class="fb-method-grid">
|
| 642 |
<div>
|
| 643 |
<h3>Scoring contract</h3>
|
| 644 |
+
<p><strong>FlavourBench Score</strong> is model-only exact-choice accuracy over
|
| 645 |
+
all 32 tasks and is the only ranking metric. Epicure compiles the reference
|
| 646 |
+
answers; it is not a model row. The matched named-operation condition makes the
|
| 647 |
+
same runtime output available to the endpoint, so its near-100% result is an
|
| 648 |
+
expected execution ceiling, not a second benchmark score.</p>
|
| 649 |
<p>Tasks cover substitution, composition, cookability, and evidence. Every expected
|
| 650 |
answer is derived from a fixed read-only Epicure operation.</p>
|
| 651 |
<h3>Public records</h3>
|