Spaces:
Running
Running
Samples: Better/Worse verdict chips + shared pair transcripts
Browse files
app.py
CHANGED
|
@@ -68,8 +68,8 @@ MODALITIES = [
|
|
| 68 |
HIDDEN_BOARDS: frozenset = frozenset()
|
| 69 |
|
| 70 |
# Curated audio samples (optional): a samples.json manifest next to the board
|
| 71 |
-
# JSONs, each record {modality, factor, label?, group?,
|
| 72 |
-
# transcript?, audio} where "audio" is a repo-relative path (e.g.
|
| 73 |
# "samples/foo.mp3") resolved against the dataset (or ./data locally). A
|
| 74 |
# record's modality routes it to that tab, which appends a samples section
|
| 75 |
# (per-factor category tabs) below the board table. "text" (generation prompt)
|
|
@@ -79,6 +79,11 @@ HIDDEN_BOARDS: frozenset = frozenset()
|
|
| 79 |
# render under one shared subheading instead of per-row labels; a group whose
|
| 80 |
# records carry a "scenario" renders a bold "Scenario:" blurb as its lead-in
|
| 81 |
# instead of the heading.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
# A record with "turns" is a conversation (STS samples) rendered as a card:
|
| 83 |
# header = model (or "label" for stimulus cards) + optional "score"
|
| 84 |
# ({value, max, label}) badge + "verdict"/"verdict_label" chip + "caption";
|
|
@@ -412,6 +417,7 @@ TABLE_CSS = """
|
|
| 412 |
--lb-row-line:#f1f2f4; --lb-row-alt:#fafafa; --lb-tip-bg:#1f2328; --lb-tip-ink:#f5f6f7;
|
| 413 |
--lb-tip-border:#1f2328; --lb-shadow:rgba(0,0,0,.18); --lb-ramp:@RAMP_LIGHT@;
|
| 414 |
--lb-dim-bg:#eef0f2; --lb-dim-ink:#9aa1ab;
|
|
|
|
| 415 |
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
| 416 |
color:var(--lb-ink); max-width:100%; margin:0; color-scheme:light;
|
| 417 |
background:var(--lb-surface); border:1px solid var(--lb-border); border-radius:12px; padding:16px 18px; }
|
|
@@ -420,6 +426,7 @@ TABLE_CSS = """
|
|
| 420 |
--lb-row-line:#26292e; --lb-row-alt:#202327; --lb-tip-bg:#262e3a; --lb-tip-ink:#e7eaef;
|
| 421 |
--lb-tip-border:#39424f; --lb-shadow:rgba(0,0,0,.55); --lb-ramp:@RAMP_DARK@;
|
| 422 |
--lb-dim-bg:#22262d; --lb-dim-ink:#79818d;
|
|
|
|
| 423 |
color-scheme:dark; }
|
| 424 |
.ttslb .tbl-wrap { overflow-x:auto; }
|
| 425 |
/* Natural table width + pinned widths keep the rank/provider/License columns the
|
|
@@ -551,6 +558,19 @@ TABLE_CSS = """
|
|
| 551 |
.ttslb .smp-gnote { margin:2px 0 8px; max-width:760px; text-align:left;
|
| 552 |
font-size:12px; line-height:1.5; color:var(--lb-ink-2); }
|
| 553 |
.ttslb .smp-gnote strong { color:var(--lb-ink); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 554 |
/* a Scenario blurb starting the next group gets breathing room after the
|
| 555 |
previous group's cards */
|
| 556 |
.ttslb .smp-convo + .smp-gnote { margin-top:20px; }
|
|
@@ -1065,7 +1085,11 @@ def render_samples_section(samples: list, factor_labels: dict,
|
|
| 1065 |
but not displayed; a "transcript" (the human reference for ASR golden
|
| 1066 |
samples) is rendered next to the player. Rows carrying a "group" cluster
|
| 1067 |
under one shared subheading (with a sample count) instead of repeating a
|
| 1068 |
-
per-row label — the manifest is expected to keep a group's rows adjacent.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1069 |
if not samples:
|
| 1070 |
return ""
|
| 1071 |
factors = []
|
|
@@ -1081,23 +1105,39 @@ def render_samples_section(samples: list, factor_labels: dict,
|
|
| 1081 |
f"{html.escape(f_label)} <span class='smp-n'>({len(rows)})</span></button>")
|
| 1082 |
rows_html = []
|
| 1083 |
cur_group = None
|
|
|
|
| 1084 |
for s in rows:
|
| 1085 |
group = (s.get("group") or "").strip()
|
| 1086 |
# each run of same-group records opens with a lead-in: a bold
|
| 1087 |
# "Scenario:" blurb when the record carries one (STS conversation
|
| 1088 |
-
# groups), else the group name
|
| 1089 |
-
# buckets,
|
| 1090 |
-
#
|
|
|
|
|
|
|
|
|
|
| 1091 |
if group and group != cur_group:
|
|
|
|
|
|
|
| 1092 |
if s.get("scenario"):
|
| 1093 |
rows_html.append(f"<div class='smp-gnote'><strong>Scenario:"
|
| 1094 |
f"</strong> {html.escape(s['scenario'])}</div>")
|
| 1095 |
elif group != f_label:
|
| 1096 |
# a bucket named exactly like its tab would just repeat the
|
| 1097 |
# tab label — skip the subheading, keep the grouped rows
|
| 1098 |
-
|
| 1099 |
-
|
| 1100 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1101 |
cur_group = group or None
|
| 1102 |
if s.get("turns"):
|
| 1103 |
rows_html.append(_convo_html(s))
|
|
@@ -1106,6 +1146,16 @@ def render_samples_section(samples: list, factor_labels: dict,
|
|
| 1106 |
player = (f"<audio controls preload='none' src='{src}'></audio>"
|
| 1107 |
if src else "<span class='smp-pending'>audio pending</span>")
|
| 1108 |
transcript = (s.get("transcript") or "").strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1109 |
if group:
|
| 1110 |
body = (f"{player}<div class='smp-text'>{html.escape(transcript)}</div>"
|
| 1111 |
if transcript else player)
|
|
|
|
| 68 |
HIDDEN_BOARDS: frozenset = frozenset()
|
| 69 |
|
| 70 |
# Curated audio samples (optional): a samples.json manifest next to the board
|
| 71 |
+
# JSONs, each record {modality, factor, label?, group?, verdict?, model?,
|
| 72 |
+
# text?, transcript?, audio} where "audio" is a repo-relative path (e.g.
|
| 73 |
# "samples/foo.mp3") resolved against the dataset (or ./data locally). A
|
| 74 |
# record's modality routes it to that tab, which appends a samples section
|
| 75 |
# (per-factor category tabs) below the board table. "text" (generation prompt)
|
|
|
|
| 79 |
# render under one shared subheading instead of per-row labels; a group whose
|
| 80 |
# records carry a "scenario" renders a bold "Scenario:" blurb as its lead-in
|
| 81 |
# instead of the heading.
|
| 82 |
+
# A flat record with "verdict" (better|worse) is one half of a curated TTS
|
| 83 |
+
# contrast pair: it renders as a colored chip + player row under its group
|
| 84 |
+
# (the eval's display name), whose shared prompt "transcript" prints once at
|
| 85 |
+
# the lead-in. "model"/"score"/"instructions"/"tag"/"eval" ride along in the
|
| 86 |
+
# manifest as provenance, deliberately never displayed.
|
| 87 |
# A record with "turns" is a conversation (STS samples) rendered as a card:
|
| 88 |
# header = model (or "label" for stimulus cards) + optional "score"
|
| 89 |
# ({value, max, label}) badge + "verdict"/"verdict_label" chip + "caption";
|
|
|
|
| 417 |
--lb-row-line:#f1f2f4; --lb-row-alt:#fafafa; --lb-tip-bg:#1f2328; --lb-tip-ink:#f5f6f7;
|
| 418 |
--lb-tip-border:#1f2328; --lb-shadow:rgba(0,0,0,.18); --lb-ramp:@RAMP_LIGHT@;
|
| 419 |
--lb-dim-bg:#eef0f2; --lb-dim-ink:#9aa1ab;
|
| 420 |
+
--lb-good-bg:#eaf3df; --lb-good-ink:#567d2e; --lb-bad-bg:#f9e9e6; --lb-bad-ink:#b04a3e;
|
| 421 |
font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
|
| 422 |
color:var(--lb-ink); max-width:100%; margin:0; color-scheme:light;
|
| 423 |
background:var(--lb-surface); border:1px solid var(--lb-border); border-radius:12px; padding:16px 18px; }
|
|
|
|
| 426 |
--lb-row-line:#26292e; --lb-row-alt:#202327; --lb-tip-bg:#262e3a; --lb-tip-ink:#e7eaef;
|
| 427 |
--lb-tip-border:#39424f; --lb-shadow:rgba(0,0,0,.55); --lb-ramp:@RAMP_DARK@;
|
| 428 |
--lb-dim-bg:#22262d; --lb-dim-ink:#79818d;
|
| 429 |
+
--lb-good-bg:#2c3f1e; --lb-good-ink:#a3c585; --lb-bad-bg:#48261f; --lb-bad-ink:#d98a80;
|
| 430 |
color-scheme:dark; }
|
| 431 |
.ttslb .tbl-wrap { overflow-x:auto; }
|
| 432 |
/* Natural table width + pinned widths keep the rank/provider/License columns the
|
|
|
|
| 558 |
.ttslb .smp-gnote { margin:2px 0 8px; max-width:760px; text-align:left;
|
| 559 |
font-size:12px; line-height:1.5; color:var(--lb-ink-2); }
|
| 560 |
.ttslb .smp-gnote strong { color:var(--lb-ink); }
|
| 561 |
+
/* Better/Worse contrast pairs (curated TTS samples): fixed-width verdict
|
| 562 |
+
chips keep the pair's two players aligned; inks match the STS verdict
|
| 563 |
+
dots below. The pair's shared prompt text (.smp-gtx) sits under its group
|
| 564 |
+
heading — .long (the multi-minute long-form evals) caps it into a scroll
|
| 565 |
+
box instead of a wall of prose. */
|
| 566 |
+
.ttslb .smp-chip { flex:none; width:60px; text-align:center; font-size:11px; font-weight:700;
|
| 567 |
+
letter-spacing:.2px; padding:3px 0; border-radius:999px; }
|
| 568 |
+
.ttslb .smp-chip.better { background:var(--lb-good-bg); color:var(--lb-good-ink); }
|
| 569 |
+
.ttslb .smp-chip.worse { background:var(--lb-bad-bg); color:var(--lb-bad-ink); }
|
| 570 |
+
.ttslb .smp-gtx { margin:2px 0 4px; padding-left:14px; max-width:760px; text-align:left;
|
| 571 |
+
font-size:12.5px; line-height:1.5; color:var(--lb-ink-2); }
|
| 572 |
+
.ttslb .smp-gtx.long { max-height:76px; overflow-y:auto; margin-left:14px; padding:8px 10px;
|
| 573 |
+
border:1px solid var(--lb-row-line); border-radius:8px; }
|
| 574 |
/* a Scenario blurb starting the next group gets breathing room after the
|
| 575 |
previous group's cards */
|
| 576 |
.ttslb .smp-convo + .smp-gnote { margin-top:20px; }
|
|
|
|
| 1085 |
but not displayed; a "transcript" (the human reference for ASR golden
|
| 1086 |
samples) is rendered next to the player. Rows carrying a "group" cluster
|
| 1087 |
under one shared subheading (with a sample count) instead of repeating a
|
| 1088 |
+
per-row label — the manifest is expected to keep a group's rows adjacent.
|
| 1089 |
+
Flat rows carrying a "verdict" (better|worse) are curated contrast pairs:
|
| 1090 |
+
each renders as a colored chip + player, and the pair's shared prompt
|
| 1091 |
+
transcript prints once under the group heading (whose count is dropped —
|
| 1092 |
+
"(2)" on every pair says nothing)."""
|
| 1093 |
if not samples:
|
| 1094 |
return ""
|
| 1095 |
factors = []
|
|
|
|
| 1105 |
f"{html.escape(f_label)} <span class='smp-n'>({len(rows)})</span></button>")
|
| 1106 |
rows_html = []
|
| 1107 |
cur_group = None
|
| 1108 |
+
shared_tx = False # the group lead-in already printed the pair's prompt
|
| 1109 |
for s in rows:
|
| 1110 |
group = (s.get("group") or "").strip()
|
| 1111 |
# each run of same-group records opens with a lead-in: a bold
|
| 1112 |
# "Scenario:" blurb when the record carries one (STS conversation
|
| 1113 |
+
# groups), else the group name subheading — with a row count for
|
| 1114 |
+
# ASR's tag buckets, but without one for Better/Worse pairs, where
|
| 1115 |
+
# "(2)" says nothing. A verdict pair is a same-text contrast, so
|
| 1116 |
+
# its shared "transcript" prints once here; the multi-minute
|
| 1117 |
+
# long-form evals' text gets a capped scroll box (.long) instead
|
| 1118 |
+
# of a wall of prose.
|
| 1119 |
if group and group != cur_group:
|
| 1120 |
+
grp_rows = [r for r in rows if (r.get("group") or "").strip() == group]
|
| 1121 |
+
pair = all(r.get("verdict") and not r.get("turns") for r in grp_rows)
|
| 1122 |
if s.get("scenario"):
|
| 1123 |
rows_html.append(f"<div class='smp-gnote'><strong>Scenario:"
|
| 1124 |
f"</strong> {html.escape(s['scenario'])}</div>")
|
| 1125 |
elif group != f_label:
|
| 1126 |
# a bucket named exactly like its tab would just repeat the
|
| 1127 |
# tab label — skip the subheading, keep the grouped rows
|
| 1128 |
+
count = ("" if pair else
|
| 1129 |
+
f" <span class='smp-n'>({len(grp_rows)})</span>")
|
| 1130 |
+
rows_html.append(f"<div class='smp-group'>{html.escape(group)}{count}</div>")
|
| 1131 |
+
shared_tx = False
|
| 1132 |
+
if pair:
|
| 1133 |
+
txs = {(r.get("transcript") or "").strip() for r in grp_rows}
|
| 1134 |
+
tx = txs.pop() if len(txs) == 1 else ""
|
| 1135 |
+
if tx:
|
| 1136 |
+
shared_tx = True
|
| 1137 |
+
rows_html.append(f"<div class='smp-gtx{' long' if len(tx) > 400 else ''}'>"
|
| 1138 |
+
f"{html.escape(tx)}</div>")
|
| 1139 |
+
elif not group:
|
| 1140 |
+
shared_tx = False
|
| 1141 |
cur_group = group or None
|
| 1142 |
if s.get("turns"):
|
| 1143 |
rows_html.append(_convo_html(s))
|
|
|
|
| 1146 |
player = (f"<audio controls preload='none' src='{src}'></audio>"
|
| 1147 |
if src else "<span class='smp-pending'>audio pending</span>")
|
| 1148 |
transcript = (s.get("transcript") or "").strip()
|
| 1149 |
+
if s.get("verdict"):
|
| 1150 |
+
# a contrast-pair half: Better/Worse chip + player; the
|
| 1151 |
+
# transcript rides in the row only when the lead-in didn't
|
| 1152 |
+
# already print it for the whole pair
|
| 1153 |
+
v = "better" if s["verdict"] == "better" else "worse"
|
| 1154 |
+
tx = "" if shared_tx else transcript
|
| 1155 |
+
body = (f"<span class='smp-chip {v}'>{v.capitalize()}</span>{player}"
|
| 1156 |
+
+ (f"<div class='smp-text'>{html.escape(tx)}</div>" if tx else ""))
|
| 1157 |
+
rows_html.append(f"<div class='smp-row grp{' txt' if tx else ''}'>{body}</div>")
|
| 1158 |
+
continue
|
| 1159 |
if group:
|
| 1160 |
body = (f"{player}<div class='smp-text'>{html.escape(transcript)}</div>"
|
| 1161 |
if transcript else player)
|