Clémentine commited on
Commit
67741f2
·
1 Parent(s): 570d85c

added evaluation + leaderboard generation + reorg of the viz

Browse files
yourbench_space/app.py CHANGED
@@ -1,10 +1,13 @@
 
1
  import os
2
  import sys
3
  import time
4
  import gradio as gr
5
- from pathlib import Path
6
- from loguru import logger
7
  from huggingface_hub import whoami
 
 
8
 
9
  from yourbench_space.config import generate_and_save_config
10
  from yourbench_space.utils import (
@@ -15,6 +18,8 @@ from yourbench_space.utils import (
15
  update_dataset,
16
  STAGES,
17
  )
 
 
18
 
19
  project_description = """
20
  # YourBench 🚀
@@ -74,11 +79,11 @@ def update_process_status():
74
 
75
  return gr.update(value=True, label="Process Status: Running")
76
 
77
- def prepare_task(oauth_token: gr.OAuthToken | None, hf_dataset_prefix: str, _=None):
78
  new_env = os.environ.copy()
79
  if oauth_token:
80
  new_env["HF_TOKEN"] = oauth_token.token
81
- new_env["DATASET_PREFIX"] = hf_dataset_prefix
82
  manager.start_process(custom_env=new_env)
83
 
84
 
@@ -104,31 +109,55 @@ def switch_to_run_generation_tab():
104
  def enable_button(files):
105
  return gr.update(interactive=bool(files))
106
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  with gr.Blocks(theme=gr.themes.Default()) as app:
109
  gr.Markdown(project_description)
110
 
111
- with gr.Row():
112
- gr.Markdown("## ⚙️ YourBench Setup", elem_id="setup-title")
113
- with gr.Column(scale=0, min_width=150):
114
- login_btn = gr.LoginButton()
115
-
116
  with gr.Tabs() as tabs:
117
  with gr.Tab("Setup", id=0):
118
  with gr.Row():
119
- with gr.Accordion("Hugging Face Settings"):
120
- hf_org_dropdown = gr.Dropdown(
121
- choices=[], label="Organization", allow_custom_value=True
122
- )
123
- app.load(
124
- update_hf_org_dropdown, inputs=None, outputs=hf_org_dropdown
125
- )
126
-
127
- hf_dataset_prefix = gr.Textbox(
128
- label="Dataset Prefix",
129
- value="yourbench",
130
- info="Prefix applied to all datasets",
131
- )
 
 
132
 
133
  with gr.Accordion("Upload documents"):
134
  file_input = gr.File(
@@ -142,18 +171,18 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
142
  file_input,
143
  output,
144
  )
145
-
146
- preview_button = gr.Button("Generate New Config", interactive=False)
147
- log_message = gr.Textbox(label="Log Message", visible=True)
148
- download_button = gr.File(
149
- label="Download Config", visible=False, interactive=False
150
- )
151
 
152
  file_input.change(enable_button, inputs=file_input, outputs=preview_button)
153
 
154
  preview_button.click(
155
  generate_and_return,
156
- inputs=[hf_org_dropdown, hf_dataset_prefix],
157
  outputs=[log_message, download_button],
158
  )
159
  preview_button.click(
@@ -164,9 +193,26 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
164
 
165
  with gr.Tab("Run Generation", id=1):
166
  with gr.Row():
167
- with gr.Accordion("Log Output", open=True):
168
- log_output = gr.Code(language=None, lines=20, interactive=False)
 
 
 
 
 
 
169
 
 
 
 
 
 
 
 
 
 
 
 
170
  with gr.Accordion("Stages", open=True):
171
  stages_table = gr.CheckboxGroup(
172
  choices=STAGES,
@@ -175,27 +221,6 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
175
  interactive=False,
176
  )
177
 
178
- log_timer = gr.Timer(1.0, active=True)
179
- log_timer.tick(
180
- manager.read_and_get_output, outputs=[log_output, stages_table]
181
- )
182
-
183
- with gr.Row():
184
- process_status = gr.Checkbox(label="Process Status", interactive=False)
185
- status_timer = gr.Timer(1.0, active=True)
186
- status_timer.tick(update_process_status, outputs=process_status)
187
-
188
- with gr.Row():
189
- start_button = gr.Button("Start Task")
190
- start_button.click(prepare_task, inputs=[login_btn, hf_dataset_prefix])
191
-
192
- stop_button = gr.Button("Stop Task")
193
- stop_button.click(manager.stop_process)
194
-
195
- kill_button = gr.Button("Kill Task")
196
- kill_button.click(manager.kill_process)
197
-
198
- with gr.Row():
199
  with gr.Accordion("Ingestion"):
200
  ingestion_df = gr.DataFrame()
201
 
@@ -209,8 +234,19 @@ with gr.Blocks(theme=gr.themes.Default()) as app:
209
  answers_df = gr.DataFrame()
210
 
211
  stages_table.change(
212
- update_dataset, inputs=[stages_table, hf_org_dropdown, hf_dataset_prefix], outputs=[ingestion_df, summarization_df, single_hop, answers_df]
213
  )
214
 
 
 
 
 
 
 
 
 
 
 
 
215
 
216
  app.launch(allowed_paths=["/app"])
 
1
+ import asyncio
2
  import os
3
  import sys
4
  import time
5
  import gradio as gr
6
+
7
+ from datasets import load_dataset
8
  from huggingface_hub import whoami
9
+ from loguru import logger
10
+ from pathlib import Path
11
 
12
  from yourbench_space.config import generate_and_save_config
13
  from yourbench_space.utils import (
 
18
  update_dataset,
19
  STAGES,
20
  )
21
+ from yourbench_space.evaluation import create_eval_file, run_evaluations
22
+ from yourbench_space.leaderboard_space.env import HF_TOKEN
23
 
24
  project_description = """
25
  # YourBench 🚀
 
79
 
80
  return gr.update(value=True, label="Process Status: Running")
81
 
82
+ def prepare_task(oauth_token: gr.OAuthToken | None, hf_dataset_name: str, _=None):
83
  new_env = os.environ.copy()
84
  if oauth_token:
85
  new_env["HF_TOKEN"] = oauth_token.token
86
+ new_env["DATASET_PREFIX"] = hf_dataset_name
87
  manager.start_process(custom_env=new_env)
88
 
89
 
 
109
  def enable_button(files):
110
  return gr.update(interactive=bool(files))
111
 
112
+ def run_evaluation_pipeline(oauth_token: gr.OAuthToken | None, org_name, eval_name):
113
+ # Test dataset existence
114
+ eval_ds_name = f"{org_name}/{eval_name}"
115
+ # Test dataset existence
116
+ try:
117
+ load_dataset(eval_ds_name, streaming=True)
118
+ except Exception as e:
119
+ print(f"Error while loading the dataset: {e}")
120
+ return
121
+ # Run evaluations
122
+ create_eval_file(eval_ds_name)
123
+ status = asyncio.run(run_evaluations(eval_ds_name=eval_ds_name, org=org_name))
124
+ # Create space
125
+ from huggingface_hub import HfApi
126
+ repo_id = f"{org_name}/leaderboard_yourbench_{eval_ds_name.replace('/', '_')}"
127
+ api = HfApi()
128
+
129
+ try:
130
+ api.create_repo(repo_id=repo_id, repo_type="space", space_sdk="gradio")
131
+ api.upload_folder(repo_id=repo_id, repo_type="space", folder_path="src/")
132
+ api.add_space_secret(repo_id=repo_id, key="HF_TOKEN", value=HF_TOKEN)
133
+ api.add_space_variable(repo_id=repo_id, key="TASK", value=eval_ds_name)
134
+ api.add_space_variable(repo_id=repo_id, key="ORG_NAME", value=org_name)
135
+ except Exception as e:
136
+ status = "Evaluation" + status + "\nLeaderboard creation:" + e
137
+ return status
138
+
139
 
140
  with gr.Blocks(theme=gr.themes.Default()) as app:
141
  gr.Markdown(project_description)
142
 
 
 
 
 
 
143
  with gr.Tabs() as tabs:
144
  with gr.Tab("Setup", id=0):
145
  with gr.Row():
146
+ with gr.Column():
147
+ login_btn = gr.LoginButton()
148
+ with gr.Accordion("Hugging Face Settings"):
149
+ hf_org_dropdown = gr.Dropdown(
150
+ choices=[], label="Organization", allow_custom_value=True
151
+ )
152
+ app.load(
153
+ update_hf_org_dropdown, inputs=None, outputs=hf_org_dropdown
154
+ )
155
+
156
+ hf_dataset_name = gr.Textbox(
157
+ label="Dataset name",
158
+ value="yourbench",
159
+ info="Name of your new evaluation dataset",
160
+ )
161
 
162
  with gr.Accordion("Upload documents"):
163
  file_input = gr.File(
 
171
  file_input,
172
  output,
173
  )
174
+ with gr.Row():
175
+ preview_button = gr.Button("Generate New Config", interactive=False)
176
+ log_message = gr.Textbox(label="Log Message", visible=True)
177
+ download_button = gr.File(
178
+ label="Download Config", visible=False, interactive=False
179
+ )
180
 
181
  file_input.change(enable_button, inputs=file_input, outputs=preview_button)
182
 
183
  preview_button.click(
184
  generate_and_return,
185
+ inputs=[hf_org_dropdown, hf_dataset_name],
186
  outputs=[log_message, download_button],
187
  )
188
  preview_button.click(
 
193
 
194
  with gr.Tab("Run Generation", id=1):
195
  with gr.Row():
196
+ start_button = gr.Button("Start Task")
197
+ start_button.click(prepare_task, inputs=[login_btn, hf_dataset_name])
198
+
199
+ stop_button = gr.Button("Stop Task")
200
+ stop_button.click(manager.stop_process)
201
+
202
+ kill_button = gr.Button("Kill Task")
203
+ kill_button.click(manager.kill_process)
204
 
205
+ with gr.Column():
206
+ with gr.Row():
207
+ with gr.Accordion("Log Output", open=True):
208
+ log_output = gr.Code(language=None, lines=20, interactive=False)
209
+
210
+ with gr.Row():
211
+ process_status = gr.Checkbox(label="Process Status", interactive=False)
212
+ status_timer = gr.Timer(1.0, active=True)
213
+ status_timer.tick(update_process_status, outputs=process_status)
214
+
215
+ with gr.Column():
216
  with gr.Accordion("Stages", open=True):
217
  stages_table = gr.CheckboxGroup(
218
  choices=STAGES,
 
221
  interactive=False,
222
  )
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  with gr.Accordion("Ingestion"):
225
  ingestion_df = gr.DataFrame()
226
 
 
234
  answers_df = gr.DataFrame()
235
 
236
  stages_table.change(
237
+ update_dataset, inputs=[stages_table, hf_org_dropdown, hf_dataset_name], outputs=[ingestion_df, summarization_df, single_hop, answers_df]
238
  )
239
 
240
+ log_timer = gr.Timer(1.0, active=True)
241
+ log_timer.tick(
242
+ manager.read_and_get_output, outputs=[log_output, stages_table]
243
+ )
244
+ with gr.Tab("Evaluate", id=2):
245
+ with gr.Row():
246
+ btn_launch_evals = gr.Button("Launch evaluations")
247
+ status = gr.Textbox(label="Status")
248
+
249
+ btn_launch_evals.click(run_evaluation_pipeline, [hf_org_dropdown, hf_dataset_name], status)
250
+
251
 
252
  app.launch(allowed_paths=["/app"])
yourbench_space/evaluation.py ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import asyncio, os
2
+ from src.env import INIT_MODELS
3
+
4
+ ON_SPACES=os.environ.get("system") == "spaces"
5
+ OUTPUT_DIR = "/data" if ON_SPACES else "."
6
+
7
+ def create_eval_file(eval_ds_name):
8
+ # TODO: replace by Nathan's call
9
+ content = """
10
+ from aenum import extend_enum
11
+
12
+ from lighteval.metrics.metrics import Metrics
13
+ from lighteval.metrics.utils.metric_utils import (
14
+ CorpusLevelMetricGrouping,
15
+ MetricCategory,
16
+ MetricUseCase,
17
+ )
18
+ from lighteval.tasks.lighteval_task import LightevalTaskConfig
19
+ from lighteval.tasks.extended.hle.main import JudgeLLMHLE
20
+ from lighteval.tasks.requests import Doc
21
+
22
+
23
+ def prompt_function(line, task_name: str = None):
24
+ if line["image"] not in [None, ""]:
25
+ return
26
+
27
+ return Doc(
28
+ task_name=task_name,
29
+ query="Question: " + line["question"] + "\\nAnswer:",
30
+ choices=[line["answer"]],
31
+ gold_index=0,
32
+ specific={"question": line["question"]},
33
+ )
34
+ """ + f"""
35
+
36
+ hle = LightevalTaskConfig(
37
+ name="{eval_ds_name.replace('/', '_')}",
38
+ suite=["custom"],
39
+ prompt_function=prompt_function,
40
+ hf_repo="{eval_ds_name}",
41
+ hf_subset="default",
42
+ hf_avail_splits=["test"],
43
+ evaluation_splits=["test"],
44
+ few_shots_split=None,
45
+ few_shots_select=None,
46
+ generation_size=8192,
47
+ metric=[Metrics.exact_match],
48
+ stop_sequence=[],
49
+ trust_dataset=True,
50
+ version=0,
51
+ )
52
+
53
+
54
+ TASKS_TABLE = [hle]
55
+ """
56
+
57
+ with open(f"{OUTPUT_DIR}/custom_task.py", "w") as f:
58
+ f.write(content)
59
+
60
+ async def run_process(args: list) -> dict:
61
+ process = await asyncio.create_subprocess_exec(
62
+ *args,
63
+ stdout=asyncio.subprocess.PIPE,
64
+ stderr=asyncio.subprocess.PIPE
65
+ )
66
+ await asyncio.wait_for(process.wait(), timeout=180)
67
+ stdout = await process.stdout.read()
68
+ stderr = await process.stderr.read()
69
+ return {
70
+ 'pid': process.pid,
71
+ 'stdout': stdout.decode(),
72
+ 'stderr': stderr.decode()
73
+ }
74
+
75
+ async def run_evaluations(eval_ds_name: str, org: str) -> list:
76
+ tasks = []
77
+ for model_name, provider in INIT_MODELS:
78
+ args = [
79
+ "lighteval",
80
+ "endpoint", "inference-providers", f"model={model_name},provider={provider}",
81
+ f"custom|{eval_ds_name.replace('/', '_')}|0|0", "--custom-tasks", f"{OUTPUT_DIR}/custom_task.py", "--max-samples", "10",
82
+ "--output-dir", f"{OUTPUT_DIR}", "--save-details", "--results-org", org, "--push-to-hub"
83
+ ]
84
+ tasks.append(run_process(args))
85
+ # Will capture the task if failed
86
+ processes = await asyncio.gather(*tasks, return_exceptions=True)
87
+ if all(not isinstance(result, Exception) for result in processes):
88
+ return "✅"
89
+ return "At least one model failed"
yourbench_space/leaderboard_space/app.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ from utils import run_pipeline, update_examples
4
+ from env import TASK
5
+
6
+ with gr.Blocks(
7
+ title="YourBench Leaderboard",
8
+ theme=gr.themes.Soft(),
9
+ css="button { margin: 0 10px; padding: 5px 15px; }",
10
+ ) as demo:
11
+ # DISPLAY TABLE AND ANALYSIS
12
+ title = gr.Markdown(f"YourBench auto-Leaderboard for {TASK}")
13
+ leaderboard = gr.DataFrame(label="Results", interactive=False)
14
+ samples_ix = gr.Number(
15
+ label="Example Index",
16
+ value=0,
17
+ step=1,
18
+ info="Navigate through different examples"
19
+ )
20
+ with gr.Tab("Hardest samples"):
21
+ hard_samples = gr.HTML()
22
+ with gr.Tab("Easiest samples"):
23
+ easy_samples = gr.HTML()
24
+ with gr.Tab("All samples"):
25
+ all_samples = gr.HTML()
26
+
27
+ samples_ix.change(update_examples, samples_ix, [easy_samples, hard_samples, all_samples])
28
+
29
+ demo.load(run_pipeline, [samples_ix], [leaderboard, easy_samples, hard_samples, all_samples])
30
+
31
+ demo.launch()
yourbench_space/leaderboard_space/env.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ INIT_MODELS = [
3
+ # 70B
4
+ ("Qwen/Qwen2.5-72B-Instruct", "sambanova"),
5
+ ("meta-llama/Llama-3.3-70B-Instruct", "together"),
6
+ ("deepseek-ai/DeepSeek-R1-Distill-Llama-70B", "sambanova"),
7
+ # 20 to 30B
8
+ ("Qwen/QwQ-32B", "sambanova"),
9
+ ("mistralai/Mistral-Small-24B-Instruct-2501", "together"),
10
+ #("allenai/OLMo-2-0325-32B-Instruct", "hf-inference")
11
+ ]
12
+ MODELS = [m[0] for m in INIT_MODELS]
13
+ TASK = os.getenv("TASK")
14
+ # With storage
15
+ HF_TOKEN=os.getenv("HF_TOKEN")
16
+ ORG_NAME = os.getenv("ORG_NAME")
yourbench_space/leaderboard_space/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ datasets
2
+ huggingface_hub
yourbench_space/leaderboard_space/utils.py ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datasets import load_dataset, Dataset
2
+ from functools import lru_cache
3
+ from typing import Tuple
4
+ import gradio as gr
5
+ import json
6
+
7
+ from env import MODELS, TASK, ORG_NAME
8
+
9
+ def aggregate_results() -> list:
10
+ """From the path of outputs and model list, extracts the current scores and stores them in a list of dicts with model, score, time as keys
11
+ """
12
+ all_results = []
13
+ for org_model in MODELS:
14
+ try:
15
+ path = f"{ORG_NAME}/details_{org_model.replace('/', '__')}_private"
16
+ ds = load_dataset(path, "results", split="latest")
17
+ config = json.loads(ds["config_general"][0])
18
+ results = json.loads(ds["results"][0])
19
+
20
+ # Model data
21
+ org, model = org_model.split("/")
22
+
23
+ cur_result = {
24
+ "Org": org,
25
+ "Model": model,
26
+ "Duration (s)": config["end_time"] - config["start_time"]
27
+ }
28
+
29
+ # Extract the task from the JSON data
30
+ for k_metric, v_dict in results.items():
31
+ if k_metric != "all":
32
+ for k, v in v_dict.items():
33
+ cur_result[f"{k}({k_metric})"] = v
34
+ all_results.append(cur_result)
35
+ except Exception as e:
36
+ print(f"Error processing {model} {ORG_NAME}: {e}")
37
+ return all_results
38
+
39
+ def extract_dataviz() -> Tuple[list, list]:
40
+ """From the path of outputs and model list, extracts from the details the worst samples, best samples
41
+ """
42
+ all_samples = {}
43
+ for org_model in MODELS:
44
+ try:
45
+ path = f"{ORG_NAME}/details_{org_model.replace('/', '__')}_private"
46
+ ds = load_dataset(path, f"custom_{TASK.replace('/', '_')}_0", split="latest")
47
+
48
+ for ix, row in enumerate(ds):
49
+ prompt = row["full_prompt"]
50
+ gold = row["gold"]
51
+ score = list(row["metrics"].values())[0]
52
+ prediction = row["predictions"][0]
53
+
54
+
55
+ # We store flattened samples in a dict
56
+ # ix -> ix, prompt, gold, model_score for each model, model_prediction for each model
57
+ # then 2 lists: model_scores and models, to aggreg more easily
58
+ if ix not in all_samples:
59
+ all_samples[ix] = {
60
+ "ix": ix,
61
+ "prompt": prompt,
62
+ "gold": gold[0] if isinstance(gold, list) else gold,
63
+ # A bit redundant, but put in their own boxes for simplicity of access later
64
+ "model_scores": [],
65
+ "models": []
66
+ }
67
+ if org_model not in all_samples[ix]["models"]:
68
+ all_samples[ix][f"{org_model}_score"] = row["metrics"]
69
+ all_samples[ix][f"{org_model}_prediction"] = prediction
70
+ all_samples[ix]["model_scores"].append(score)
71
+ all_samples[ix]["models"].append(org_model)
72
+
73
+ except Exception as e:
74
+ print(f"Error processing {org_model}: {e}")
75
+
76
+ full_samples = sorted(list(all_samples.values()), key= lambda r: r['ix'])
77
+ hard_samples = sorted([sample for sample in all_samples.values() if sum(sample["model_scores"]) == 0], key= lambda r: r['ix'])
78
+ easy_samples = sorted([sample for sample in all_samples.values() if sum(sample["model_scores"]) == len(sample["model_scores"])], key= lambda r: r['ix'])
79
+ return easy_samples, hard_samples, full_samples
80
+
81
+ def samples_to_box_display(samples: list, example_index: int = 0):
82
+ """Adapted from Nathan's code in https://huggingface.co/spaces/SaylorTwift/OpenEvalsModelDetails/
83
+ """
84
+ if len(samples) == 0:
85
+ return "No samples in this category!"
86
+ outputs = []
87
+ sample = samples[example_index]
88
+ for model in sample["models"]:
89
+ try:
90
+ outputs.append({
91
+ 'Model': model,
92
+ 'Prediction': sample[f'{model}_prediction'],
93
+ 'Prompt': sample['prompt'],
94
+ 'Metrics': sample[f'{model}_score'],
95
+ 'Gold': sample['gold']
96
+ })
97
+ except (KeyError, IndexError):
98
+ continue
99
+
100
+ if not outputs:
101
+ return "No results found for the selected combination."
102
+
103
+ # Create HTML output with all models
104
+ html_output = "<div style='max-width: 800px; margin: 0 auto;'>\n\n"
105
+
106
+ # Show gold answer at the top with distinct styling
107
+ if outputs:
108
+ html_output += "<div style='background: #e6f3e6; padding: 20px; border-radius: 10px; margin-bottom: 20px;'>\n"
109
+ html_output += "<h3 style='margin-top: 0;'>Ground Truth</h3>\n"
110
+ html_output += "<div style='overflow-x: auto; max-width: 100%;'>\n"
111
+ html_output += f"<pre style='white-space: pre-wrap; word-wrap: break-word; margin: 0;'><code>{outputs[0]['Gold']}</code></pre>\n"
112
+ html_output += "</div>\n"
113
+ html_output += "</div>\n"
114
+
115
+ for output in outputs:
116
+ html_output += "<div style='background: #f5f5f5; padding: 20px; margin-bottom: 20px; border-radius: 10px;'>\n"
117
+ html_output += f"<h2 style='margin-top: 0;'>{output['Model']}</h2>\n"
118
+
119
+ # Format metrics as a clean table
120
+ html_output += "<details open style='margin-bottom: 15px;'>\n"
121
+ html_output += "<summary><h3 style='display: inline; margin: 0;'>Metrics</h3></summary>\n"
122
+ metrics = output['Metrics']
123
+ if isinstance(metrics, str):
124
+ metrics = eval(metrics)
125
+ html_output += "<div style='overflow-x: auto;'>\n"
126
+ html_output += "<table style='width: 100%; margin: 10px 0; border-collapse: collapse;'>\n"
127
+ for key, value in metrics.items():
128
+ if isinstance(value, float):
129
+ value = f"{value:.3f}"
130
+ html_output += f"<tr><td style='padding: 5px; border-bottom: 1px solid #ddd;'><strong>{key}</strong></td><td style='padding: 5px; border-bottom: 1px solid #ddd;'>{value}</td></tr>\n"
131
+ html_output += "</table>\n"
132
+ html_output += "</div>\n"
133
+ html_output += "</details>\n\n"
134
+
135
+ # Handle prompt formatting with better styling
136
+ html_output += "<details style='margin-bottom: 15px;'>\n"
137
+ html_output += "<summary><h3 style='display: inline; margin: 0;'>Prompt</h3></summary>\n"
138
+ html_output += "<div style='background: #ffffff; padding: 15px; border-radius: 5px; margin-top: 10px;'>\n"
139
+
140
+ prompt_text = output['Prompt']
141
+ if isinstance(prompt_text, list):
142
+ for i, msg in enumerate(prompt_text):
143
+ if isinstance(msg, dict) and 'content' in msg:
144
+ role = msg.get('role', 'message').title()
145
+ html_output += "<div style='margin-bottom: 10px;'>\n"
146
+ html_output += f"<strong>{role}:</strong>\n"
147
+ html_output += "<div style='overflow-x: auto;'>\n"
148
+ html_output += f"<pre style='white-space: pre-wrap; word-wrap: break-word; margin: 5px 0;'><code>{msg['content']}</code></pre>\n"
149
+ html_output += "</div>\n"
150
+ html_output += "</div>\n"
151
+ else:
152
+ html_output += "<div style='margin-bottom: 10px;'>\n"
153
+ html_output += "<div style='overflow-x: auto;'>\n"
154
+ html_output += f"<pre style='white-space: pre-wrap; word-wrap: break-word; margin: 5px 0;'><code>{json.dumps(msg, indent=2)}</code></pre>\n"
155
+ html_output += "</div>\n"
156
+ html_output += "</div>\n"
157
+ else:
158
+ html_output += "<div style='overflow-x: auto;'>\n"
159
+ if isinstance(prompt_text, dict) and 'content' in prompt_text:
160
+ html_output += f"<pre style='white-space: pre-wrap; word-wrap: break-word; margin: 5px 0;'><code>{prompt_text['content']}</code></pre>\n"
161
+ else:
162
+ html_output += f"<pre style='white-space: pre-wrap; word-wrap: break-word; margin: 5px 0;'><code>{prompt_text}</code></pre>\n"
163
+ html_output += "</div>\n"
164
+
165
+ html_output += "</div>\n"
166
+ html_output += "</details>\n\n"
167
+
168
+ # Style prediction output - now in a collapsible section
169
+ html_output += "<details open style='margin-bottom: 15px;'>\n"
170
+ html_output += "<summary><h3 style='display: inline; margin: 0;'>Prediction</h3>"
171
+ # Add word count in a muted style
172
+ word_count = len(output['Prediction'].split())
173
+ html_output += f"<span style='color: #666; font-size: 0.8em; margin-left: 10px;'>({word_count} words)</span>"
174
+ html_output += "</summary>\n"
175
+ html_output += "<div style='background: #ffffff; padding: 15px; border-radius: 5px; margin-top: 10px;'>\n"
176
+ html_output += "<div style='overflow-x: auto;'>\n"
177
+ html_output += f"<pre style='white-space: pre-wrap; word-wrap: break-word; margin: 0;'><code>{output['Prediction']}</code></pre>\n"
178
+ html_output += "</div>\n"
179
+ html_output += "</div>\n"
180
+ html_output += "</details>\n"
181
+ html_output += "</div>\n\n"
182
+
183
+ html_output += "</div>"
184
+ return html_output
185
+
186
+ def run_pipeline(samples_ix: int = 0):
187
+ results = aggregate_results()
188
+ best_samples, worst_samples, all_samples = extract_dataviz()
189
+ return gr.Dataframe(Dataset.from_list(results).to_pandas(), visible=True), \
190
+ gr.HTML(samples_to_box_display(best_samples, samples_ix), label="Easiest samples (always found)", visible=True), \
191
+ gr.HTML(samples_to_box_display(worst_samples, samples_ix), label="Hardest samples (always failed)", visible=True), \
192
+ gr.HTML(samples_to_box_display(all_samples, samples_ix), label="All samples", visible=True)
193
+
194
+ def update_examples(samples_ix: int = 0):
195
+ best_samples, worst_samples, all_samples = extract_dataviz()
196
+ return samples_to_box_display(best_samples, samples_ix), \
197
+ samples_to_box_display(worst_samples, samples_ix), \
198
+ samples_to_box_display(all_samples, samples_ix)
yourbench_space/utils.py CHANGED
@@ -22,6 +22,8 @@ STAGES = [
22
  "chunking",
23
  "single_shot_question_generation",
24
  "answer_generation",
 
 
25
  # "judge_answers", # to uncomment when fixed
26
  ]
27
 
@@ -55,20 +57,31 @@ def update_dataset(stages, hf_org, hf_prefix):
55
  """
56
  Updates the dataset based on the provided stages and dataset configuration.
57
  """
58
- # If not the final step, return empty dataframes
59
- if stages[-1] != STAGES[-1]:
60
- return (pd.DataFrame(), pd.DataFrame(), pd.DataFrame(), pd.DataFrame())
61
-
 
62
  # Construct dataset name from config
63
  dataset_name = f"{hf_org}/{hf_prefix}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
- # Load datasets and convert to DataFrame
66
- ingestion_df = pd.DataFrame(load_dataset(dataset_name, name="ingested", split="train", streaming=True))
67
- summarization_df = pd.DataFrame(load_dataset(dataset_name, name="summarization", split="train", streaming=True))
68
- single_hop = pd.DataFrame(load_dataset(dataset_name, name="single_shot_question_generation", split="train", streaming=True))
69
- answers_df = pd.DataFrame(load_dataset(dataset_name, name="answer_generation", split="train", streaming=True))
70
-
71
- return (ingestion_df, summarization_df, single_hop, answers_df)
72
 
73
  class SubprocessManager:
74
  def __init__(self, command):
 
22
  "chunking",
23
  "single_shot_question_generation",
24
  "answer_generation",
25
+ #"evaluate_models",
26
+ #"create_leaderboard"
27
  # "judge_answers", # to uncomment when fixed
28
  ]
29
 
 
57
  """
58
  Updates the dataset based on the provided stages and dataset configuration.
59
  """
60
+ ingestion_df = pd.DataFrame()
61
+ summarization_df = pd.DataFrame()
62
+ single_hop_df = pd.DataFrame()
63
+ answers_df = pd.DataFrame()
64
+
65
  # Construct dataset name from config
66
  dataset_name = f"{hf_org}/{hf_prefix}"
67
+
68
+ # TODO: add cache dir
69
+ # Will be able to group everything in one pass once the names get homogeneized
70
+ if "ingestion" in stages:
71
+ # TODO: why is the key "ingested" and not "ingestion"? (does not match the other splits)
72
+ ingestion_ds = load_dataset(dataset_name, name="ingested", split="train", streaming=True)
73
+ ingestion_df = pd.DataFrame([next(iter(ingestion_ds)) for _ in range(5)])
74
+ if "summarization" in stages:
75
+ summarization_ds = load_dataset(dataset_name, name="summarization", split="train", streaming=True)
76
+ summarization_df = pd.DataFrame([next(iter(summarization_ds)) for _ in range(5)])
77
+ if "single_shot_question_generation" in stages:
78
+ single_hop_ds = load_dataset(dataset_name, name="single_shot_question_generation", split="train", streaming=True)
79
+ single_hop_df = pd.DataFrame([next(iter(single_hop_ds)) for _ in range(5)])
80
+ if "answer_generation" in stages:
81
+ answers_ds = load_dataset(dataset_name, name="answer_generation", split="train", streaming=True)
82
+ answers_df = pd.DataFrame([next(iter(answers_ds)) for _ in range(5)])
83
 
84
+ return (ingestion_df, summarization_df, single_hop_df, answers_df)
 
 
 
 
 
 
85
 
86
  class SubprocessManager:
87
  def __init__(self, command):