mhattingpete commited on
Commit
be75c32
·
1 Parent(s): 0e32f4e

reverted app.py to original

Browse files
Files changed (1) hide show
  1. app.py +145 -156
app.py CHANGED
@@ -1,204 +1,193 @@
1
- import asyncio
2
- import json
3
  import os
4
- from pathlib import Path
5
 
6
- import aiohttp
7
  import gradio as gr
8
  import pandas as pd
 
9
 
10
  from agent import Agent
 
11
 
12
- # --- Constants --------------------------------------------------------------
13
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
14
- CACHE_PATH = Path("answers_cache.json") # local answer cache
15
- MAX_CONCURRENCY = int(os.getenv("MAX_CONCURRENCY", 8)) # tune if needed
16
- # ----------------------------------------------------------------------------
17
-
18
-
19
- # ---------------------------------------------------------------------------
20
- # Small helpers
21
- # ---------------------------------------------------------------------------
22
- def load_cache() -> dict[str, str]:
23
- if CACHE_PATH.is_file():
24
- try:
25
- return json.loads(CACHE_PATH.read_text())
26
- except Exception:
27
- print("⚠️ Cache file corrupt – starting fresh.")
28
- return {}
29
-
30
-
31
- def save_cache(cache: dict[str, str]) -> None:
32
- tmp = CACHE_PATH.with_suffix(".tmp")
33
- tmp.write_text(json.dumps(cache, ensure_ascii=False, indent=2))
34
- tmp.replace(CACHE_PATH)
35
-
36
-
37
- # ---------------------------------------------------------------------------
38
- # Core async logic
39
- # ---------------------------------------------------------------------------
40
- async def _fetch_questions(
41
- session: aiohttp.ClientSession, url: str
42
- ) -> list[dict]:
43
- async with session.get(url, timeout=15) as r:
44
- r.raise_for_status()
45
- return await r.json()
46
-
47
-
48
- async def _submit_answers(session: aiohttp.ClientSession, url: str, data: dict):
49
- async with session.post(url, json=data, timeout=60) as r:
50
- r.raise_for_status()
51
- return await r.json()
52
-
53
-
54
- def _run_agent_sync(
55
- agent: Agent,
56
- question: str,
57
- task_id: str | int,
58
- file_name: str,
59
- cache: dict[str, str],
60
- ) -> tuple[str | int, str]:
61
- """
62
- Run the agent in a threadpool (because most agents are sync / blocking),
63
- respecting concurrency limits, and fill the cache.
64
- """
65
- if str(task_id) in cache:
66
- return task_id, cache[str(task_id)]
67
 
68
- answer = agent(
69
- question, task_id, file_name, DEFAULT_API_URL
70
- ) # execute in default thread‑pool
71
- cache[str(task_id)] = answer
72
- return task_id, answer
73
 
74
 
75
- async def _async_main(profile: gr.OAuthProfile | None):
76
  """
77
- Async counterpart of run_and_submit_all; returns (status_msg, results_df)
 
78
  """
79
- if not profile:
80
- return "Please login with the Hugging Face button.", None
81
-
82
- username = profile.username
83
- space_id = os.getenv("SPACE_ID")
84
- agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
 
 
 
 
 
85
 
86
  api_url = DEFAULT_API_URL
87
  questions_url = f"{api_url}/questions"
88
  submit_url = f"{api_url}/submit"
89
 
90
- # 1. Build agent (sync, cheap)
91
  try:
92
  agent = Agent()
93
  except Exception as e:
 
94
  return f"Error initializing agent: {e}", None
 
 
 
95
 
96
- # 2. Fetch questions
97
- async with aiohttp.ClientSession() as session:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  try:
99
- questions = await _fetch_questions(session, questions_url)
100
- except Exception as e:
101
- return f"Error fetching questions: {e}", None
102
-
103
- if not questions:
104
- return "Fetched questions list is empty.", None
105
-
106
- # 3. Run agent with cache
107
- cache = load_cache()
108
- results = [
109
- _run_agent_sync(
110
- agent, q["question"], q["task_id"], q["file_name"], cache
111
  )
112
- for q in questions
113
- if q.get("task_id") and q.get("question") is not None
114
- ]
115
-
116
- results_log: list[dict] = []
117
- answers_json: list[dict] = []
118
-
119
- for task_id, answer in results:
120
- answers_json.append(
121
- {"task_id": task_id, "submitted_answer": answer}
122
  )
 
 
123
  results_log.append(
124
  {
125
  "Task ID": task_id,
126
- "Question": next(
127
- (
128
- q["question"]
129
- for q in questions
130
- if q["task_id"] == task_id
131
- ),
132
- "",
133
- ),
134
- "Submitted Answer": answer,
135
  }
136
  )
137
 
138
- # 3b. Persist cache for later runs
139
- save_cache(cache)
140
-
141
- if not answers_json:
142
- return "Agent produced no answers.", pd.DataFrame(results_log)
143
 
144
- # 4. Submit
145
- submission = {
146
- "username": username.strip(),
147
- "agent_code": agent_code,
148
- "answers": answers_json,
149
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  try:
151
- result = await _submit_answers(session, submit_url, submission)
152
- except Exception as e:
153
- status = f"Submission failed: {e}"
154
- return status, pd.DataFrame(results_log)
155
-
156
- # Format success message
157
- final = (
158
- "Submission Successful!\n"
159
- f"User: {result.get('username')}\n"
160
- f"Overall Score: {result.get('score', 'N/A')}% "
161
- f"({result.get('correct_count', '?')}/{result.get('total_attempted', '?')} correct)\n"
162
- f"Message: {result.get('message', 'No message received.')}"
163
- )
164
- return final, pd.DataFrame(results_log)
165
-
166
-
167
- # ---------------------------------------------------------------------------
168
- # Thin sync wrapper required by gradio
169
- # ---------------------------------------------------------------------------
170
- def run_and_submit_all(profile: gr.OAuthProfile | None):
171
- """
172
- Synchronous façade expected by Gradio; just dispatches to asyncio.
173
- """
174
- return asyncio.run(_async_main(profile))
 
175
 
176
 
177
- # ---------------------------------------------------------------------------
178
- # Gradio UI (unchanged except for doc‑string tweaks)
179
- # ---------------------------------------------------------------------------
180
  with gr.Blocks() as demo:
181
- gr.Markdown("# Async‑cached Agent Evaluation Runner")
182
-
183
  gr.Markdown(
184
  """
185
- **Quick‑start**
 
 
 
186
 
187
- 1. Log in with the HF button (needed for ranking).
188
- 2. Hit **Run Evaluation & Submit All Answers** – answers are cached
189
- locally so reruns are instant; agent calls & HTTP are parallel.
 
190
  """
191
  )
192
 
193
  gr.LoginButton()
194
 
195
- run_btn = gr.Button("Run Evaluation & Submit All Answers")
196
- status_box = gr.Textbox(label="Status / Submission Result", lines=5)
197
- results_table = gr.DataFrame(label="Questions & Answers", wrap=True)
 
 
 
 
198
 
199
- run_btn.click(
200
- fn=run_and_submit_all,
201
- outputs=[status_box, results_table],
202
  )
203
 
204
  if __name__ == "__main__":
 
 
 
1
  import os
 
2
 
 
3
  import gradio as gr
4
  import pandas as pd
5
+ import requests
6
 
7
  from agent import Agent
8
+ from src.tracing import add_tracing
9
 
10
+ add_tracing()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ # (Keep Constants as is)
13
+ # --- Constants ---
14
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
 
 
15
 
16
 
17
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
18
  """
19
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
20
+ and displays the results.
21
  """
22
+ # --- Determine HF Space Runtime URL and Repo URL ---
23
+ space_id = os.getenv(
24
+ "SPACE_ID"
25
+ ) # Get the SPACE_ID for sending link to the code
26
+
27
+ if profile:
28
+ username = f"{profile.username}"
29
+ print(f"User logged in: {username}")
30
+ else:
31
+ print("User not logged in.")
32
+ return "Please Login to Hugging Face with the button.", None
33
 
34
  api_url = DEFAULT_API_URL
35
  questions_url = f"{api_url}/questions"
36
  submit_url = f"{api_url}/submit"
37
 
38
+ # 1. Instantiate Agent ( modify this part to create your agent)
39
  try:
40
  agent = Agent()
41
  except Exception as e:
42
+ print(f"Error instantiating agent: {e}")
43
  return f"Error initializing agent: {e}", None
44
+ # 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)
45
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
46
+ print(agent_code)
47
 
48
+ # 2. Fetch Questions
49
+ print(f"Fetching questions from: {questions_url}")
50
+ try:
51
+ response = requests.get(questions_url, timeout=15)
52
+ response.raise_for_status()
53
+ questions_data = response.json()
54
+ if not questions_data:
55
+ print("Fetched questions list is empty.")
56
+ return "Fetched questions list is empty or invalid format.", None
57
+ print(f"Fetched {len(questions_data)} questions.")
58
+ except requests.exceptions.RequestException as e:
59
+ print(f"Error fetching questions: {e}")
60
+ return f"Error fetching questions: {e}", None
61
+ except requests.exceptions.JSONDecodeError as e:
62
+ print(f"Error decoding JSON response from questions endpoint: {e}")
63
+ print(f"Response text: {response.text[:500]}")
64
+ return f"Error decoding server response for questions: {e}", None
65
+ except Exception as e:
66
+ print(f"An unexpected error occurred fetching questions: {e}")
67
+ return f"An unexpected error occurred fetching questions: {e}", None
68
+
69
+ # 3. Run your Agent
70
+ results_log = []
71
+ answers_payload = []
72
+ print(f"Running agent on {len(questions_data)} questions...")
73
+ for item in questions_data:
74
+ task_id = item.get("task_id")
75
+ question_text = item.get("question")
76
+ if not task_id or question_text is None:
77
+ print(f"Skipping item with missing task_id or question: {item}")
78
+ continue
79
  try:
80
+ submitted_answer = agent(question_text)
81
+ answers_payload.append(
82
+ {"task_id": task_id, "submitted_answer": submitted_answer}
 
 
 
 
 
 
 
 
 
83
  )
84
+ results_log.append(
85
+ {
86
+ "Task ID": task_id,
87
+ "Question": question_text,
88
+ "Submitted Answer": submitted_answer,
89
+ }
 
 
 
 
90
  )
91
+ except Exception as e:
92
+ print(f"Error running agent on task {task_id}: {e}")
93
  results_log.append(
94
  {
95
  "Task ID": task_id,
96
+ "Question": question_text,
97
+ "Submitted Answer": f"AGENT ERROR: {e}",
 
 
 
 
 
 
 
98
  }
99
  )
100
 
101
+ if not answers_payload:
102
+ print("Agent did not produce any answers to submit.")
103
+ return "Agent did not produce any answers to submit.", pd.DataFrame(
104
+ results_log
105
+ )
106
 
107
+ # 4. Prepare Submission
108
+ submission_data = {
109
+ "username": username.strip(),
110
+ "agent_code": agent_code,
111
+ "answers": answers_payload,
112
+ }
113
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
114
+ print(status_update)
115
+
116
+ # 5. Submit
117
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
118
+ try:
119
+ response = requests.post(submit_url, json=submission_data, timeout=60)
120
+ response.raise_for_status()
121
+ result_data = response.json()
122
+ final_status = (
123
+ f"Submission Successful!\n"
124
+ f"User: {result_data.get('username')}\n"
125
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
126
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
127
+ f"Message: {result_data.get('message', 'No message received.')}"
128
+ )
129
+ print("Submission successful.")
130
+ results_df = pd.DataFrame(results_log)
131
+ return final_status, results_df
132
+ except requests.exceptions.HTTPError as e:
133
+ error_detail = f"Server responded with status {e.response.status_code}."
134
  try:
135
+ error_json = e.response.json()
136
+ error_detail += (
137
+ f" Detail: {error_json.get('detail', e.response.text)}"
138
+ )
139
+ except requests.exceptions.JSONDecodeError:
140
+ error_detail += f" Response: {e.response.text[:500]}"
141
+ status_message = f"Submission Failed: {error_detail}"
142
+ print(status_message)
143
+ results_df = pd.DataFrame(results_log)
144
+ return status_message, results_df
145
+ except requests.exceptions.Timeout:
146
+ status_message = "Submission Failed: The request timed out."
147
+ print(status_message)
148
+ results_df = pd.DataFrame(results_log)
149
+ return status_message, results_df
150
+ except requests.exceptions.RequestException as e:
151
+ status_message = f"Submission Failed: Network error - {e}"
152
+ print(status_message)
153
+ results_df = pd.DataFrame(results_log)
154
+ return status_message, results_df
155
+ except Exception as e:
156
+ status_message = f"An unexpected error occurred during submission: {e}"
157
+ print(status_message)
158
+ results_df = pd.DataFrame(results_log)
159
+ return status_message, results_df
160
 
161
 
162
+ # --- Build Gradio Interface using Blocks ---
 
 
163
  with gr.Blocks() as demo:
164
+ gr.Markdown("# Basic Agent Evaluation Runner")
 
165
  gr.Markdown(
166
  """
167
+ **Instructions:**
168
+
169
+ 1. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
170
+ 2. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
171
 
172
+ ---
173
+ **Disclaimers:**
174
+ 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).
175
+ 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.
176
  """
177
  )
178
 
179
  gr.LoginButton()
180
 
181
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
182
+
183
+ status_output = gr.Textbox(
184
+ label="Run Status / Submission Result", lines=5, interactive=False
185
+ )
186
+ # Removed max_rows=10 from DataFrame constructor
187
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
188
 
189
+ run_button.click(
190
+ fn=run_and_submit_all, outputs=[status_output, results_table]
 
191
  )
192
 
193
  if __name__ == "__main__":