victor-johnson commited on
Commit
8a32bb6
·
verified ·
1 Parent(s): 9a5392b

updare to app.py

Browse files
Files changed (1) hide show
  1. app.py +99 -139
app.py CHANGED
@@ -3,107 +3,84 @@ import gradio as gr
3
  import requests
4
  import inspect
5
  import pandas as pd
 
 
 
 
 
 
6
 
7
- # (Keep Constants as is)
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
10
 
11
- # --- Basic Agent Definition ---
12
- # ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
13
- # --- Enhanced Agent (replace the old BasicAgent with this) ---
14
- import re
15
- import json
16
- import textwrap
17
 
 
18
  class BasicAgent:
19
  """
20
- Calls a small LLM on the Hugging Face Inference API and post-processes the output
21
- to return a concise, exact-match-friendly answer.
22
- Reads HF API token from the HF Space secret HF_TOKEN.
23
  """
 
24
  def __init__(self):
25
- self.model_url = "https://api-inference.huggingface.co/models/HuggingFaceTB/SmolLM3-3B"
26
- self.headers = {
27
- "Authorization": f"Bearer {os.getenv('HF_TOKEN', '')}",
28
- "Content-Type": "application/json",
29
- }
30
- if not os.getenv("HF_TOKEN"):
31
- print("⚠️ HF_TOKEN not set — requests to the Inference API will fail.")
32
- print("🚀 Enhanced BasicAgent initialized.")
 
 
 
 
 
33
 
34
  def _clean(self, raw: str) -> str:
35
- """
36
- Post-process the model output to a short, exact value:
37
- - Keep only the final line after common prefixes.
38
- - Strip quotes/backticks and trailing punctuation.
39
- """
40
  txt = raw.strip()
41
-
42
- # If the model echoed the prompt, take the last line
43
  lines = [l.strip() for l in txt.splitlines() if l.strip()]
44
  if lines:
45
  txt = lines[-1]
46
-
47
- # Remove common prefixes
48
  txt = re.sub(r"^(final answer|answer|prediction)\s*[:\-]\s*", "", txt, flags=re.I)
49
-
50
- # Strip code fences/quotes and trailing punctuation
51
  txt = txt.strip("`'\" \t\n\r")
52
  txt = re.sub(r"[ \t]*[.;,:-]+$", "", txt)
53
-
54
- # Keep it short (exact match tasks usually want a short string/number)
55
  return txt[:200]
56
 
57
  def __call__(self, question: str) -> str:
58
  print(f"🧠 Agent received question: {question[:120]}...")
59
- # A very simple, direct prompt to reduce rambling
 
60
  prompt = textwrap.dedent(f"""
61
  You must answer the question with a single, concise value
62
- (number, word, date, short phrase) and nothing else.
63
-
64
  Question: {question}
65
  Final answer:
66
  """).strip()
67
 
68
- payload = {
69
- "inputs": prompt,
70
- "parameters": {
71
- "max_new_tokens": 96,
72
- "temperature": 0.2,
73
- "return_full_text": False,
74
- },
75
- "options": {"wait_for_model": True},
76
- }
77
 
78
- try:
79
- r = requests.post(self.model_url, headers=self.headers, data=json.dumps(payload), timeout=60)
80
- r.raise_for_status()
81
- data = r.json()
82
- # Inference API (text-generation) usually returns a list with "generated_text"
83
- if isinstance(data, list) and data and "generated_text" in data[0]:
84
- generated = data[0]["generated_text"]
85
- else:
86
- # Fallback: stringify whatever came back
87
- generated = str(data)
88
- answer = self._clean(generated)
89
- print(f"✅ Cleaned answer: {answer}")
90
- # Ensure we never submit an empty string (server rejects)
91
- return answer if answer else "N/A"
92
- except Exception as e:
93
- print(f"❌ Error generating answer: {e}")
94
- return "N/A"
95
 
96
 
97
- def run_and_submit_all( profile: gr.OAuthProfile | None):
 
98
  """
99
- Fetches all questions, runs the BasicAgent on them, submits all answers,
100
  and displays the results.
101
  """
102
- # --- Determine HF Space Runtime URL and Repo URL ---
103
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
104
 
105
  if profile:
106
- username= f"{profile.username}"
107
  print(f"User logged in: {username}")
108
  else:
109
  print("User not logged in.")
@@ -113,38 +90,35 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
113
  questions_url = f"{api_url}/questions"
114
  submit_url = f"{api_url}/submit"
115
 
116
- # 1. Instantiate Agent ( modify this part to create your agent)
117
  try:
118
  agent = BasicAgent()
119
  except Exception as e:
120
  print(f"Error instantiating agent: {e}")
121
  return f"Error initializing agent: {e}", None
122
- # In the case of an app running as a hugging Face space, this link points toward your codebase ( usefull for others so please keep it public)
123
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
124
  print(agent_code)
125
 
126
- # 2. Fetch Questions
127
  print(f"Fetching questions from: {questions_url}")
128
  try:
129
  response = requests.get(questions_url, timeout=15)
130
  response.raise_for_status()
131
  questions_data = response.json()
132
  if not questions_data:
133
- print("Fetched questions list is empty.")
134
- return "Fetched questions list is empty or invalid format.", None
135
  print(f"Fetched {len(questions_data)} questions.")
136
  except requests.exceptions.RequestException as e:
137
  print(f"Error fetching questions: {e}")
138
  return f"Error fetching questions: {e}", None
139
  except requests.exceptions.JSONDecodeError as e:
140
- print(f"Error decoding JSON response from questions endpoint: {e}")
141
- print(f"Response text: {response.text[:500]}")
142
- return f"Error decoding server response for questions: {e}", None
143
- except Exception as e:
144
- print(f"An unexpected error occurred fetching questions: {e}")
145
- return f"An unexpected error occurred fetching questions: {e}", None
146
 
147
- # 3. Run your Agent
148
  results_log = []
149
  answers_payload = []
150
  print(f"Running agent on {len(questions_data)} questions...")
@@ -156,22 +130,40 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
156
  continue
157
  try:
158
  submitted_answer = agent(question_text)
159
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
160
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
 
 
 
 
 
 
 
 
161
  except Exception as e:
162
- print(f"Error running agent on task {task_id}: {e}")
163
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
 
 
 
 
 
164
 
165
  if not answers_payload:
166
  print("Agent did not produce any answers to submit.")
167
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
168
 
169
- # 4. Prepare Submission
170
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
 
 
 
 
 
171
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
172
  print(status_update)
173
 
174
- # 5. Submit
175
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
176
  try:
177
  response = requests.post(submit_url, json=submission_data, timeout=60)
@@ -187,85 +179,53 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
187
  print("Submission successful.")
188
  results_df = pd.DataFrame(results_log)
189
  return final_status, results_df
190
- except requests.exceptions.HTTPError as e:
191
- error_detail = f"Server responded with status {e.response.status_code}."
192
- try:
193
- error_json = e.response.json()
194
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
195
- except requests.exceptions.JSONDecodeError:
196
- error_detail += f" Response: {e.response.text[:500]}"
197
- status_message = f"Submission Failed: {error_detail}"
198
- print(status_message)
199
- results_df = pd.DataFrame(results_log)
200
- return status_message, results_df
201
- except requests.exceptions.Timeout:
202
- status_message = "Submission Failed: The request timed out."
203
- print(status_message)
204
- results_df = pd.DataFrame(results_log)
205
- return status_message, results_df
206
- except requests.exceptions.RequestException as e:
207
- status_message = f"Submission Failed: Network error - {e}"
208
- print(status_message)
209
- results_df = pd.DataFrame(results_log)
210
- return status_message, results_df
211
  except Exception as e:
212
- status_message = f"An unexpected error occurred during submission: {e}"
213
  print(status_message)
214
  results_df = pd.DataFrame(results_log)
215
  return status_message, results_df
216
 
217
 
218
- # --- Build Gradio Interface using Blocks ---
219
  with gr.Blocks() as demo:
220
  gr.Markdown("# Basic Agent Evaluation Runner")
221
  gr.Markdown(
222
  """
223
  **Instructions:**
224
-
225
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
226
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
227
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
228
-
229
  ---
230
- **Disclaimers:**
231
- Once clicking on the "submit button, it can take quite some time ( this is the time for the agent to go through all the questions).
232
- This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance for the delay process of the submit button, a solution could be to cache the answers and submit in a seperate action or even to answer the questions in async.
233
  """
234
  )
235
 
236
  gr.LoginButton()
237
-
238
  run_button = gr.Button("Run Evaluation & Submit All Answers")
239
-
240
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
241
- # Removed max_rows=10 from DataFrame constructor
242
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
243
 
244
- run_button.click(
245
- fn=run_and_submit_all,
246
- outputs=[status_output, results_table]
247
- )
248
 
 
249
  if __name__ == "__main__":
250
- print("\n" + "-"*30 + " App Starting " + "-"*30)
251
- # Check for SPACE_HOST and SPACE_ID at startup for information
252
- space_host_startup = os.getenv("SPACE_HOST")
253
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
254
-
255
- if space_host_startup:
256
- print(f"✅ SPACE_HOST found: {space_host_startup}")
257
- print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
258
- else:
259
- print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
260
 
261
- if space_id_startup: # Print repo URLs if SPACE_ID is found
262
- print(f"✅ SPACE_ID found: {space_id_startup}")
263
- print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
264
- print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
265
  else:
266
- print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
267
 
268
- print("-"*(60 + len(" App Starting ")) + "\n")
 
 
 
 
 
269
 
 
270
  print("Launching Gradio Interface for Basic Agent Evaluation...")
271
- demo.launch(debug=True, share=False)
 
3
  import requests
4
  import inspect
5
  import pandas as pd
6
+ import re
7
+ import json
8
+ import textwrap
9
+ from transformers import AutoTokenizer, AutoModelForCausalLM
10
+ import torch
11
+
12
 
 
13
  # --- Constants ---
14
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
15
 
 
 
 
 
 
 
16
 
17
+ # --- Enhanced BasicAgent (local model version) ---
18
  class BasicAgent:
19
  """
20
+ Loads and runs a small LLM *locally* inside the Hugging Face Space
21
+ instead of calling the Hugging Face Inference API (which is blocked).
 
22
  """
23
+
24
  def __init__(self):
25
+ # Small model to fit free Spaces — change to another instruct model if needed
26
+ model_id = "HuggingFaceTB/SmolLM3-1.7B"
27
+ print(f"🚀 Loading model locally: {model_id}")
28
+
29
+ # Load tokenizer and model
30
+ self.tokenizer = AutoTokenizer.from_pretrained(model_id)
31
+ self.model = AutoModelForCausalLM.from_pretrained(
32
+ model_id,
33
+ torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
34
+ device_map="auto",
35
+ )
36
+
37
+ print("✅ Local model ready.")
38
 
39
  def _clean(self, raw: str) -> str:
40
+ """Post-process the model output to a short, exact value."""
 
 
 
 
41
  txt = raw.strip()
 
 
42
  lines = [l.strip() for l in txt.splitlines() if l.strip()]
43
  if lines:
44
  txt = lines[-1]
 
 
45
  txt = re.sub(r"^(final answer|answer|prediction)\s*[:\-]\s*", "", txt, flags=re.I)
 
 
46
  txt = txt.strip("`'\" \t\n\r")
47
  txt = re.sub(r"[ \t]*[.;,:-]+$", "", txt)
 
 
48
  return txt[:200]
49
 
50
  def __call__(self, question: str) -> str:
51
  print(f"🧠 Agent received question: {question[:120]}...")
52
+
53
+ # Simple concise prompt
54
  prompt = textwrap.dedent(f"""
55
  You must answer the question with a single, concise value
56
+ (number, word, date, or short phrase) and nothing else.
 
57
  Question: {question}
58
  Final answer:
59
  """).strip()
60
 
61
+ inputs = self.tokenizer(prompt, return_tensors="pt").to(self.model.device)
62
+ outputs = self.model.generate(
63
+ **inputs, max_new_tokens=96, temperature=0.2, do_sample=True
64
+ )
 
 
 
 
 
65
 
66
+ text = self.tokenizer.decode(
67
+ outputs[0][inputs["input_ids"].shape[-1]:], skip_special_tokens=True
68
+ )
69
+ answer = self._clean(text)
70
+ print(f"✅ Cleaned answer: {answer}")
71
+ return answer or "N/A"
 
 
 
 
 
 
 
 
 
 
 
72
 
73
 
74
+ # --- Evaluation Runner ---
75
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
76
  """
77
+ Fetches all questions, runs the BasicAgent locally, submits answers,
78
  and displays the results.
79
  """
80
+ space_id = os.getenv("SPACE_ID")
 
81
 
82
  if profile:
83
+ username = f"{profile.username}"
84
  print(f"User logged in: {username}")
85
  else:
86
  print("User not logged in.")
 
90
  questions_url = f"{api_url}/questions"
91
  submit_url = f"{api_url}/submit"
92
 
93
+ # --- Instantiate Agent ---
94
  try:
95
  agent = BasicAgent()
96
  except Exception as e:
97
  print(f"Error instantiating agent: {e}")
98
  return f"Error initializing agent: {e}", None
99
+
100
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
101
  print(agent_code)
102
 
103
+ # --- Fetch Questions ---
104
  print(f"Fetching questions from: {questions_url}")
105
  try:
106
  response = requests.get(questions_url, timeout=15)
107
  response.raise_for_status()
108
  questions_data = response.json()
109
  if not questions_data:
110
+ print("Fetched questions list is empty.")
111
+ return "Fetched questions list is empty or invalid format.", None
112
  print(f"Fetched {len(questions_data)} questions.")
113
  except requests.exceptions.RequestException as e:
114
  print(f"Error fetching questions: {e}")
115
  return f"Error fetching questions: {e}", None
116
  except requests.exceptions.JSONDecodeError as e:
117
+ print(f"Error decoding JSON response from questions endpoint: {e}")
118
+ print(f"Response text: {response.text[:500]}")
119
+ return f"Error decoding server response for questions: {e}", None
 
 
 
120
 
121
+ # --- Run Agent ---
122
  results_log = []
123
  answers_payload = []
124
  print(f"Running agent on {len(questions_data)} questions...")
 
130
  continue
131
  try:
132
  submitted_answer = agent(question_text)
133
+ answers_payload.append(
134
+ {"task_id": task_id, "submitted_answer": submitted_answer}
135
+ )
136
+ results_log.append(
137
+ {
138
+ "Task ID": task_id,
139
+ "Question": question_text,
140
+ "Submitted Answer": submitted_answer,
141
+ }
142
+ )
143
  except Exception as e:
144
+ print(f"Error running agent on task {task_id}: {e}")
145
+ results_log.append(
146
+ {
147
+ "Task ID": task_id,
148
+ "Question": question_text,
149
+ "Submitted Answer": f"AGENT ERROR: {e}",
150
+ }
151
+ )
152
 
153
  if not answers_payload:
154
  print("Agent did not produce any answers to submit.")
155
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
156
 
157
+ # --- Submit ---
158
+ submission_data = {
159
+ "username": username.strip(),
160
+ "agent_code": agent_code,
161
+ "answers": answers_payload,
162
+ }
163
+
164
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
165
  print(status_update)
166
 
 
167
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
168
  try:
169
  response = requests.post(submit_url, json=submission_data, timeout=60)
 
179
  print("Submission successful.")
180
  results_df = pd.DataFrame(results_log)
181
  return final_status, results_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  except Exception as e:
183
+ status_message = f"Submission Failed: {e}"
184
  print(status_message)
185
  results_df = pd.DataFrame(results_log)
186
  return status_message, results_df
187
 
188
 
189
+ # --- Gradio Interface ---
190
  with gr.Blocks() as demo:
191
  gr.Markdown("# Basic Agent Evaluation Runner")
192
  gr.Markdown(
193
  """
194
  **Instructions:**
195
+ 1. Log in to your Hugging Face account.
196
+ 2. Click 'Run Evaluation & Submit All Answers'.
 
 
 
197
  ---
198
+ The agent now runs *locally* inside the Space instead of using the API.
 
 
199
  """
200
  )
201
 
202
  gr.LoginButton()
 
203
  run_button = gr.Button("Run Evaluation & Submit All Answers")
 
204
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
205
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
206
 
207
+ run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
208
+
 
 
209
 
210
+ # --- Launch ---
211
  if __name__ == "__main__":
212
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
213
+ space_host = os.getenv("SPACE_HOST")
214
+ space_id = os.getenv("SPACE_ID")
 
 
 
 
 
 
 
215
 
216
+ if space_host:
217
+ print(f"✅ SPACE_HOST found: {space_host}")
218
+ print(f" Runtime URL should be: https://{space_host}.hf.space")
 
219
  else:
220
+ print("ℹ️ SPACE_HOST not found (running locally?).")
221
 
222
+ if space_id:
223
+ print(f"✅ SPACE_ID found: {space_id}")
224
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id}")
225
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id}/tree/main")
226
+ else:
227
+ print("ℹ️ SPACE_ID not found (running locally?).")
228
 
229
+ print("-" * (60 + len(" App Starting ")) + "\n")
230
  print("Launching Gradio Interface for Basic Agent Evaluation...")
231
+ demo.launch(debug=True, share=False)