webchick commited on
Commit
d5af82e
·
verified ·
1 Parent(s): 841e1eb

Fix column headers and stale cache via demo.load()

Browse files
Files changed (1) hide show
  1. app.py +121 -82
app.py CHANGED
@@ -4,6 +4,8 @@ Reads EvalEval instance-level records from a HuggingFace dataset and
4
  renders a sortable comparison table across models and skills.
5
  """
6
  import json
 
 
7
  from pathlib import Path
8
 
9
  import gradio as gr
@@ -14,53 +16,55 @@ DATASET_REPO = "webchick/eval-results-poc"
14
 
15
 
16
  def load_results() -> pd.DataFrame:
17
- """Download the dataset and flatten instance records into a DataFrame."""
18
- local_dir = snapshot_download(repo_id=DATASET_REPO, repo_type="dataset")
19
- rows = []
20
-
21
- # Instance-level data lives in *_samples.jsonl files, one JSON object per line.
22
- # The aggregate *.json files have a different schema and are intentionally skipped.
23
- for jsonl_file in sorted(Path(local_dir).rglob("*_samples.jsonl")):
24
- with open(jsonl_file) as f:
25
- for line in f:
26
- line = line.strip()
27
- if not line:
28
- continue
29
- try:
30
- rec = json.loads(line)
31
- except json.JSONDecodeError:
32
- continue
33
- if not rec.get("schema_version", "").startswith("instance_level_eval"):
34
- continue
35
-
36
- meta = rec.get("metadata") or {}
37
- perf = rec.get("performance") or {}
38
- usage = rec.get("token_usage") or {}
39
- ev = rec.get("evaluation") or {}
40
-
41
- raw_prompt = (rec.get("input") or {}).get("raw", "")
42
- task = (raw_prompt[:97] + "…") if len(raw_prompt) > 100 else raw_prompt
43
-
44
- rows.append({
45
- "Namespace": meta.get("eval_namespace", "?"),
46
- "Skill": meta.get("skill_name", "?"),
47
- "Case": meta.get("case_id", "?"),
48
- "Task": task,
49
- "Model": rec.get("model_id", "?"),
50
- "Passed": "✅" if ev.get("is_correct") else "❌",
51
- "Latency (ms)": round(perf.get("latency_ms") or 0, 0),
52
- "Input tokens": usage.get("input_tokens", 0),
53
- "Output tokens": usage.get("output_tokens", 0),
54
- "Cost (USD)": round(float(meta.get("cost_usd") or 0), 6),
55
- "Run timestamp": meta.get("timestamp_run", ""),
56
- })
57
-
58
- return pd.DataFrame(rows)
 
 
 
 
59
 
60
 
61
  def build_ui():
62
- df = load_results()
63
-
64
  with gr.Blocks(title="Drupal AI Eval Dashboard (POC)") as demo:
65
  gr.Markdown(
66
  "# Drupal AI Eval Dashboard (POC)\n\n"
@@ -71,48 +75,83 @@ def build_ui():
71
  "(https://github.com/evaleval/every_eval_ever)."
72
  )
73
 
74
- if df.empty:
75
- gr.Markdown("_No results found in the dataset yet._")
76
- else:
77
- namespaces = sorted(df["Namespace"].unique().tolist())
78
- namespace_filter = gr.Dropdown(
79
- choices=["(all)"] + namespaces,
80
- value="(all)",
81
- label="Filter by namespace",
 
 
 
 
 
 
 
 
 
 
 
82
  )
83
- summary = gr.Markdown()
84
- results_table = gr.Dataframe(interactive=False, wrap=True)
85
- pass_rate_table = gr.Dataframe(interactive=False)
86
-
87
- def update(ns):
88
- filtered = df if ns == "(all)" else df[df["Namespace"] == ns]
89
- summary_text = (
90
- f"**{len(filtered)} result(s)** across "
91
- f"{filtered['Model'].nunique()} model(s) and "
92
- f"{filtered['Case'].nunique()} case(s)."
93
- )
94
- filtered["_passed_int"] = (filtered["Passed"] == "✅").astype(int)
95
- agg = (
96
- filtered.groupby("Model")["_passed_int"]
97
- .agg(["mean", "count"])
98
- .reset_index()
99
- .rename(columns={"mean": "Pass rate", "count": "Cases run"})
 
 
 
 
 
 
100
  )
101
- agg["Pass rate"] = agg["Pass rate"].round(2)
102
- return summary_text, filtered.drop(columns=["_passed_int"], errors="ignore"), agg
103
-
104
- namespace_filter.change(
105
- fn=update,
106
- inputs=namespace_filter,
107
- outputs=[summary, results_table, pass_rate_table],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  )
109
- # populate on load
110
- init_summary, init_table, init_agg = update("(all)")
111
- summary.value = init_summary
112
- results_table.value = init_table
113
 
114
- gr.Markdown("## Pass rate by model")
115
- pass_rate_table.value = init_agg
 
 
 
 
 
 
 
 
116
 
117
  return demo
118
 
 
4
  renders a sortable comparison table across models and skills.
5
  """
6
  import json
7
+ import shutil
8
+ import tempfile
9
  from pathlib import Path
10
 
11
  import gradio as gr
 
16
 
17
 
18
  def load_results() -> pd.DataFrame:
19
+ """Download the dataset fresh and flatten instance records into a DataFrame."""
20
+ tmp = tempfile.mkdtemp()
21
+ try:
22
+ local_dir = snapshot_download(
23
+ repo_id=DATASET_REPO,
24
+ repo_type="dataset",
25
+ local_dir=tmp,
26
+ )
27
+ rows = []
28
+ for jsonl_file in sorted(Path(local_dir).rglob("*_samples.jsonl")):
29
+ with open(jsonl_file) as f:
30
+ for line in f:
31
+ line = line.strip()
32
+ if not line:
33
+ continue
34
+ try:
35
+ rec = json.loads(line)
36
+ except json.JSONDecodeError:
37
+ continue
38
+ if not rec.get("schema_version", "").startswith("instance_level_eval"):
39
+ continue
40
+
41
+ meta = rec.get("metadata") or {}
42
+ perf = rec.get("performance") or {}
43
+ usage = rec.get("token_usage") or {}
44
+ ev = rec.get("evaluation") or {}
45
+
46
+ raw_prompt = (rec.get("input") or {}).get("raw", "")
47
+ task = (raw_prompt[:97] + "…") if len(raw_prompt) > 100 else raw_prompt
48
+
49
+ rows.append({
50
+ "Namespace": meta.get("eval_namespace", "?"),
51
+ "Skill": meta.get("skill_name", "?"),
52
+ "Case": meta.get("case_id", "?"),
53
+ "Task": task,
54
+ "Model": rec.get("model_id", "?"),
55
+ "Passed": "✅" if ev.get("is_correct") else "❌",
56
+ "Latency (ms)": round(perf.get("latency_ms") or 0, 0),
57
+ "Input tokens": usage.get("input_tokens", 0),
58
+ "Output tokens": usage.get("output_tokens", 0),
59
+ "Cost (USD)": round(float(meta.get("cost_usd") or 0), 6),
60
+ "Run timestamp": meta.get("timestamp_run", ""),
61
+ })
62
+ return pd.DataFrame(rows)
63
+ finally:
64
+ shutil.rmtree(tmp, ignore_errors=True)
65
 
66
 
67
  def build_ui():
 
 
68
  with gr.Blocks(title="Drupal AI Eval Dashboard (POC)") as demo:
69
  gr.Markdown(
70
  "# Drupal AI Eval Dashboard (POC)\n\n"
 
75
  "(https://github.com/evaleval/every_eval_ever)."
76
  )
77
 
78
+ namespace_filter = gr.Dropdown(
79
+ choices=["(all)"],
80
+ value="(all)",
81
+ label="Filter by namespace",
82
+ )
83
+ summary = gr.Markdown("_Loading results…_")
84
+ results_table = gr.Dataframe(interactive=False, wrap=True)
85
+ gr.Markdown("## Pass rate by model")
86
+ pass_rate_table = gr.Dataframe(interactive=False)
87
+
88
+ def filter_data(ns, df_json):
89
+ df = pd.read_json(df_json, orient="split")
90
+ filtered = df if ns == "(all)" else df[df["Namespace"] == ns]
91
+ if filtered.empty:
92
+ return "_No results found._", pd.DataFrame(), pd.DataFrame()
93
+ summary_text = (
94
+ f"**{len(filtered)} result(s)** across "
95
+ f"{filtered['Model'].nunique()} model(s) and "
96
+ f"{filtered['Case'].nunique()} case(s)."
97
  )
98
+ filtered = filtered.copy()
99
+ filtered["_passed_int"] = (filtered["Passed"] == "✅").astype(int)
100
+ agg = (
101
+ filtered.groupby("Model")["_passed_int"]
102
+ .agg(["mean", "count"])
103
+ .reset_index()
104
+ .rename(columns={"mean": "Pass rate", "count": "Cases run"})
105
+ )
106
+ agg["Pass rate"] = agg["Pass rate"].round(2)
107
+ return summary_text, filtered.drop(columns=["_passed_int"]), agg
108
+
109
+ # Hidden state holds the full DataFrame so filter_data is pure
110
+ data_store = gr.State()
111
+
112
+ def on_load():
113
+ df = load_results()
114
+ if df.empty:
115
+ return (
116
+ gr.Dropdown(choices=["(all)"], value="(all)"),
117
+ df.to_json(orient="split"),
118
+ "_No results found in the dataset yet._",
119
+ pd.DataFrame(),
120
+ pd.DataFrame(),
121
  )
122
+ namespaces = sorted(df["Namespace"].unique().tolist())
123
+ summary_text = (
124
+ f"**{len(df)} result(s)** across "
125
+ f"{df['Model'].nunique()} model(s) and "
126
+ f"{df['Case'].nunique()} case(s)."
127
+ )
128
+ df_copy = df.copy()
129
+ df_copy["_passed_int"] = (df_copy["Passed"] == "✅").astype(int)
130
+ agg = (
131
+ df_copy.groupby("Model")["_passed_int"]
132
+ .agg(["mean", "count"])
133
+ .reset_index()
134
+ .rename(columns={"mean": "Pass rate", "count": "Cases run"})
135
+ )
136
+ agg["Pass rate"] = agg["Pass rate"].round(2)
137
+ return (
138
+ gr.Dropdown(choices=["(all)"] + namespaces, value="(all)"),
139
+ df.to_json(orient="split"),
140
+ summary_text,
141
+ df,
142
+ agg,
143
  )
 
 
 
 
144
 
145
+ demo.load(
146
+ fn=on_load,
147
+ outputs=[namespace_filter, data_store, summary, results_table, pass_rate_table],
148
+ )
149
+
150
+ namespace_filter.change(
151
+ fn=filter_data,
152
+ inputs=[namespace_filter, data_store],
153
+ outputs=[summary, results_table, pass_rate_table],
154
+ )
155
 
156
  return demo
157