Toumaima commited on
Commit
2ec7389
·
verified ·
1 Parent(s): 3894546

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +228 -43
app.py CHANGED
@@ -1,73 +1,258 @@
1
  import os
2
  import time
3
- import requests
4
  import moviepy
 
5
  import whisper
6
  import gradio as gr
7
  import pandas as pd
8
- import wikipedia
9
  from duckduckgo_search import DDGS
10
  from transformers import pipeline
 
 
11
 
 
 
12
 
13
- class SmartAgent:
 
14
  def __init__(self):
15
- print("SmartAgent initialized.")
16
- self.whisper_model = whisper.load_model("base")
17
- self.qa_pipeline = pipeline("question-answering")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  def call_whisper(self, video_path: str) -> str:
 
20
  video = moviepy.editor.VideoFileClip(video_path)
21
  audio_path = "temp_audio.wav"
22
  video.audio.write_audiofile(audio_path)
 
 
23
  result = self.whisper_model.transcribe(audio_path)
24
  return result["text"]
25
 
26
- def classify_question(self, question: str) -> str:
27
- q = question.lower()
28
- if "how many" in q or "number of" in q:
29
- return "count"
30
- elif "when" in q or "what year" in q:
31
- return "date"
32
- return "open"
 
 
 
 
 
 
 
33
 
34
- def wiki_search(self, question: str) -> str:
35
- try:
36
- results = wikipedia.search(question, results=1)
37
- if not results:
38
- return ""
39
- page = wikipedia.page(results[0])
40
- return page.content
41
- except Exception as e:
42
- return ""
43
 
44
- def fallback_duckduckgo(self, question: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  try:
46
- with DDGS() as ddgs:
47
- results = list(ddgs.text(question, max_results=3))
48
- return results[0]["body"] if results else ""
 
49
  except Exception as e:
50
- return ""
 
 
 
 
 
51
 
52
- def answer_with_context(self, question: str, context: str) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  try:
54
- if not context.strip():
55
- return "No reliable context found."
56
- result = self.qa_pipeline(question=question, context=context)
57
- return result["answer"]
58
- except Exception as e:
59
- return f"QA error: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
- def __call__(self, question: str, video_path: str = None) -> str:
62
- print(f"Agent received question: {question[:60]}...")
63
 
64
- if video_path:
65
- return self.call_whisper(video_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
- classification = self.classify_question(question)
 
 
 
 
 
 
 
 
 
 
68
 
69
- context = self.wiki_search(question)
70
- if not context:
71
- context = self.fallback_duckduckgo(question)
72
 
73
- return self.answer_with_context(question, context)
 
 
1
  import os
2
  import time
 
3
  import moviepy
4
+ import requests
5
  import whisper
6
  import gradio as gr
7
  import pandas as pd
 
8
  from duckduckgo_search import DDGS
9
  from transformers import pipeline
10
+ from sklearn.metrics.pairwise import cosine_similarity
11
+ import numpy as np
12
 
13
+ # --- Constants ---
14
+ DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
15
 
16
+ # --- Basic Agent Definition ---
17
+ class BasicAgent:
18
  def __init__(self):
19
+ print("BasicAgent initialized.")
20
+ # Initialize the Whisper model for video transcription
21
+ self.whisper_model = whisper.load_model("base") # You can change the model to `large`, `medium`, etc.
22
+ self.search_pipeline = pipeline("question-answering")
23
+ self.nlp_model = pipeline("feature-extraction") # For semantic similarity (using transformer model)
24
+
25
+ def score_search_results(self, question: str, search_results: list) -> str:
26
+ # Transform the question and results to embeddings (vector representations)
27
+ question_embedding = self.nlp_model(question)
28
+ question_embedding = np.mean(question_embedding[0], axis=0)
29
+
30
+ best_score = -1
31
+ best_answer = None
32
+
33
+ # Loop through search results and calculate similarity
34
+ for result in search_results:
35
+ result_embedding = self.nlp_model(result['body'])
36
+ result_embedding = np.mean(result_embedding[0], axis=0)
37
+
38
+ # Calculate cosine similarity
39
+ similarity = cosine_similarity([question_embedding], [result_embedding])
40
+
41
+ # Check if this result is better
42
+ if similarity > best_score:
43
+ best_score = similarity
44
+ best_answer = result['body']
45
+
46
+ return best_answer
47
+
48
+ def search(self, question: str) -> str:
49
+ try:
50
+ with DDGS() as ddgs:
51
+ results = list(ddgs.text(question, max_results=3)) # Fetch top 3 results
52
+ if results:
53
+ # Score all the results and return the best one
54
+ return self.score_search_results(question, results)
55
+ else:
56
+ return "No relevant search results found."
57
+ except Exception as e:
58
+ return f"Search error: {e}"
59
 
60
  def call_whisper(self, video_path: str) -> str:
61
+ # Transcribe the video to text using Whisper model
62
  video = moviepy.editor.VideoFileClip(video_path)
63
  audio_path = "temp_audio.wav"
64
  video.audio.write_audiofile(audio_path)
65
+
66
+ # Transcribe audio to text
67
  result = self.whisper_model.transcribe(audio_path)
68
  return result["text"]
69
 
70
+ def __call__(self, question: str, video_path: str = None) -> str:
71
+ print(f"Agent received question (first 50 chars): {question[:50]}...")
72
+
73
+ # If a video path is provided, use Whisper to transcribe the video
74
+ if video_path:
75
+ transcription = self.call_whisper(video_path)
76
+ print(f"Transcribed video text: {transcription[:100]}...") # Print first 100 characters
77
+ return transcription
78
+
79
+ # If no video is provided, search the web for an answer
80
+ search_answer = self.search(question)
81
+ print(f"Agent returning search result: {search_answer[:100]}...")
82
+ time.sleep(2)
83
+ return search_answer
84
 
 
 
 
 
 
 
 
 
 
85
 
86
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
87
+ """
88
+ Fetches all questions, runs the BasicAgent on them, submits all answers,
89
+ and displays the results.
90
+ """
91
+ # --- Determine HF Space Runtime URL and Repo URL ---
92
+ space_id = os.getenv("SPACE_ID") # Get the SPACE_ID for sending link to the code
93
+
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
+
101
+ api_url = DEFAULT_API_URL
102
+ questions_url = f"{api_url}/questions"
103
+ submit_url = f"{api_url}/submit"
104
+
105
+ # 1. Instantiate Agent
106
+ try:
107
+ agent = BasicAgent()
108
+ except Exception as e:
109
+ print(f"Error instantiating agent: {e}")
110
+ return f"Error initializing agent: {e}", None
111
+
112
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
113
+ print(agent_code)
114
+
115
+ # 2. Fetch Questions
116
+ print(f"Fetching questions from: {questions_url}")
117
+ try:
118
+ response = requests.get(questions_url, timeout=15)
119
+ response.raise_for_status()
120
+ questions_data = response.json()
121
+ if not questions_data:
122
+ print("Fetched questions list is empty.")
123
+ return "Fetched questions list is empty or invalid format.", None
124
+ print(f"Fetched {len(questions_data)} questions.")
125
+ except requests.exceptions.RequestException as e:
126
+ print(f"Error fetching questions: {e}")
127
+ return f"Error fetching questions: {e}", None
128
+ except requests.exceptions.JSONDecodeError as e:
129
+ print(f"Error decoding JSON response from questions endpoint: {e}")
130
+ return f"Error decoding server response for questions: {e}", None
131
+ except Exception as e:
132
+ print(f"An unexpected error occurred fetching questions: {e}")
133
+ return f"An unexpected error occurred fetching questions: {e}", None
134
+
135
+ # 3. Run Agent
136
+ results_log = []
137
+ answers_payload = []
138
+ print(f"Running agent on {len(questions_data)} questions...")
139
+ for item in questions_data:
140
+ task_id = item.get("task_id")
141
+ question_text = item.get("question")
142
+ video_link = item.get("video_link") # Assuming the question contains an optional video link
143
+
144
+ if not task_id or question_text is None:
145
+ print(f"Skipping item with missing task_id or question: {item}")
146
+ continue
147
+
148
  try:
149
+ # Pass video_link if available, else just the question text
150
+ submitted_answer = agent(question_text, video_path=video_link)
151
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
152
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
153
  except Exception as e:
154
+ print(f"Error running agent on task {task_id}: {e}")
155
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
156
+
157
+ if not answers_payload:
158
+ print("Agent did not produce any answers to submit.")
159
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
160
 
161
+ # 4. Prepare Submission
162
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
163
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
164
+ print(status_update)
165
+
166
+ # 5. Submit
167
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
168
+ try:
169
+ response = requests.post(submit_url, json=submission_data, timeout=60)
170
+ response.raise_for_status()
171
+ result_data = response.json()
172
+ final_status = (
173
+ f"Submission Successful!\n"
174
+ f"User: {result_data.get('username')}\n"
175
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
176
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
177
+ f"Message: {result_data.get('message', 'No message received.')}"
178
+ )
179
+ print("Submission successful.")
180
+ results_df = pd.DataFrame(results_log)
181
+ return final_status, results_df
182
+ except requests.exceptions.HTTPError as e:
183
+ error_detail = f"Server responded with status {e.response.status_code}."
184
  try:
185
+ error_json = e.response.json()
186
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
187
+ except requests.exceptions.JSONDecodeError:
188
+ error_detail += f" Response: {e.response.text[:500]}"
189
+ status_message = f"Submission Failed: {error_detail}"
190
+ print(status_message)
191
+ results_df = pd.DataFrame(results_log)
192
+ return status_message, results_df
193
+ except requests.exceptions.Timeout:
194
+ status_message = "Submission Failed: The request timed out."
195
+ print(status_message)
196
+ results_df = pd.DataFrame(results_log)
197
+ return status_message, results_df
198
+ except requests.exceptions.RequestException as e:
199
+ status_message = f"Submission Failed: Network error - {e}"
200
+ print(status_message)
201
+ results_df = pd.DataFrame(results_log)
202
+ return status_message, results_df
203
+ except Exception as e:
204
+ status_message = f"An unexpected error occurred during submission: {e}"
205
+ print(status_message)
206
+ results_df = pd.DataFrame(results_log)
207
+ return status_message, results_df
208
 
 
 
209
 
210
+ # --- Build Gradio Interface using Blocks ---
211
+ with gr.Blocks() as demo:
212
+ gr.Markdown("# Basic Agent Evaluation Runner")
213
+ gr.Markdown(
214
+ """
215
+ **Instructions:**
216
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
217
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
218
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
219
+ ---
220
+ **Disclaimers:**
221
+ 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).
222
+ This space provides a basic setup and is intentionally sub-optimal to encourage you to develop your own, more robust solution.
223
+ """
224
+ )
225
+
226
+ gr.LoginButton()
227
+
228
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
229
+
230
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
231
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
232
+
233
+ run_button.click(
234
+ fn=run_and_submit_all,
235
+ outputs=[status_output, results_table]
236
+ )
237
+
238
+ if __name__ == "__main__":
239
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
240
+ space_host_startup = os.getenv("SPACE_HOST")
241
+ space_id_startup = os.getenv("SPACE_ID")
242
 
243
+ if space_host_startup:
244
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
245
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
246
+ else:
247
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
248
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
249
+ print(f"✅ SPACE_ID found: {space_id_startup}")
250
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
251
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
252
+ else:
253
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
254
 
255
+ print("-"*(60 + len(" App Starting ")) + "\n")
 
 
256
 
257
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
258
+ demo.launch(debug=True, share=False)