Alina Lozovskaya commited on
Commit
7ccf9d4
·
1 Parent(s): a8fcdeb

Simplify Setup tab

Browse files
yourbench_space/app.py CHANGED
@@ -1,16 +1,15 @@
1
  import os
2
  import sys
 
3
  import gradio as gr
 
4
  from loguru import logger
5
- from huggingface_hub import HfApi, whoami
6
 
7
- from yourbench_space.config import generate_base_config, save_config
8
  from yourbench_space.utils import (
9
  CONFIG_PATH,
10
  UPLOAD_DIRECTORY,
11
- BASE_API_URLS,
12
- AVAILABLE_MODELS,
13
- DEFAULT_MODEL,
14
  SubprocessManager,
15
  save_files,
16
  )
@@ -23,21 +22,33 @@ logger.add(sys.stderr, level="INFO")
23
  command = ["uv", "run", "yourbench", f"--config={CONFIG_PATH}"]
24
  manager = SubprocessManager(command)
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  def prepare_task(oauth_token: gr.OAuthToken | None, model_token: str):
 
28
  new_env = os.environ.copy()
29
- # Override env token, when running in gradio space
30
  if oauth_token:
31
  new_env["HF_TOKEN"] = oauth_token.token
32
  new_env["MODEL_API_KEY"] = model_token
33
  manager.start_process(custom_env=new_env)
34
 
35
-
36
  def update_hf_org_dropdown(oauth_token: gr.OAuthToken | None):
 
37
  if oauth_token is None:
38
- print(
39
- "Please, deploy this on Spaces and log in to view the list of available organizations"
40
- )
41
  return gr.Dropdown([], label="Organization")
42
 
43
  try:
@@ -46,108 +57,49 @@ def update_hf_org_dropdown(oauth_token: gr.OAuthToken | None):
46
  user_name = user_info.get("name", "Unknown User")
47
  org_names.insert(0, user_name)
48
  return gr.Dropdown(org_names, value=user_name, label="Organization")
49
-
50
  except Exception as e:
51
  print(f"Error retrieving user info: {e}")
52
- return gr.Dropdown([], label="Organization")
53
 
 
 
 
54
 
55
- config_output = gr.Code(label="Generated Config", language="yaml")
56
- model_name = gr.Dropdown(
57
- label="Model Name",
58
- value=DEFAULT_MODEL,
59
- choices=AVAILABLE_MODELS,
60
- allow_custom_value=True,
61
- )
62
- base_url = gr.Textbox(
63
- label="Model API Base URL",
64
- value=BASE_API_URLS["huggingface"],
65
- info="Use a custom API base URL for Hugging Face Inference Endpoints",
66
- )
67
 
68
  with gr.Blocks() as app:
69
- gr.Markdown("## YourBench Configuration")
 
70
  with gr.Row():
71
  login_btn = gr.LoginButton()
72
 
73
- with gr.Tab("Configuration"):
74
- with gr.Accordion("Hugging Face"):
75
- hf_org_dropdown = gr.Dropdown(
76
- list(),
77
- label="Organization",
78
- allow_custom_value=True,
79
- )
80
- app.load(update_hf_org_dropdown, inputs=None, outputs=hf_org_dropdown)
81
-
82
- hf_dataset_prefix = gr.Textbox(
83
- label="Dataset Prefix",
84
- value="yourbench",
85
- info="Prefix applied to all datasets",
86
- )
87
- private_dataset = gr.Checkbox(
88
- label="Private Dataset",
89
- value=True,
90
- info="Create private datasets (recommended by default)",
91
- )
92
-
93
- with gr.Accordion("Model"):
94
- model_name.render()
95
-
96
- provider = gr.Radio(
97
- ["huggingface", "openrouter", "openai"],
98
- value="huggingface",
99
- label="Inference Provider",
100
- )
101
-
102
- def set_base_url(provider):
103
- return gr.Textbox(
104
- label="Model API Base URL", value=BASE_API_URLS.get(provider, "")
105
- )
106
-
107
- provider.change(fn=set_base_url, inputs=provider, outputs=base_url)
108
- model_api_key = gr.Textbox(label="Model API Key", type="password")
109
- base_url.render()
110
- max_concurrent_requests = gr.Radio(
111
- [8, 16, 32], value=16, label="Max Concurrent Requests"
112
- )
113
-
114
- preview_button = gr.Button("Generate New Config")
115
- preview_button.click(
116
- generate_base_config,
117
- inputs=[
118
- hf_org_dropdown,
119
- hf_dataset_prefix,
120
- model_name,
121
- provider,
122
- base_url,
123
- model_api_key,
124
- max_concurrent_requests,
125
- private_dataset,
126
- ],
127
- outputs=config_output,
128
- )
129
 
130
- with gr.Tab("Raw Configuration"):
131
- config_output.render()
132
- config_output.change(
133
- fn=save_config,
134
- inputs=[config_output],
135
- outputs=[gr.Textbox(label="Save Status")],
136
- )
137
 
138
- with gr.Tab("Files"):
139
- file_input = gr.File(
140
- label="Upload text files",
141
- file_count="multiple",
142
- file_types=[".txt", ".md", ".html"],
 
 
 
 
 
143
  )
144
- output = gr.Textbox(label="Log")
145
- file_input.upload(save_files, file_input, output)
146
 
147
  with gr.Tab("Run Generation"):
148
- log_output = gr.Code(
149
- label="Log Output", language=None, lines=20, interactive=False
150
- )
151
  log_timer = gr.Timer(0.05, active=True)
152
  log_timer.tick(manager.read_and_get_output, outputs=log_output)
153
 
@@ -158,7 +110,7 @@ with gr.Blocks() as app:
158
 
159
  with gr.Row():
160
  start_button = gr.Button("Start Task")
161
- start_button.click(prepare_task, inputs=[model_api_key])
162
 
163
  stop_button = gr.Button("Stop Task")
164
  stop_button.click(manager.stop_process)
@@ -166,4 +118,4 @@ with gr.Blocks() as app:
166
  kill_button = gr.Button("Kill Task")
167
  kill_button.click(manager.kill_process)
168
 
169
- app.launch()
 
1
  import os
2
  import sys
3
+ import time # Needed for file existence check
4
  import gradio as gr
5
+ import yaml
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 (
11
  CONFIG_PATH,
12
  UPLOAD_DIRECTORY,
 
 
 
13
  SubprocessManager,
14
  save_files,
15
  )
 
22
  command = ["uv", "run", "yourbench", f"--config={CONFIG_PATH}"]
23
  manager = SubprocessManager(command)
24
 
25
+ def generate_and_return(hf_org, hf_prefix):
26
+ """Handles config generation and validates file existence before enabling download"""
27
+ generate_and_save_config(hf_org, hf_prefix) # No need to store the return value
28
+
29
+ # Wait until the config file is actually created
30
+ for _ in range(5):
31
+ if CONFIG_PATH.exists():
32
+ break
33
+ time.sleep(0.5)
34
+
35
+ if CONFIG_PATH.exists():
36
+ return "✅ Config saved!", gr.update(value=str(CONFIG_PATH), visible=True, interactive=True)
37
+ else:
38
+ return "❌ Config generation failed.", gr.update(visible=False, interactive=False)
39
 
40
  def prepare_task(oauth_token: gr.OAuthToken | None, model_token: str):
41
+ """Prepares and starts the subprocess with environment variables."""
42
  new_env = os.environ.copy()
 
43
  if oauth_token:
44
  new_env["HF_TOKEN"] = oauth_token.token
45
  new_env["MODEL_API_KEY"] = model_token
46
  manager.start_process(custom_env=new_env)
47
 
 
48
  def update_hf_org_dropdown(oauth_token: gr.OAuthToken | None):
49
+ """Updates the dropdown with the user's Hugging Face organizations"""
50
  if oauth_token is None:
51
+ print("Please deploy this on Spaces and log in to view the list of available organizations")
 
 
52
  return gr.Dropdown([], label="Organization")
53
 
54
  try:
 
57
  user_name = user_info.get("name", "Unknown User")
58
  org_names.insert(0, user_name)
59
  return gr.Dropdown(org_names, value=user_name, label="Organization")
60
+
61
  except Exception as e:
62
  print(f"Error retrieving user info: {e}")
63
+ return gr.Dropdown([], label="Organization")
64
 
65
+ def enable_button(files):
66
+ """Enables the button if files are uploaded"""
67
+ return gr.update(interactive=bool(files))
68
 
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
  with gr.Blocks() as app:
71
+ gr.Markdown("## YourBench Setup")
72
+
73
  with gr.Row():
74
  login_btn = gr.LoginButton()
75
 
76
+ with gr.Tab("Setup"):
77
+ with gr.Row():
78
+ with gr.Accordion("Hugging Face Settings"):
79
+ hf_org_dropdown = gr.Dropdown(choices=[], label="Organization", allow_custom_value=True)
80
+ app.load(update_hf_org_dropdown, inputs=None, outputs=hf_org_dropdown)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
+ hf_dataset_prefix = gr.Textbox(label="Dataset Prefix", value="yourbench", info="Prefix applied to all datasets")
83
+
84
+ with gr.Accordion("Upload documents"):
85
+ file_input = gr.File(label="Upload text files", file_count="multiple", file_types=[".txt", ".md", ".html"])
86
+ output = gr.Textbox(label="Log")
87
+ file_input.upload(lambda files: save_files([file.name for file in files]), file_input, output)
 
88
 
89
+ preview_button = gr.Button("Generate New Config", interactive=False)
90
+ log_message = gr.Textbox(label="Log Message", visible=True)
91
+ download_button = gr.File(label="Download Config", visible=False, interactive=False)
92
+
93
+ file_input.change(enable_button, inputs=file_input, outputs=preview_button)
94
+
95
+ preview_button.click(
96
+ generate_and_return,
97
+ inputs=[hf_org_dropdown, hf_dataset_prefix],
98
+ outputs=[log_message, download_button],
99
  )
 
 
100
 
101
  with gr.Tab("Run Generation"):
102
+ log_output = gr.Code(label="Log Output", language=None, lines=20, interactive=False)
 
 
103
  log_timer = gr.Timer(0.05, active=True)
104
  log_timer.tick(manager.read_and_get_output, outputs=log_output)
105
 
 
110
 
111
  with gr.Row():
112
  start_button = gr.Button("Start Task")
113
+ start_button.click(prepare_task, inputs=[hf_org_dropdown])
114
 
115
  stop_button = gr.Button("Stop Task")
116
  stop_button.click(manager.stop_process)
 
118
  kill_button = gr.Button("Kill Task")
119
  kill_button.click(manager.kill_process)
120
 
121
+ app.launch(allowed_paths=["/app"])
yourbench_space/config.py CHANGED
@@ -1,49 +1,43 @@
1
  import yaml
 
2
  from yourbench_space.utils import CONFIG_PATH
3
 
4
- def generate_base_config(
5
- hf_org,
6
- hf_dataset_name,
7
- model_name,
8
- provider,
9
- base_url,
10
- model_api_key,
11
- max_concurrent_requests,
12
- private_dataset,
13
- ):
14
- config = {
15
  "hf_configuration": {
16
  "token": "$HF_TOKEN",
17
- "private": private_dataset,
18
- "hf_organization": hf_org,
19
- "hf_dataset_name": hf_dataset_name,
20
  },
 
21
  "model_list": [
22
  {
23
- "model_name": model_name,
24
- "provider": provider,
25
- "base_url": base_url,
26
- "api_key": "$MODEL_API_KEY",
27
- "max_concurrent_requests": max_concurrent_requests,
28
  }
29
  ],
30
  "model_roles": {
31
- "ingestion": [model_name],
32
- "summarization": [model_name],
33
- "single_shot_question_generation": [model_name],
34
- "multi_hop_question_generation": [model_name],
35
- "answer_generation": [model_name],
36
- "judge_answers": [model_name],
37
  },
38
  "pipeline": {
39
  "ingestion": {
40
  "source_documents_dir": "/app/uploaded_files",
41
  "output_dir": "/app/ingested",
42
- "run": True,
43
  },
44
  "upload_ingest_to_hub": {
45
  "source_documents_dir": "/app/ingested",
46
- "run": True,
47
  },
48
  "summarization": {"run": True},
49
  "chunking": {
@@ -52,34 +46,42 @@ def generate_base_config(
52
  "l_max_tokens": 128,
53
  "tau_threshold": 0.3,
54
  "h_min": 2,
55
- "h_max": 4,
56
  },
57
- "run": True,
58
  },
59
  "single_shot_question_generation": {
60
  "diversification_seed": "24 year old adult",
61
- "run": True,
62
  },
63
  "multi_hop_question_generation": {"run": True},
64
  "answer_generation": {
65
  "question_type": "single_shot",
66
  "run": True,
67
  "strategies": [
68
- {"name": "zeroshot", "prompt": "ZEROSHOT_QA_USER_PROMPT", "model_name": model_name},
69
- {"name": "gold", "prompt": "GOLD_QA_USER_PROMPT", "model_name": model_name},
70
- ],
71
  },
72
  "judge_answers": {
73
  "run": True,
74
  "comparing_strategies": [["zeroshot", "gold"]],
75
  "chunk_column_index": 0,
76
- "random_seed": 42,
77
- },
78
- },
79
  }
80
- return yaml.dump(config, sort_keys=False)
81
 
82
- def save_config(yaml_text):
 
83
  with open(CONFIG_PATH, "w") as file:
84
- file.write(yaml_text)
85
- return "✅ Config saved!"
 
 
 
 
 
 
 
 
 
1
  import yaml
2
+ from loguru import logger
3
  from yourbench_space.utils import CONFIG_PATH
4
 
5
+ def generate_base_config(hf_org, hf_prefix):
6
+ """Creates the base config dictionary"""
7
+ return {
 
 
 
 
 
 
 
 
8
  "hf_configuration": {
9
  "token": "$HF_TOKEN",
10
+ "private": True,
11
+ "hf_organization": hf_org,
12
+ "hf_dataset_name": hf_prefix
13
  },
14
+ "local_dataset_dir": "results/",
15
  "model_list": [
16
  {
17
+ "model_name": "meta-llama/Llama-3.3-70B-Instruct",
18
+ "provider": "huggingface",
19
+ "base_url": "https://jsq69lxgkhvpnliw.us-east-1.aws.endpoints.huggingface.cloud",
20
+ "api_key": "$HF_TOKEN",
21
+ "max_concurrent_requests": 16
22
  }
23
  ],
24
  "model_roles": {
25
+ "ingestion": ["meta-llama/Llama-3.3-70B-Instruct"],
26
+ "summarization": ["meta-llama/Llama-3.3-70B-Instruct"],
27
+ "single_shot_question_generation": ["meta-llama/Llama-3.3-70B-Instruct"],
28
+ "multi_hop_question_generation": ["meta-llama/Llama-3.3-70B-Instruct"],
29
+ "answer_generation": ["meta-llama/Llama-3.3-70B-Instruct"],
30
+ "judge_answers": ["meta-llama/Llama-3.3-70B-Instruct"]
31
  },
32
  "pipeline": {
33
  "ingestion": {
34
  "source_documents_dir": "/app/uploaded_files",
35
  "output_dir": "/app/ingested",
36
+ "run": True
37
  },
38
  "upload_ingest_to_hub": {
39
  "source_documents_dir": "/app/ingested",
40
+ "run": True
41
  },
42
  "summarization": {"run": True},
43
  "chunking": {
 
46
  "l_max_tokens": 128,
47
  "tau_threshold": 0.3,
48
  "h_min": 2,
49
+ "h_max": 4
50
  },
51
+ "run": True
52
  },
53
  "single_shot_question_generation": {
54
  "diversification_seed": "24 year old adult",
55
+ "run": True
56
  },
57
  "multi_hop_question_generation": {"run": True},
58
  "answer_generation": {
59
  "question_type": "single_shot",
60
  "run": True,
61
  "strategies": [
62
+ {"name": "zeroshot", "prompt": "ZEROSHOT_QA_USER_PROMPT", "model_name": "meta-llama/Llama-3.3-70B-Instruct"},
63
+ {"name": "gold", "prompt": "GOLD_QA_USER_PROMPT", "model_name": "meta-llama/Llama-3.3-70B-Instruct"}
64
+ ]
65
  },
66
  "judge_answers": {
67
  "run": True,
68
  "comparing_strategies": [["zeroshot", "gold"]],
69
  "chunk_column_index": 0,
70
+ "random_seed": 42
71
+ }
72
+ }
73
  }
 
74
 
75
+ def save_yaml_file(config):
76
+ """Saves the given config dictionary to a YAML file"""
77
  with open(CONFIG_PATH, "w") as file:
78
+ yaml.dump(config, file, default_flow_style=False, sort_keys=False)
79
+ return CONFIG_PATH
80
+
81
+ def generate_and_save_config(hf_org, hf_prefix):
82
+ """Generates and saves the YAML configuration file"""
83
+ logger.debug(f"Generating config with org: {hf_org}, prefix: {hf_prefix}")
84
+ config = generate_base_config(hf_org, hf_prefix)
85
+ file_path = save_yaml_file(config)
86
+ logger.success(f"Config saved at: {file_path}")
87
+ return file_path
yourbench_space/utils.py CHANGED
@@ -4,26 +4,34 @@ import pathlib
4
  import shutil
5
  from loguru import logger
6
  import subprocess
 
7
 
8
  UPLOAD_DIRECTORY = pathlib.Path("/app/uploaded_files")
9
  CONFIG_PATH = pathlib.Path("/app/yourbench_config.yml")
10
 
11
- AVAILABLE_MODELS = [
12
- "mistralai/Mistral-Small-24B-Instruct-2501",
13
- "meta-llama/Llama-3.3-70B-Instruct",
14
- ]
15
- DEFAULT_MODEL = AVAILABLE_MODELS[0]
16
 
17
- BASE_API_URLS = {
18
- "huggingface": "https://router.huggingface.co/hf-inference/v1",
19
- "openrouter": "https://openrouter.ai/api/v1",
20
- "openai": "https://api.openai.com/v1/",
21
- }
22
 
23
- def save_files(files: list[str]):
24
- saved_paths = [shutil.move(str(pathlib.Path(file)), str(UPLOAD_DIRECTORY / pathlib.Path(file).name)) for file in files]
25
- return f"Files saved to: {', '.join(saved_paths)}"
 
26
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  class SubprocessManager:
29
  def __init__(self, command):
@@ -51,7 +59,7 @@ class SubprocessManager:
51
  logger.info("Started the process")
52
 
53
  def read_and_get_output(self):
54
- """Read available subprocess output and return the captured output."""
55
  if self.process and self.process.stdout:
56
  try:
57
  while True:
@@ -76,7 +84,7 @@ class SubprocessManager:
76
  #return exit_code
77
 
78
  def kill_process(self):
79
- """Forcefully kill the subprocess."""
80
  if not self.is_running():
81
  logger.info("Process is not running")
82
  return
@@ -87,5 +95,5 @@ class SubprocessManager:
87
  #return exit_code
88
 
89
  def is_running(self):
90
- """Check if the subprocess is still running."""
91
  return self.process and self.process.poll() is None
 
4
  import shutil
5
  from loguru import logger
6
  import subprocess
7
+ from typing import List
8
 
9
  UPLOAD_DIRECTORY = pathlib.Path("/app/uploaded_files")
10
  CONFIG_PATH = pathlib.Path("/app/yourbench_config.yml")
11
 
12
+ # Ensure the upload directory exists
13
+ UPLOAD_DIRECTORY.mkdir(parents=True, exist_ok=True)
 
 
 
14
 
15
+ def save_files(files: List[pathlib.Path]) -> str:
16
+ """Save uploaded files to the UPLOAD_DIRECTORY safely"""
17
+ saved_paths = []
 
 
18
 
19
+ for file in files:
20
+ try:
21
+ source_path = pathlib.Path(file)
22
+ destination_path = UPLOAD_DIRECTORY / source_path.name
23
 
24
+ if not source_path.exists():
25
+ print(f"File not found: {source_path}")
26
+ continue # Skip missing files
27
+
28
+ shutil.move(str(source_path), str(destination_path))
29
+ saved_paths.append(str(destination_path))
30
+
31
+ except Exception as e:
32
+ print(f"Error moving file {file}: {e}")
33
+
34
+ return f"Files saved to: {', '.join(saved_paths)}" if saved_paths else "No files were saved"
35
 
36
  class SubprocessManager:
37
  def __init__(self, command):
 
59
  logger.info("Started the process")
60
 
61
  def read_and_get_output(self):
62
+ """Read available subprocess output and return the captured output"""
63
  if self.process and self.process.stdout:
64
  try:
65
  while True:
 
84
  #return exit_code
85
 
86
  def kill_process(self):
87
+ """Forcefully kill the subprocess"""
88
  if not self.is_running():
89
  logger.info("Process is not running")
90
  return
 
95
  #return exit_code
96
 
97
  def is_running(self):
98
+ """Check if the subprocess is still running"""
99
  return self.process and self.process.poll() is None