Humanlearning commited on
Commit
d0f9059
·
1 Parent(s): f4fba99

+ async answer generation

Browse files
Files changed (1) hide show
  1. app.py +87 -95
app.py CHANGED
@@ -4,6 +4,8 @@ import requests
4
  import inspect
5
  import pandas as pd
6
  from agents import LlamaIndexAgent
 
 
7
  # (Keep Constants as is)
8
  # --- Constants ---
9
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
@@ -14,91 +16,95 @@ class BasicAgent:
14
  def __init__(self):
15
  self.agent = LlamaIndexAgent()
16
  print("BasicAgent initialized.")
17
- def __call__(self, question: str) -> str:
18
  print(f"Agent received question (first 50 chars): {question[:50]}...")
19
- response = self.agent.run_query(question)
20
  print(f"Agent returning fixed answer: {response}")
21
  return response
22
 
23
- def run_and_submit_all( profile: gr.OAuthProfile | None):
 
 
 
 
 
24
  """
25
- Fetches all questions, runs the BasicAgent on them, submits all answers,
26
- and displays the results.
27
  """
28
- # --- Determine HF Space Runtime URL and Repo URL ---
29
- space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
30
-
31
  if profile:
32
- username= f"{profile.username}"
33
  print(f"User logged in: {username}")
34
  else:
35
  print("User not logged in.")
36
- return "Please Login to Hugging Face with the button.", None
37
-
38
  api_url = DEFAULT_API_URL
39
  questions_url = f"{api_url}/questions"
40
- submit_url = f"{api_url}/submit"
41
-
42
- # 1. Instantiate Agent ( modify this part to create your agent)
43
- try:
44
- agent = BasicAgent()
45
- except Exception as e:
46
- print(f"Error instantiating agent: {e}")
47
- return f"Error initializing agent: {e}", None
48
- # 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)
49
- agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
50
- print(agent_code)
51
-
52
- # 2. Fetch Questions
53
- print(f"Fetching questions from: {questions_url}")
54
  try:
55
  response = requests.get(questions_url, timeout=15)
56
  response.raise_for_status()
57
  questions_data = response.json()
58
  if not questions_data:
59
- print("Fetched questions list is empty.")
60
- return "Fetched questions list is empty or invalid format.", None
61
  print(f"Fetched {len(questions_data)} questions.")
62
- except requests.exceptions.RequestException as e:
63
- print(f"Error fetching questions: {e}")
64
- return f"Error fetching questions: {e}", None
65
- except requests.exceptions.JSONDecodeError as e:
66
- print(f"Error decoding JSON response from questions endpoint: {e}")
67
- print(f"Response text: {response.text[:500]}")
68
- return f"Error decoding server response for questions: {e}", None
69
  except Exception as e:
70
- print(f"An unexpected error occurred fetching questions: {e}")
71
- return f"An unexpected error occurred fetching questions: {e}", None
72
-
73
- # 3. Run your Agent
74
  results_log = []
75
  answers_payload = []
76
- print(f"Running agent on {len(questions_data)} questions...")
77
- for item in questions_data:
 
 
78
  task_id = item.get("task_id")
79
  question_text = item.get("question")
80
  if not task_id or question_text is None:
81
  print(f"Skipping item with missing task_id or question: {item}")
82
- continue
83
  try:
84
- submitted_answer = agent(question_text)
85
- answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
86
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
87
  except Exception as e:
88
- print(f"Error running agent on task {task_id}: {e}")
89
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
90
-
91
- if not answers_payload:
92
- print("Agent did not produce any answers to submit.")
93
- return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
94
-
95
- # 4. Prepare Submission
96
- submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
97
- status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
98
- print(status_update)
99
-
100
- # 5. Submit
101
- print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  try:
103
  response = requests.post(submit_url, json=submission_data, timeout=60)
104
  response.raise_for_status()
@@ -110,36 +116,12 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
110
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
111
  f"Message: {result_data.get('message', 'No message received.')}"
112
  )
113
- print("Submission successful.")
114
- results_df = pd.DataFrame(results_log)
115
  return final_status, results_df
116
- except requests.exceptions.HTTPError as e:
117
- error_detail = f"Server responded with status {e.response.status_code}."
118
- try:
119
- error_json = e.response.json()
120
- error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
121
- except requests.exceptions.JSONDecodeError:
122
- error_detail += f" Response: {e.response.text[:500]}"
123
- status_message = f"Submission Failed: {error_detail}"
124
- print(status_message)
125
- results_df = pd.DataFrame(results_log)
126
- return status_message, results_df
127
- except requests.exceptions.Timeout:
128
- status_message = "Submission Failed: The request timed out."
129
- print(status_message)
130
- results_df = pd.DataFrame(results_log)
131
- return status_message, results_df
132
- except requests.exceptions.RequestException as e:
133
- status_message = f"Submission Failed: Network error - {e}"
134
- print(status_message)
135
- results_df = pd.DataFrame(results_log)
136
- return status_message, results_df
137
  except Exception as e:
138
- status_message = f"An unexpected error occurred during submission: {e}"
139
- print(status_message)
140
- results_df = pd.DataFrame(results_log)
141
- return status_message, results_df
142
-
143
 
144
  # --- Build Gradio Interface using Blocks ---
145
  with gr.Blocks() as demo:
@@ -150,26 +132,36 @@ with gr.Blocks() as demo:
150
 
151
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
152
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
153
- 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
154
 
155
  ---
156
  **Disclaimers:**
157
- 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).
158
- 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.
159
  """
160
  )
161
 
162
  gr.LoginButton()
163
 
164
- run_button = gr.Button("Run Evaluation & Submit All Answers")
 
 
165
 
166
- status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
167
- # Removed max_rows=10 from DataFrame constructor
 
168
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
169
 
170
- run_button.click(
171
- fn=run_and_submit_all,
172
- outputs=[status_output, results_table]
 
 
 
 
 
 
 
 
173
  )
174
 
175
  if __name__ == "__main__":
 
4
  import inspect
5
  import pandas as pd
6
  from agents import LlamaIndexAgent
7
+ import asyncio
8
+
9
  # (Keep Constants as is)
10
  # --- Constants ---
11
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
 
16
  def __init__(self):
17
  self.agent = LlamaIndexAgent()
18
  print("BasicAgent initialized.")
19
+ async def aquery(self, question: str) -> str:
20
  print(f"Agent received question (first 50 chars): {question[:50]}...")
21
+ response = await self.agent.run_query(question)
22
  print(f"Agent returning fixed answer: {response}")
23
  return response
24
 
25
+ # Global cache for answers (in-memory)
26
+ cached_answers = None
27
+ cached_results_log = None
28
+ cached_questions = None
29
+
30
+ async def generate_answers(profile: gr.OAuthProfile | None, progress=gr.Progress(track_tqdm=True)):
31
  """
32
+ Fetches all questions, runs the BasicAgent on them asynchronously, and returns the answers and log.
 
33
  """
34
+ global cached_answers, cached_results_log, cached_questions
35
+ space_id = os.getenv("SPACE_ID")
 
36
  if profile:
37
+ username = f"{profile.username}"
38
  print(f"User logged in: {username}")
39
  else:
40
  print("User not logged in.")
41
+ return "Please Login to Hugging Face with the button.", None, gr.update(interactive=False), gr.update(value=0, visible=False)
 
42
  api_url = DEFAULT_API_URL
43
  questions_url = f"{api_url}/questions"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  try:
45
  response = requests.get(questions_url, timeout=15)
46
  response.raise_for_status()
47
  questions_data = response.json()
48
  if not questions_data:
49
+ print("Fetched questions list is empty.")
50
+ return "Fetched questions list is empty or invalid format.", None, gr.update(interactive=False), gr.update(value=0, visible=False)
51
  print(f"Fetched {len(questions_data)} questions.")
 
 
 
 
 
 
 
52
  except Exception as e:
53
+ print(f"Error fetching questions: {e}")
54
+ return f"Error fetching questions: {e}", None, gr.update(interactive=False), gr.update(value=0, visible=False)
55
+ agent = BasicAgent()
 
56
  results_log = []
57
  answers_payload = []
58
+ cached_questions = questions_data
59
+ total = len(questions_data)
60
+ progress(0, desc="Starting answer generation...")
61
+ async def answer_one(item):
62
  task_id = item.get("task_id")
63
  question_text = item.get("question")
64
  if not task_id or question_text is None:
65
  print(f"Skipping item with missing task_id or question: {item}")
66
+ return {"Task ID": task_id, "Question": question_text, "Submitted Answer": "SKIPPED"}, None
67
  try:
68
+ submitted_answer = await agent.aquery(question_text)
69
+ return {"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer}, {"task_id": task_id, "submitted_answer": submitted_answer}
 
70
  except Exception as e:
71
+ print(f"Error running agent on task {task_id}: {e}")
72
+ return {"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"}, None
73
+ tasks = [answer_one(item) for item in questions_data]
74
+ results_log = []
75
+ answers_payload = []
76
+ for idx, coro in enumerate(asyncio.as_completed(tasks)):
77
+ log, answer = await coro
78
+ results_log.append(log)
79
+ if answer:
80
+ answers_payload.append(answer)
81
+ progress(int((idx+1)/total*100), desc=f"Answered {idx+1}/{total}")
82
+ cached_answers = answers_payload
83
+ cached_results_log = results_log
84
+ progress(100, desc="Done.")
85
+ results_df = pd.DataFrame(results_log)
86
+ return "Answer generation complete. Review and submit.", results_df, gr.update(interactive=True), gr.update(value=100, visible=True)
87
+
88
+ def submit_answers(profile: gr.OAuthProfile | None):
89
+ """
90
+ Submits cached answers and returns the result.
91
+ """
92
+ global cached_answers, cached_results_log, cached_questions
93
+ space_id = os.getenv("SPACE_ID")
94
+ if profile:
95
+ username = f"{profile.username}"
96
+ print(f"User logged in: {username}")
97
+ else:
98
+ print("User not logged in.")
99
+ return "Please Login to Hugging Face with the button.", None
100
+ if not cached_answers:
101
+ print("No answers to submit.")
102
+ return "No answers to submit. Please generate answers first.", None
103
+ api_url = DEFAULT_API_URL
104
+ submit_url = f"{api_url}/submit"
105
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
106
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": cached_answers}
107
+ print(f"Submitting {len(cached_answers)} answers to: {submit_url}")
108
  try:
109
  response = requests.post(submit_url, json=submission_data, timeout=60)
110
  response.raise_for_status()
 
116
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
117
  f"Message: {result_data.get('message', 'No message received.')}"
118
  )
119
+ results_df = pd.DataFrame(cached_results_log)
 
120
  return final_status, results_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  except Exception as e:
122
+ print(f"Submission error: {e}")
123
+ results_df = pd.DataFrame(cached_results_log)
124
+ return f"Submission Failed: {e}", results_df
 
 
125
 
126
  # --- Build Gradio Interface using Blocks ---
127
  with gr.Blocks() as demo:
 
132
 
133
  1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
134
  2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
135
+ 3. Click 'Generate Answers' to fetch questions and run your agent. Review the answers, then click 'Submit Answers' to submit them and see your score.
136
 
137
  ---
138
  **Disclaimers:**
139
+ Generating answers may take some time. This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution. For instance, you could cache the answers and submit in a separate action or answer the questions asynchronously.
 
140
  """
141
  )
142
 
143
  gr.LoginButton()
144
 
145
+ with gr.Row():
146
+ generate_button = gr.Button("Generate Answers")
147
+ submit_button = gr.Button("Submit Answers", interactive=False)
148
 
149
+ progress_bar = gr.Progress(label="Progress", value=0, minimum=0, maximum=100, visible=False)
150
+
151
+ status_output = gr.Textbox(label="Status / Submission Result", lines=5, interactive=False)
152
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
153
 
154
+ generate_button.click(
155
+ fn=generate_answers,
156
+ inputs=[gr.OAuthProfile],
157
+ outputs=[status_output, results_table, submit_button, progress_bar],
158
+ api_name="generate_answers"
159
+ )
160
+ submit_button.click(
161
+ fn=submit_answers,
162
+ inputs=[gr.OAuthProfile],
163
+ outputs=[status_output, results_table],
164
+ api_name="submit_answers"
165
  )
166
 
167
  if __name__ == "__main__":