Toumaima commited on
Commit
30c4ebf
·
verified ·
1 Parent(s): 3983439

start from scratch

Browse files
Files changed (1) hide show
  1. app.py +126 -251
app.py CHANGED
@@ -1,304 +1,175 @@
1
- import requests
2
- import string
3
- import inspect
4
  import os
5
- import re
6
- import spacy
7
- from transformers import pipeline
8
- from duckduckgo_search import DDGS
9
- from sklearn.metrics.pairwise import cosine_similarity
10
- import numpy as np
11
- import whisper
12
- import moviepy
13
  import gradio as gr
 
 
14
  import pandas as pd
15
- from spacy.cli import download
16
- from transformers import AutoTokenizer, AutoModel
17
- import torch
18
 
 
 
 
 
 
19
  class BasicAgent:
20
  def __init__(self):
21
  print("BasicAgent initialized.")
22
- try:
23
- self.spacy = spacy.load("en_core_web_sm")
24
- except OSError:
25
- download("en_core_web_sm")
26
- self.spacy = spacy.load("en_core_web_sm")
27
-
28
- self.whisper_model = whisper.load_model("base")
29
- self.qa_pipeline = pipeline("question-answering", truncation=True, padding=True)
30
- self.ner_pipeline = pipeline("ner", aggregation_strategy="simple")
31
-
32
- # FIXED: safer embedding model setup
33
- self.embedding_tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
34
- self.embedding_model = AutoModel.from_pretrained("bert-base-uncased")
35
-
36
- def split_text_into_chunks(self, text, max_length=512):
37
- """Split text into chunks smaller than `max_length` tokens."""
38
- words = text.split()
39
- chunks = []
40
- chunk = []
41
-
42
- for word in words:
43
- chunk.append(word)
44
- if len(' '.join(chunk)) > max_length:
45
- chunks.append(' '.join(chunk[:-1])) # Add the chunk and reset
46
- chunk = [word]
47
-
48
- if chunk:
49
- chunks.append(' '.join(chunk)) # Add the final chunk
50
-
51
- return chunks
52
-
53
- def answer_question(self, question: str, context: str) -> str:
54
- try:
55
- context_chunks = self.split_text_into_chunks(context, max_length=512)
56
- answers = []
57
- for chunk in context_chunks:
58
- answer = self.qa_pipeline(question=question, context=chunk)["answer"]
59
- answers.append(answer)
60
-
61
- return " ".join(answers) # Combine answers from chunks
62
- except Exception as e:
63
- return f"Error answering question: {e}"
64
-
65
- def extract_named_entities(self, text):
66
- entities = self.ner_pipeline(text)
67
- return [e["word"] for e in entities if e["entity_group"] == "PER"]
68
-
69
- def extract_numbers(self, text):
70
- return re.findall(r"\d+", text)
71
-
72
- def extract_keywords(self, text):
73
- doc = self.spacy(text)
74
- return [token.text for token in doc if token.pos_ in ["NOUN", "PROPN"]]
75
-
76
- def call_whisper(self, video_path: str) -> str:
77
- video = moviepy.editor.VideoFileClip(video_path)
78
- audio_path = "temp_audio.wav"
79
- video.audio.write_audiofile(audio_path)
80
- result = self.whisper_model.transcribe(audio_path)
81
- os.remove(audio_path)
82
- return result["text"]
83
-
84
- def search(self, question: str) -> str:
85
- try:
86
- with DDGS() as ddgs:
87
- results = list(ddgs.text(question, max_results=3))
88
- if not results:
89
- return "No relevant search results found."
90
- context = results[0]["body"]
91
- return context
92
- except Exception as e:
93
- return f"Search error: {e}"
94
-
95
- def answer_question(self, question: str, context: str) -> str:
96
- try:
97
- return self.qa_pipeline(question=question, context=context)["answer"]
98
- except:
99
- return context # Fallback to context if QA fails
100
-
101
- def handle_logic_riddles(self, question: str) -> str | None:
102
- # Normalize the input
103
- q = question.lower().strip()
104
- q = q.translate(str.maketrans("", "", string.punctuation)) # remove punctuation
105
- q = re.sub(r"\s+", " ", q) # normalize multiple spaces
106
-
107
- logic_patterns = [
108
- {
109
- "pattern": r"opposite of the word left",
110
- "answer": "right"
111
- },
112
- {
113
- "pattern": r"what comes after a",
114
- "answer": "b"
115
- },
116
- {
117
- "pattern": r"first letter of the alphabet",
118
- "answer": "a"
119
- },
120
- {
121
- "pattern": r"what is the color of the clear sky",
122
- "answer": "blue"
123
- },
124
- {
125
- "pattern": r"how many sides does a triangle have",
126
- "answer": "3"
127
- },
128
- {
129
- "pattern": r"how many legs does a spider have",
130
- "answer": "8"
131
- },
132
- {
133
- "pattern": r"what is 2 \+ 2",
134
- "answer": "4"
135
- },
136
- {
137
- "pattern": r"what is the opposite of up",
138
- "answer": "down"
139
- },
140
- {
141
- "pattern": r"if you understand this sentence.*opposite.*left",
142
- "answer": "right"
143
- }
144
- ]
145
-
146
- for item in logic_patterns:
147
- if re.search(item["pattern"], q, re.IGNORECASE):
148
- return item["answer"]
149
-
150
- return None
151
-
152
-
153
- def solve_riddle(self, riddle: str) -> str:
154
- """Fallback riddle solver using QA pipeline with general logic context."""
155
- riddle_context = (
156
- "You are a riddle-solving assistant. Try to give a short and logical answer to riddles.\n"
157
- "Examples:\n"
158
- "Q: What has keys but can't open locks?\nA: A piano\n"
159
- "Q: What runs but never walks?\nA: Water\n"
160
- "Q: What comes once in a minute, twice in a moment, but never in a thousand years?\nA: The letter M\n"
161
- f"Q: {riddle}\nA:"
162
- )
163
- try:
164
- result = self.qa_pipeline(question=riddle, context=riddle_context)
165
- return result["answer"]
166
- except Exception as e:
167
- return f"Could not solve riddle: {e}"
168
-
169
-
170
-
171
- def __call__(self, question: str, video_path: str = None) -> str:
172
- print(f"Agent received question: {question[:60]}...")
173
-
174
- # Handle logic/riddle questions first
175
- logic_answer = self.handle_logic_riddles(question)
176
- if logic_answer is not None:
177
- return f"🧠 Logic Answer: {logic_answer}"
178
- else:
179
- riddle_guess = self.solve_riddle(question)
180
- return f"🤖 Riddle Guess: {riddle_guess}"
181
-
182
- if video_path:
183
- transcription = self.call_whisper(video_path)
184
- print(f"Transcribed video: {transcription[:100]}...")
185
- return transcription
186
-
187
- context = self.search(question)
188
- answer = self.answer_question(question, context)
189
- q_lower = question.lower()
190
-
191
- # Enhanced formatting based on question type
192
- if "who" in q_lower:
193
- people = self.extract_named_entities(context)
194
- return f"👤 Who: {', '.join(people) if people else 'No person found'}\n\n🧠 Answer: {answer}"
195
-
196
- elif "how many" in q_lower:
197
- numbers = self.extract_numbers(context)
198
- return f"🔢 How many: {', '.join(numbers) if numbers else 'No numbers found'}\n\n🧠 Answer: {answer}"
199
-
200
- elif "how" in q_lower:
201
- return f"⚙️ How: {answer}"
202
-
203
- elif "what" in q_lower or "where" in q_lower:
204
- keywords = self.extract_keywords(context)
205
- return f"🗝️ Keywords: {', '.join(keywords[:5])}\n\n🧠 Answer: {answer}"
206
-
207
- else:
208
- return f"🧠 Answer: {answer}"
209
-
210
- # --- Submission Function ---
211
- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
212
-
213
- def run_and_submit_all(profile: gr.OAuthProfile | None):
214
- space_id = os.getenv("SPACE_ID")
215
 
216
  if profile:
217
- username = profile.username
218
  print(f"User logged in: {username}")
219
  else:
 
220
  return "Please Login to Hugging Face with the button.", None
221
 
222
  api_url = DEFAULT_API_URL
223
  questions_url = f"{api_url}/questions"
224
  submit_url = f"{api_url}/submit"
225
 
 
226
  try:
227
  agent = BasicAgent()
228
  except Exception as e:
 
229
  return f"Error initializing agent: {e}", None
230
-
231
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
232
- print(f"Agent repo: {agent_code}")
233
 
 
 
234
  try:
235
  response = requests.get(questions_url, timeout=15)
236
  response.raise_for_status()
237
  questions_data = response.json()
 
 
 
238
  print(f"Fetched {len(questions_data)} questions.")
239
- except Exception as e:
 
240
  return f"Error fetching questions: {e}", None
 
 
 
 
 
 
 
241
 
 
242
  results_log = []
243
  answers_payload = []
244
-
245
  for item in questions_data:
246
  task_id = item.get("task_id")
247
  question_text = item.get("question")
248
- video_link = item.get("video_link")
249
-
250
  if not task_id or question_text is None:
 
251
  continue
252
-
253
  try:
254
- submitted_answer = agent(question_text, video_path=video_link)
255
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
256
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
257
  except Exception as e:
258
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"ERROR: {e}"})
 
259
 
260
  if not answers_payload:
261
- return "No answers were submitted.", pd.DataFrame(results_log)
 
262
 
263
- submission_data = {
264
- "username": username.strip(),
265
- "agent_code": agent_code,
266
- "answers": answers_payload
267
- }
268
 
 
 
269
  try:
270
  response = requests.post(submit_url, json=submission_data, timeout=60)
271
  response.raise_for_status()
272
  result_data = response.json()
273
  final_status = (
274
- f"Submission Successful!\n"
275
  f"User: {result_data.get('username')}\n"
276
- f"Score: {result_data.get('score', 'N/A')}% "
277
- f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')})\n"
278
- f"Message: {result_data.get('message', '')}"
279
  )
280
- return final_status, pd.DataFrame(results_log)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  except Exception as e:
282
- return f"Submission Failed: {e}", pd.DataFrame(results_log)
 
 
 
283
 
284
 
285
- # --- Gradio Interface ---
286
  with gr.Blocks() as demo:
287
  gr.Markdown("# Basic Agent Evaluation Runner")
288
  gr.Markdown(
289
- """
290
- **Instructions:**
291
- 1. Clone this space and modify the agent logic if desired.
292
- 2. Log in to Hugging Face with the button below.
293
- 3. Click 'Run Evaluation & Submit All Answers' to evaluate and submit your agent.
294
- ---
295
- **Note:** This process may take several minutes depending on the number of questions.
296
- """
297
  )
298
 
299
  gr.LoginButton()
 
300
  run_button = gr.Button("Run Evaluation & Submit All Answers")
 
301
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
302
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
303
 
304
  run_button.click(
@@ -306,22 +177,26 @@ with gr.Blocks() as demo:
306
  outputs=[status_output, results_table]
307
  )
308
 
309
-
310
  if __name__ == "__main__":
311
- print("-" * 30 + " App Starting " + "-" * 30)
312
- space_host = os.getenv("SPACE_HOST")
313
- space_id = os.getenv("SPACE_ID")
314
-
315
- if space_host:
316
- print(f"✅ SPACE_HOST: {space_host}")
317
- print(f" https://{space_host}.hf.space")
 
318
  else:
319
- print("ℹ️ No SPACE_HOST set.")
320
 
321
- if space_id:
322
- print(f"✅ SPACE_ID: {space_id}")
323
- print(f" https://huggingface.co/spaces/{space_id}/tree/main")
 
324
  else:
325
- print("ℹ️ No SPACE_ID set.")
 
 
326
 
 
327
  demo.launch(debug=True, share=False)
 
 
 
 
1
  import os
 
 
 
 
 
 
 
 
2
  import gradio as gr
3
+ import requests
4
+ import inspect
5
  import pandas as pd
6
+ from smolagents import CodeAgent, DuckDuckGoSearchTool, HfApiModel
 
 
7
 
8
+ # (Keep Constants and BasicAgent class as is)
9
+ # --- Constants ---
10
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
11
+
12
+ # --- Basic Agent Definition ---
13
  class BasicAgent:
14
  def __init__(self):
15
  print("BasicAgent initialized.")
16
+ self.agent = CodeAgent(tools=[DuckDuckGoSearchTool()], model=HfApiModel())
17
+
18
+ SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question. Report your thoughts, and
19
+ finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER].
20
+ YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated
21
+ list of numbers and/or strings.
22
+ If you are asked for a number, don't use comma to write your number neither use units such as $ or
23
+ percent sign unless specified otherwise.
24
+ If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the
25
+ digits in plain text unless specified otherwise.
26
+ If you are asked for a comma separated list, apply the above rules depending of whether the element
27
+ to be put in the list is a number or a string.
28
+ """
29
+ self.agent.prompt_templates["system_prompt"] = self.agent.prompt_templates["system_prompt"] + SYSTEM_PROMPT
30
+
31
+ def __call__(self, question: str) -> str:
32
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
33
+ final_answer = self.agent.run(question)
34
+ print(f"Agent returning final answer: {final_answer}")
35
+ return final_answer
36
+
37
+ def run_and_submit_all( profile: gr.OAuthProfile | None):
38
+ """
39
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
40
+ and displays the results.
41
+ """
42
+ # --- Determine HF Space Runtime URL and Repo URL ---
43
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  if profile:
46
+ username= f"{profile.username}"
47
  print(f"User logged in: {username}")
48
  else:
49
+ print("User not logged in.")
50
  return "Please Login to Hugging Face with the button.", None
51
 
52
  api_url = DEFAULT_API_URL
53
  questions_url = f"{api_url}/questions"
54
  submit_url = f"{api_url}/submit"
55
 
56
+ # 1. Instantiate Agent ( modify this part to create your agent)
57
  try:
58
  agent = BasicAgent()
59
  except Exception as e:
60
+ print(f"Error instantiating agent: {e}")
61
  return f"Error initializing agent: {e}", None
62
+ # 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)
63
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
64
+ print(agent_code)
65
 
66
+ # 2. Fetch Questions
67
+ print(f"Fetching questions from: {questions_url}")
68
  try:
69
  response = requests.get(questions_url, timeout=15)
70
  response.raise_for_status()
71
  questions_data = response.json()
72
+ if not questions_data:
73
+ print("Fetched questions list is empty.")
74
+ return "Fetched questions list is empty or invalid format.", None
75
  print(f"Fetched {len(questions_data)} questions.")
76
+ except requests.exceptions.RequestException as e:
77
+ print(f"Error fetching questions: {e}")
78
  return f"Error fetching questions: {e}", None
79
+ except requests.exceptions.JSONDecodeError as e:
80
+ print(f"Error decoding JSON response from questions endpoint: {e}")
81
+ print(f"Response text: {response.text[:500]}")
82
+ return f"Error decoding server response for questions: {e}", None
83
+ except Exception as e:
84
+ print(f"An unexpected error occurred fetching questions: {e}")
85
+ return f"An unexpected error occurred fetching questions: {e}", None
86
 
87
+ # 3. Run your Agent
88
  results_log = []
89
  answers_payload = []
90
+ print(f"Running agent on {len(questions_data)} questions...")
91
  for item in questions_data:
92
  task_id = item.get("task_id")
93
  question_text = item.get("question")
 
 
94
  if not task_id or question_text is None:
95
+ print(f"Skipping item with missing task_id or question: {item}")
96
  continue
 
97
  try:
98
+ submitted_answer = agent(question_text)
99
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
100
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
101
  except Exception as e:
102
+ print(f"Error running agent on task {task_id}: {e}")
103
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
104
 
105
  if not answers_payload:
106
+ print("Agent did not produce any answers to submit.")
107
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
108
 
109
+ # 4. Prepare Submission
110
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
111
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
112
+ print(status_update)
 
113
 
114
+ # 5. Submit
115
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
116
  try:
117
  response = requests.post(submit_url, json=submission_data, timeout=60)
118
  response.raise_for_status()
119
  result_data = response.json()
120
  final_status = (
121
+ f"Submission Successful!\n"
122
  f"User: {result_data.get('username')}\n"
123
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
124
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
125
+ f"Message: {result_data.get('message', 'No message received.')}"
126
  )
127
+ print("Submission successful.")
128
+ results_df = pd.DataFrame(results_log)
129
+ return final_status, results_df
130
+ except requests.exceptions.HTTPError as e:
131
+ error_detail = f"Server responded with status {e.response.status_code}."
132
+ try:
133
+ error_json = e.response.json()
134
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
135
+ except requests.exceptions.JSONDecodeError:
136
+ error_detail += f" Response: {e.response.text[:500]}"
137
+ status_message = f"Submission Failed: {error_detail}"
138
+ print(status_message)
139
+ results_df = pd.DataFrame(results_log)
140
+ return status_message, results_df
141
+ except requests.exceptions.Timeout:
142
+ status_message = "Submission Failed: The request timed out."
143
+ print(status_message)
144
+ results_df = pd.DataFrame(results_log)
145
+ return status_message, results_df
146
+ except requests.exceptions.RequestException as e:
147
+ status_message = f"Submission Failed: Network error - {e}"
148
+ print(status_message)
149
+ results_df = pd.DataFrame(results_log)
150
+ return status_message, results_df
151
  except Exception as e:
152
+ status_message = f"An unexpected error occurred during submission: {e}"
153
+ print(status_message)
154
+ results_df = pd.DataFrame(results_log)
155
+ return status_message, results_df
156
 
157
 
158
+ # --- Build Gradio Interface using Blocks ---
159
  with gr.Blocks() as demo:
160
  gr.Markdown("# Basic Agent Evaluation Runner")
161
  gr.Markdown(
162
+ "Please clone this space, then modify the code to define your agent's logic within the `BasicAgent` class. "
163
+ "Log in to your Hugging Face account using the button below. This uses your HF username for submission. "
164
+ "Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score."
 
 
 
 
 
165
  )
166
 
167
  gr.LoginButton()
168
+
169
  run_button = gr.Button("Run Evaluation & Submit All Answers")
170
+
171
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
172
+ # Removed max_rows=10 from DataFrame constructor
173
  results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
174
 
175
  run_button.click(
 
177
  outputs=[status_output, results_table]
178
  )
179
 
 
180
  if __name__ == "__main__":
181
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
182
+ # Check for SPACE_HOST and SPACE_ID at startup for information
183
+ space_host_startup = os.getenv("SPACE_HOST")
184
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
185
+
186
+ if space_host_startup:
187
+ print(f" SPACE_HOST found: {space_host_startup}")
188
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
189
  else:
190
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
191
 
192
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
193
+ print(f"✅ SPACE_ID found: {space_id_startup}")
194
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
195
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
196
  else:
197
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
198
+
199
+ print("-"*(60 + len(" App Starting ")) + "\n")
200
 
201
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
202
  demo.launch(debug=True, share=False)