josefchen commited on
Commit
a5a9440
·
verified ·
1 Parent(s): b2aac0d

Make leaderboard score-first with statistical intervals

Browse files
Files changed (2) hide show
  1. README.md +5 -3
  2. app.py +78 -36
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 and makes every paired result
24
- inspectable. It does not call models or Epicure at runtime. The checked-in release JSON is the sole
25
- data source.
 
 
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: 8px;
140
  position: relative;
141
  }
142
- .fb-rail-base { background: var(--fb-blue); height: 8px; left: 0; position: absolute; }
143
- .fb-rail-uplift { background: var(--fb-gold); height: 8px; position: absolute; }
 
 
 
 
 
 
 
 
 
 
 
 
 
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 MODELS[:12]:
259
- off = float(model["conditions"]["epicure_off"]["accuracy_percent"])
260
- on = float(model["conditions"]["epicure_on"]["accuracy_percent"])
 
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-base' style='width:{off:.3f}%'></span>"
267
- f"<span class='fb-rail-uplift' style='left:{off:.3f}%;width:{max(on - off, 0):.3f}%'></span>"
268
  "</div>"
269
- f"<div class='fb-rail-score'>{off:.0f}</div>"
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 measures Model only. Gold measures the gain from Epicure.</strong>
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["assigned_pairs"]}</strong><span>matched pairs</span></div>
290
- <div class="fb-stat"><strong>{counts["observed_response_arms"]:,}</strong><span>observed arms</span></div>
291
  </div>
292
  </section>
293
- <section class="fb-frontier" aria-label="FlavourBench Score and Epicure Gain">
294
- <div class="fb-frontier-head"><strong>FlavourBench Score plus Epicure Gain</strong><span>Top 12 · percent correct</span></div>
295
  {_frontier_html()}
296
- <div class="fb-note">One task equals 3.125 percentage points. Read adjacent rows as a
297
- close score group, then inspect the underlying pairs.</div>
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 MODELS:
306
  off = model["conditions"]["epicure_off"]
307
- on = model["conditions"]["epicure_on"]
308
- observed = int(off["normal_completions"]) + int(on["normal_completions"])
309
  rows.append(
310
  {
311
- "Rank": model["rank"],
 
 
 
 
312
  "Model": model["display_name"],
313
- "Model only": f"{off['accuracy_percent']:.3g}%",
314
- "Model + Epicure": f"{on['accuracy_percent']:.3g}%",
315
- "Epicure Gain": f"+{model['uplift_percentage_points']:.3g} pp",
316
- "Observed arms": f"{observed}/64",
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>Model + Epicure accuracy</small>
336
  <strong>{on["accuracy_percent"]:.3g}%</strong>
337
- <span>Epicure Gain: +{model["uplift_percentage_points"]:.3g} percentage points</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>Rank follows FlavourBench Score. Model + Epicure and Epicure Gain show the matched intervention.</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, 260, 95, 95, 105, 110, 110],
496
  )
497
  gr.Markdown(
498
- "**Reading the table.** Rank follows Model only accuracy over this 32-task release; "
499
- "it is not a claim about general model quality. Equal scores follow the release's "
500
- "frozen tie-break rules. Use Pair Lens before interpreting small differences."
 
 
 
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 Model only exact-choice accuracy over
604
- all 32 tasks. <strong>Model + Epicure</strong> uses the same endpoint-task cells
605
- with one named Epicure operation. <strong>Epicure Gain</strong> is the matched
606
- percentage-point change and does not affect rank.</p>
 
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>