yannis2025 commited on
Commit
3d0d39f
·
verified ·
1 Parent(s): 487a5b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +251 -67
app.py CHANGED
@@ -1,71 +1,255 @@
 
1
  import gradio as gr
2
  import requests
3
- import os
4
- from huggingface_hub import InferenceClient
5
- from tools import WikipediaTool, MathTool
6
-
7
- # Use a lightweight model that runs on free Spaces (optional: try mistralai/Mistral-7B-Instruct-v0.1 if you pay for GPU)
8
- MODEL_ID = "tiiuae/falcon-7b-instruct"
9
- client = InferenceClient(MODEL_ID, token=os.getenv("HF_TOKEN"))
10
-
11
- tools = [WikipediaTool(), MathTool()]
12
-
13
- # Prompt template
14
- def build_prompt(question):
15
- return f"""You are a helpful AI tutor. Answer the following question very concisely but accurately.
16
-
17
- Question: {question}
18
- Answer:"""
19
-
20
- # Get questions from the evaluation server
21
- def fetch_questions():
22
- res = requests.get("https://agents-course-unit4-scoring.hf.space/questions")
23
- return res.json()
24
-
25
- # Submit answers back to the evaluation server
26
- def submit_answers(answers):
27
- res = requests.post("https://agents-course-unit4-scoring.hf.space/submit", json={"answers": answers})
28
- return res.json()
29
-
30
- # Core agent logic
31
- def run_agent(questions):
32
- answers = []
33
- logs = []
34
- for q in questions:
35
- prompt = build_prompt(q)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  try:
37
- output = client.text_generation(prompt, max_new_tokens=100, temperature=0.5)
38
- final_answer = output.strip().split("Answer:")[-1].strip()
 
 
 
 
 
 
39
  except Exception as e:
40
- final_answer = "AGENT ERROR"
41
- output = str(e)
42
-
43
- answers.append(final_answer)
44
- logs.append(f"**Q:** {q}\n**Prompt:** {prompt}\n**Model Output:** {output}\n**Submitted Answer:** {final_answer}\n\n---\n")
45
-
46
- return answers, "\n".join(logs)
47
-
48
- # Gradio UI
49
- def main():
50
- with gr.Blocks() as demo:
51
- gr.Markdown("# 🤖 Final Assignment Agent (Unit 4)")
52
- with gr.Row():
53
- run_button = gr.Button("🔍 Run Agent on 20 Questions")
54
- submit_button = gr.Button("🚀 Submit to Evaluation")
55
- output_text = gr.Textbox(label="Log Output", lines=30)
56
- score_text = gr.Textbox(label="Score Result")
57
- state = gr.State()
58
-
59
- def run_and_log():
60
- questions = fetch_questions()
61
- answers, log = run_agent(questions)
62
- return answers, log
63
-
64
- def submit_wrapper(answers):
65
- result = submit_answers(answers)
66
- return str(result)
67
-
68
- run_button.click(run_and_log, outputs=[state, output_text])
69
- submit_button.click(submit_wrapper, inputs=[state], outputs=score_text)
70
-
71
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
  import gradio as gr
3
  import requests
4
+ import inspect
5
+ import pandas as pd
6
+ import re
7
+
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
+ self.api_url = "https://api-inference.huggingface.co/models/mixtral-7b-instruct-v0.3"
16
+ self.api_token = os.getenv("HF_TOKEN")
17
+ if not self.api_token:
18
+ raise ValueError("HF_TOKEN environment variable not set.")
19
+ self.headers = {"Authorization": f"Bearer {self.api_token}"}
20
+ print("BasicAgent initialized with Mistral-7B-Instruct-v0.3.")
21
+
22
+ def __call__(self, question: str) -> tuple[str, str]:
23
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
24
+ try:
25
+ # Prompt designed for concise answers and detailed reasoning
26
+ prompt = (
27
+ f"Question: {question}\n"
28
+ "Please provide a concise answer (e.g., a number like '5' or a short phrase) "
29
+ "followed by a detailed explanation of your reasoning. "
30
+ "Format your response as: Answer: <concise answer>\nReasoning: <detailed reasoning>"
31
+ )
32
+ payload = {
33
+ "inputs": prompt,
34
+ "parameters": {"max_new_tokens": 300, "return_full_text": False}
35
+ }
36
+ response = requests.post(self.api_url, headers=self.headers, json=payload, timeout=10)
37
+ response.raise_for_status()
38
+ full_response = response.json()[0]["generated_text"].strip()
39
+
40
+ # Extract concise answer and reasoning
41
+ answer_match = re.search(r"Answer: (.*?)(?:\nReasoning: (.*))?$", full_response, re.DOTALL)
42
+ if answer_match:
43
+ concise_answer = answer_match.group(1).strip()
44
+ reasoning = answer_match.group(2).strip() if answer_match.group(2) else "No reasoning provided by model."
45
+ else:
46
+ # Fallback: Try to extract a concise answer (e.g., a number or short phrase)
47
+ concise_answer = self._extract_concise_answer(full_response)
48
+ reasoning = full_response
49
+
50
+ print(f"Agent returning concise answer: {concise_answer}")
51
+ print(f"Reasoning (first 50 chars): {reasoning[:50]}...")
52
+ return concise_answer, reasoning
53
+ except requests.exceptions.RequestException as e:
54
+ print(f"Error querying Inference API: {e}")
55
+ return f"Error: {e}", f"Error: Failed to get answer from model - {e}"
56
+ except Exception as e:
57
+ print(f"Unexpected error in agent: {e}")
58
+ return f"Error: {e}", f"Error: {e}"
59
+
60
+ def _extract_concise_answer(self, response: str) -> str:
61
+ """Extracts a concise answer (e.g., number or short phrase) from the model's response."""
62
+ # Try to find a number (integer or float)
63
+ number_match = re.search(r"\b\d+(\.\d+)?\b", response)
64
+ if number_match:
65
+ return number_match.group(0)
66
+ # Try to find a short phrase (up to 3 words)
67
+ words = response.split()[:3]
68
+ if len(words) <= 3 and len(" ".join(words)) <= 20:
69
+ return " ".join(words)
70
+ # Fallback: Use first sentence or first 10 characters
71
+ sentence_end = response.find(". ")
72
+ if sentence_end != -1:
73
+ return response[:sentence_end].strip()[:20]
74
+ return response[:20].strip()
75
+
76
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
77
+ """
78
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
79
+ and displays the results.
80
+ """
81
+ # --- Determine HF Space Runtime URL and Repo URL ---
82
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
83
+
84
+ if profile:
85
+ username= f"{profile.username}"
86
+ print(f"User logged in: {username}")
87
+ else:
88
+ print("User not logged in.")
89
+ return "Please Login to Hugging Face with the button.", None
90
+
91
+ api_url = DEFAULT_API_URL
92
+ questions_url = f"{api_url}/questions"
93
+ submit_url = f"{api_url}/submit"
94
+
95
+ # 1. Instantiate Agent
96
+ try:
97
+ agent = BasicAgent()
98
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
99
+ print(agent_code)
100
+ except Exception as e:
101
+ print(f"Error instantiating agent: {e}")
102
+ return f"Error initializing agent: {e}", None
103
+
104
+ # 2. Fetch Questions
105
+ print(f"Fetching questions from: {questions_url}")
106
+ try:
107
+ response = requests.get(questions_url, timeout=15)
108
+ response.raise_for_status()
109
+ questions_data = response.json()
110
+ if not questions_data:
111
+ print("Fetched questions list is empty.")
112
+ return "Fetched questions list is empty or invalid format.", None
113
+ print(f"Fetched {len(questions_data)} questions.")
114
+ except requests.exceptions.RequestException as e:
115
+ print(f"Error fetching questions: {e}")
116
+ return f"Error fetching questions: {e}", None
117
+ except requests.exceptions.JSONDecodeError as e:
118
+ print(f"Error decoding JSON response from questions endpoint: {e}")
119
+ print(f"Response text: {response.text[:500]}")
120
+ return f"Error decoding server response for questions: {e}", None
121
+ except Exception as e:
122
+ print(f"An unexpected error occurred fetching questions: {e}")
123
+ return f"An unexpected error occurred fetching questions: {e}", None
124
+
125
+ # 3. Run your Agent
126
+ results_log = []
127
+ answers_payload = []
128
+ print(f"Running agent on {len(questions_data)} questions...")
129
+ for item in questions_data:
130
+ task_id = item.get("task_id")
131
+ question_text = item.get("question")
132
+ if not task_id or question_text is None:
133
+ print(f"Skipping item with missing task_id or question: {item}")
134
+ continue
135
  try:
136
+ submitted_answer, reasoning = agent(question_text)
137
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
138
+ results_log.append({
139
+ "Task ID": task_id,
140
+ "Question": question_text,
141
+ "Submitted Answer": submitted_answer,
142
+ "Reasoning": reasoning
143
+ })
144
  except Exception as e:
145
+ print(f"Error running agent on task {task_id}: {e}")
146
+ results_log.append({
147
+ "Task ID": task_id,
148
+ "Question": question_text,
149
+ "Submitted Answer": f"AGENT ERROR: {e}",
150
+ "Reasoning": f"Error: {e}"
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
+ # 4. Prepare Submission
158
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
159
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
160
+ print(status_update)
161
+
162
+ # 5. Submit
163
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
164
+ try:
165
+ response = requests.post(submit_url, json=submission_data, timeout=60)
166
+ response.raise_for_status()
167
+ result_data = response.json()
168
+ final_status = (
169
+ f"Submission Successful!\n"
170
+ f"User: {result_data.get('username')}\n"
171
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
172
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
173
+ f"Message: {result_data.get('message', 'No message received.')}"
174
+ )
175
+ print("Submission successful.")
176
+ results_df = pd.DataFrame(results_log)
177
+ return final_status, results_df
178
+ except requests.exceptions.HTTPError as e:
179
+ error_detail = f"Server responded with status {e.response.status_code}."
180
+ try:
181
+ error_json = e.response.json()
182
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
183
+ except requests.exceptions.JSONDecodeError:
184
+ error_detail += f" Response: {e.response.text[:500]}"
185
+ status_message = f"Submission Failed: {error_detail}"
186
+ print(status_message)
187
+ results_df = pd.DataFrame(results_log)
188
+ return status_message, results_df
189
+ except requests.exceptions.Timeout:
190
+ status_message = "Submission Failed: The request timed out."
191
+ print(status_message)
192
+ results_df = pd.DataFrame(results_log)
193
+ return status_message, results_df
194
+ except requests.exceptions.RequestException as e:
195
+ status_message = f"Submission Failed: Network error - {e}"
196
+ print(status_message)
197
+ results_df = pd.DataFrame(results_log)
198
+ return status_message, results_df
199
+ except Exception as e:
200
+ status_message = f"An unexpected error occurred during submission: {e}"
201
+ print(status_message)
202
+ results_df = pd.DataFrame(results_log)
203
+ return status_message, results_df
204
+
205
+ # --- Build Gradio Interface using Blocks ---
206
+ with gr.Blocks() as demo:
207
+ gr.Markdown("# Basic Agent Evaluation Runner")
208
+ gr.Markdown(
209
+ """
210
+ **Instructions:**
211
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
212
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
213
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
214
+ ---
215
+ **Disclaimers:**
216
+ 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).
217
+ 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.
218
+ """
219
+ )
220
+
221
+ gr.LoginButton()
222
+
223
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
224
+
225
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
226
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
227
+
228
+ run_button.click(
229
+ fn=run_and_submit_all,
230
+ outputs=[status_output, results_table]
231
+ )
232
+
233
+ if __name__ == "__main__":
234
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
235
+ # Check for SPACE_HOST and SPACE_ID at startup for information
236
+ space_host_startup = os.getenv("SPACE_HOST")
237
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
238
+
239
+ if space_host_startup:
240
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
241
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
242
+ else:
243
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
244
+
245
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
246
+ print(f"✅ SPACE_ID found: {space_id_startup}")
247
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
248
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
249
+ else:
250
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
251
+
252
+ print("-"*(60 + len(" App Starting ")) + "\n")
253
+
254
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
255
+ demo.launch(debug=True, share=False)