SergeyO7 commited on
Commit
417b294
·
verified ·
1 Parent(s): 4c0b1a1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +169 -76
app.py CHANGED
@@ -1,34 +1,113 @@
 
1
  import os
2
  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
- class BasicAgent:
14
- def __init__(self):
15
- print("BasicAgent initialized.")
16
- def __call__(self, question: str) -> str:
17
- print(f"Agent received question (first 50 chars): {question[:50]}...")
18
- fixed_answer = "This is a default answer."
19
- print(f"Agent returning fixed answer: {fixed_answer}")
20
- return fixed_answer
21
-
22
- def run_and_submit_all( profile: gr.OAuthProfile | None):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  """
24
- Fetches all questions, runs the BasicAgent on them, submits all answers,
25
  and displays the results.
26
  """
27
  # --- Determine HF Space Runtime URL and Repo URL ---
28
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
29
 
30
  if profile:
31
- username= f"{profile.username}"
32
  print(f"User logged in: {username}")
33
  else:
34
  print("User not logged in.")
@@ -38,60 +117,80 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
38
  questions_url = f"{api_url}/questions"
39
  submit_url = f"{api_url}/submit"
40
 
41
- # 1. Instantiate Agent ( modify this part to create your agent)
42
  try:
43
- agent = BasicAgent()
44
  except Exception as e:
45
  print(f"Error instantiating agent: {e}")
46
  return f"Error initializing agent: {e}", None
47
- # 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)
48
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
49
  print(agent_code)
50
 
51
- # 2. Fetch Questions
52
- print(f"Fetching questions from: {questions_url}")
53
- try:
54
- response = requests.get(questions_url, timeout=15)
55
- response.raise_for_status()
56
- questions_data = response.json()
57
- if not questions_data:
58
- print("Fetched questions list is empty.")
59
- return "Fetched questions list is empty or invalid format.", None
60
- print(f"Fetched {len(questions_data)} questions.")
61
- except requests.exceptions.RequestException as e:
62
- print(f"Error fetching questions: {e}")
63
- return f"Error fetching questions: {e}", None
64
- except requests.exceptions.JSONDecodeError as e:
65
- print(f"Error decoding JSON response from questions endpoint: {e}")
66
- print(f"Response text: {response.text[:500]}")
67
- return f"Error decoding server response for questions: {e}", None
68
- except Exception as e:
69
- print(f"An unexpected error occurred fetching questions: {e}")
70
- return f"An unexpected error occurred fetching questions: {e}", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
- # 3. Run your Agent
73
  results_log = []
74
  answers_payload = []
75
- print(f"Running agent on {len(questions_data)} questions...")
76
- for item in questions_data:
77
- task_id = item.get("task_id")
78
- question_text = item.get("question")
79
- if not task_id or question_text is None:
80
- print(f"Skipping item with missing task_id or question: {item}")
81
- continue
82
- try:
83
- submitted_answer = agent(question_text)
 
 
 
 
84
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
85
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
86
- except Exception as e:
87
- print(f"Error running agent on task {task_id}: {e}")
88
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
 
89
 
90
  if not answers_payload:
91
  print("Agent did not produce any answers to submit.")
92
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
93
 
94
- # 4. Prepare Submission
95
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
96
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
97
  print(status_update)
@@ -99,14 +198,15 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
99
  # 5. Submit
100
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
101
  try:
102
- response = requests.post(submit_url, json=submission_data, timeout=60)
 
103
  response.raise_for_status()
104
  result_data = response.json()
105
  final_status = (
106
  f"Submission Successful!\n"
107
  f"User: {result_data.get('username')}\n"
108
  f"Overall Score: {result_data.get('score', 'N/A')}% "
109
- f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
110
  f"Message: {result_data.get('message', 'No message received.')}"
111
  )
112
  print("Submission successful.")
@@ -139,31 +239,25 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
139
  results_df = pd.DataFrame(results_log)
140
  return status_message, results_df
141
 
142
-
143
  # --- Build Gradio Interface using Blocks ---
144
  with gr.Blocks() as demo:
145
- gr.Markdown("# Basic Agent Evaluation Runner")
146
  gr.Markdown(
147
  """
148
  **Instructions:**
149
-
150
- 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
151
- 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
152
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
153
-
154
  ---
155
  **Disclaimers:**
156
- 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).
157
- 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.
158
  """
159
  )
160
 
161
  gr.LoginButton()
162
-
163
  run_button = gr.Button("Run Evaluation & Submit All Answers")
164
-
165
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
166
- # Removed max_rows=10 from DataFrame constructor
167
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
168
 
169
  run_button.click(
@@ -173,9 +267,8 @@ with gr.Blocks() as demo:
173
 
174
  if __name__ == "__main__":
175
  print("\n" + "-"*30 + " App Starting " + "-"*30)
176
- # Check for SPACE_HOST and SPACE_ID at startup for information
177
  space_host_startup = os.getenv("SPACE_HOST")
178
- space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
179
 
180
  if space_host_startup:
181
  print(f"✅ SPACE_HOST found: {space_host_startup}")
@@ -183,14 +276,14 @@ if __name__ == "__main__":
183
  else:
184
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
185
 
186
- if space_id_startup: # Print repo URLs if SPACE_ID is found
187
  print(f"✅ SPACE_ID found: {space_id_startup}")
188
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
189
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
190
  else:
191
- print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
192
 
193
  print("-"*(60 + len(" App Starting ")) + "\n")
194
-
195
- print("Launching Gradio Interface for Basic Agent Evaluation...")
196
- demo.launch(debug=True, share=False)
 
1
+ ```python
2
  import os
3
  import gradio as gr
4
  import requests
 
5
  import pandas as pd
6
+ import json
7
+ import time
8
+ import asyncio
9
+ from concurrent.futures import ThreadPoolExecutor
10
+ from pathlib import Path
11
+ from langchain_core.messages import HumanMessage
12
+ from requests.adapters import HTTPAdapter
13
+ from urllib3.util.retry import Retry
14
+ from agent import AdvancedAgent
15
 
 
16
  # --- Constants ---
17
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
18
+ CACHE_FILE = "questions_cache.json"
19
+ CACHE_EXPIRATION_SECONDS = 86400 # 1 day
20
+ MAX_RETRIES = 3
21
+ INITIAL_BACKOFF = 2 # seconds
22
 
23
+ def create_retry_session():
24
+ """Create a requests session with retry logic for handling 429 errors."""
25
+ session = requests.Session()
26
+ retries = Retry(
27
+ total=MAX_RETRIES,
28
+ backoff_factor=INITIAL_BACKOFF,
29
+ status_forcelist=[429],
30
+ allowed_methods=["GET", "POST"]
31
+ )
32
+ adapter = HTTPAdapter(max_retries=retries)
33
+ session.mount("http://", adapter)
34
+ session.mount("https://", adapter)
35
+ return session
36
+
37
+ def load_cached_questions():
38
+ """Load cached questions if the cache is still valid."""
39
+ cache_path = Path(CACHE_FILE)
40
+ if cache_path.exists():
41
+ try:
42
+ with cache_path.open('r') as f:
43
+ data = json.load(f)
44
+ cached_time = data.get("timestamp")
45
+ if cached_time and (time.time() - cached_time) < CACHE_EXPIRATION_SECONDS:
46
+ questions = [
47
+ {
48
+ "task_id": item["task_id"],
49
+ "question": HumanMessage(content=item["question"])
50
+ }
51
+ for item in data["questions"]
52
+ ]
53
+ print(f"Loaded {len(questions)} questions from cache.")
54
+ return questions
55
+ else:
56
+ print("Cache expired.")
57
+ except Exception as e:
58
+ print(f"Error loading cached questions: {e}")
59
+ return None
60
+
61
+ def cache_questions(questions_data):
62
+ """Cache questions with a timestamp."""
63
+ cache_path = Path(CACHE_FILE)
64
+ try:
65
+ cache_data = {
66
+ "timestamp": time.time(),
67
+ "questions": [
68
+ {
69
+ "task_id": item["task_id"],
70
+ "question": item["question"].content
71
+ }
72
+ for item in questions_data
73
+ ]
74
+ }
75
+ with cache_path.open('w') as f:
76
+ json.dump(cache_data, f, indent=2)
77
+ print(f"Cached {len(questions_data)} questions to {CACHE_FILE}.")
78
+ except Exception as e:
79
+ print(f"Error caching questions: {e}")
80
+
81
+ async def process_question(agent, item):
82
+ """Process a single question using the agent."""
83
+ task_id = item["task_id"]
84
+ question = item["question"]
85
+ try:
86
+ loop = asyncio.get_event_loop()
87
+ submitted_answer = await loop.run_in_executor(None, agent, question.content)
88
+ return {
89
+ "task_id": task_id,
90
+ "submitted_answer": submitted_answer,
91
+ "question_text": question.content
92
+ }
93
+ except Exception as e:
94
+ print(f"Error processing task {task_id}: {e}")
95
+ return {
96
+ "task_id": task_id,
97
+ "submitted_answer": f"AGENT ERROR: {e}",
98
+ "question_text": question.content
99
+ }
100
+
101
+ async def run_and_submit_all(profile: gr.OAuthProfile | None):
102
  """
103
+ Fetches all questions, runs the AdvancedAgent on them, submits all answers,
104
  and displays the results.
105
  """
106
  # --- Determine HF Space Runtime URL and Repo URL ---
107
+ space_id = os.getenv("SPACE_ID")
108
 
109
  if profile:
110
+ username = f"{profile.username}"
111
  print(f"User logged in: {username}")
112
  else:
113
  print("User not logged in.")
 
117
  questions_url = f"{api_url}/questions"
118
  submit_url = f"{api_url}/submit"
119
 
120
+ # 1. Instantiate Agent
121
  try:
122
+ agent = AdvancedAgent()
123
  except Exception as e:
124
  print(f"Error instantiating agent: {e}")
125
  return f"Error initializing agent: {e}", None
126
+
127
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
128
  print(agent_code)
129
 
130
+ # 2. Fetch or Load Questions
131
+ questions_data = load_cached_questions()
132
+ if questions_data is None:
133
+ print(f"Fetching questions from: {questions_url}")
134
+ try:
135
+ session = create_retry_session()
136
+ response = session.get(questions_url, timeout=15)
137
+ response.raise_for_status()
138
+ raw_questions = response.json()
139
+ if not raw_questions:
140
+ print("Fetched questions list is empty.")
141
+ return "Fetched questions list is empty or invalid format.", None
142
+ questions_data = [
143
+ {
144
+ "task_id": item["task_id"],
145
+ "question": HumanMessage(content=item["question"])
146
+ }
147
+ for item in raw_questions
148
+ ]
149
+ print(f"Fetched {len(questions_data)} questions.")
150
+ cache_questions(questions_data)
151
+ except requests.exceptions.RequestException as e:
152
+ print(f"Error fetching questions: {e}")
153
+ # Fallback to cache even if expired
154
+ questions_data = load_cached_questions()
155
+ if questions_data:
156
+ print("Using expired cache due to API failure.")
157
+ else:
158
+ return f"Error fetching questions and no valid cache: {e}", None
159
+ except requests.exceptions.JSONDecodeError as e:
160
+ print(f"Error decoding JSON response: {e}")
161
+ return f"Error decoding server response: {e}", None
162
+ except Exception as e:
163
+ print(f"An unexpected error occurred fetching questions: {e}")
164
+ return f"An unexpected error occurred: {e}", None
165
 
166
+ # 3. Run Agent Asynchronously
167
  results_log = []
168
  answers_payload = []
169
+ print(f"Running agent on {len(questions_data)} questions asynchronously...")
170
+
171
+ with ThreadPoolExecutor(max_workers=5) as executor:
172
+ tasks = [process_question(agent, item) for item in questions_data]
173
+ responses = await asyncio.gather(*tasks, return_exceptions=True)
174
+
175
+ for response in responses:
176
+ if isinstance(response, Exception):
177
+ print(f"Unexpected error in async processing: {response}")
178
+ continue
179
+ task_id = response["task_id"]
180
+ submitted_answer = response["submitted_answer"]
181
+ question_text = response["question_text"]
182
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
183
+ results_log.append({
184
+ "Task ID": task_id,
185
+ "Question": question_text,
186
+ "Submitted Answer": submitted_answer
187
+ })
188
 
189
  if not answers_payload:
190
  print("Agent did not produce any answers to submit.")
191
  return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
192
 
193
+ # 4. Prepare Submission
194
  submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
195
  status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
196
  print(status_update)
 
198
  # 5. Submit
199
  print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
200
  try:
201
+ session = create_retry_session()
202
+ response = session.post(submit_url, json=submission_data, timeout=60)
203
  response.raise_for_status()
204
  result_data = response.json()
205
  final_status = (
206
  f"Submission Successful!\n"
207
  f"User: {result_data.get('username')}\n"
208
  f"Overall Score: {result_data.get('score', 'N/A')}% "
209
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?']} correct)\n"
210
  f"Message: {result_data.get('message', 'No message received.')}"
211
  )
212
  print("Submission successful.")
 
239
  results_df = pd.DataFrame(results_log)
240
  return status_message, results_df
241
 
 
242
  # --- Build Gradio Interface using Blocks ---
243
  with gr.Blocks() as demo:
244
+ gr.Markdown("# Advanced Agent Evaluation Runner")
245
  gr.Markdown(
246
  """
247
  **Instructions:**
248
+ 1. Modify the `agent.py` to define your agent's logic, tools, and packages.
249
+ 2. Log in to your Hugging Face account using the button below.
250
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
 
 
251
  ---
252
  **Disclaimers:**
253
+ The submission process may take time due to the number of questions.
254
+ Questions are cached locally to reduce API calls.
255
  """
256
  )
257
 
258
  gr.LoginButton()
 
259
  run_button = gr.Button("Run Evaluation & Submit All Answers")
 
260
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
261
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
262
 
263
  run_button.click(
 
267
 
268
  if __name__ == "__main__":
269
  print("\n" + "-"*30 + " App Starting " + "-"*30)
 
270
  space_host_startup = os.getenv("SPACE_HOST")
271
+ space_id_startup = os.getenv("SPACE_ID")
272
 
273
  if space_host_startup:
274
  print(f"✅ SPACE_HOST found: {space_host_startup}")
 
276
  else:
277
  print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
278
 
279
+ if space_id_startup:
280
  print(f"✅ SPACE_ID found: {space_id_startup}")
281
  print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
282
  print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
283
  else:
284
+ print("ℹ️ SPACE_ID environment variable not found (running locally?).")
285
 
286
  print("-"*(60 + len(" App Starting ")) + "\n")
287
+ print("Launching Gradio Interface for Advanced Agent Evaluation...")
288
+ demo.launch(debug=True, share=False)
289
+ ```