dawid-lorek commited on
Commit
b27256b
·
verified ·
1 Parent(s): bbc75b7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +154 -64
app.py CHANGED
@@ -1,55 +1,151 @@
 
1
  import os
2
  import gradio as gr
3
- import requests
4
  import pandas as pd
5
  import time
6
  import re
7
-
 
 
 
8
  from langchain_openai import ChatOpenAI
9
- from langchain.prompts import PromptTemplate
10
  from langchain.agents import AgentExecutor, create_react_agent
11
  from langchain.memory import ConversationSummaryMemory
12
- from typing import List, Optional
13
-
14
- # === TOOL IMPORTS ===
15
- from helper import repl_tool, file_saver_tool, audio_transcriber_tool, gemini_multimodal_tool, wikipedia_search_tool2
16
 
17
- # Constants
18
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
19
 
20
- # --- Prompt ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  prompt = PromptTemplate(
22
  input_variables=["input", "agent_scratchpad", "chat_history", "tool_names"],
23
  template="""
24
- You are a smart and helpful AI Agent/Assistant that excels at fact-based reasoning. You are allowed and encouraged to use one or more tools as needed to answer complex questions and perform tasks.
25
- [ ...cut for brevity: insert your strict format rules and examples here ... ]
26
- {chat_history}
27
- New input: {input}
28
- ---
29
- {agent_scratchpad}
30
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  )
32
 
33
- # === AGENT DEFINITION ===
34
  class BasicAgent:
35
  def __init__(
36
  self,
37
- agent, tools: List, verbose: bool = False, handle_parsing_errors: bool = True,
38
- max_iterations: int = 9, memory: Optional[ConversationSummaryMemory] = None
 
 
 
 
39
  ):
40
- self.agent = agent
41
- self.tools = tools
42
- self.verbose = verbose
43
- self.handle_parsing_errors = handle_parsing_errors
44
- self.max_iterations = max_iterations
45
- self.memory = memory
46
  self.agent_obj = AgentExecutor(
47
- agent=self.agent,
48
- tools=self.tools,
49
- verbose=self.verbose,
50
- handle_parsing_errors=self.handle_parsing_errors,
51
- max_iterations=self.max_iterations,
52
- memory=self.memory
53
  )
54
 
55
  def __call__(self, question: str) -> str:
@@ -61,9 +157,8 @@ class BasicAgent:
61
 
62
  def run_and_submit_all(profile: gr.OAuthProfile | None):
63
  space_id = os.getenv("SPACE_ID")
64
-
65
  if profile:
66
- username = f"{profile.username}"
67
  print(f"User logged in: {username}")
68
  else:
69
  print("User not logged in.")
@@ -73,42 +168,30 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
73
  questions_url = f"{api_url}/questions"
74
  submit_url = f"{api_url}/submit"
75
 
76
- # OpenAI API key only!
77
  openai_api_key = os.getenv("OPENAI_API_KEY")
78
  if not openai_api_key:
79
  print("OpenAI API key not found in environment variables.")
80
  return "OpenAI API key not found. Please set OPENAI_API_KEY environment variable.", None
 
81
 
82
- # Use GPT-4o (or another allowed OpenAI model)
83
  llm_client = ChatOpenAI(model='gpt-4o', temperature=0, api_key=openai_api_key)
84
 
85
- # Tools: only offline/tools not requiring other APIs
86
- tools = [
87
- repl_tool,
88
- file_saver_tool,
89
- audio_transcriber_tool,
90
- gemini_multimodal_tool, # If this is purely local or adapted for OpenAI images, otherwise remove!
91
- wikipedia_search_tool2
92
- ]
93
-
94
  summary_memory = ConversationSummaryMemory(llm=llm_client, memory_key="chat_history")
95
 
96
  summary_react_agent = create_react_agent(
97
  llm=llm_client,
98
- tools=tools,
99
  prompt=prompt
100
  )
101
 
102
- # 1. Instantiate Agent
103
  try:
104
- agent = BasicAgent(summary_react_agent, tools, True, True, 30, summary_memory)
105
  except Exception as e:
106
  print(f"Error instantiating agent: {e}")
107
  return f"Error initializing agent: {e}", None
108
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
109
  print(agent_code)
110
 
111
- # 2. Fetch Questions
112
  print(f"Fetching questions from: {questions_url}")
113
  try:
114
  response = requests.get(questions_url, timeout=15)
@@ -118,11 +201,17 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
118
  print("Fetched questions list is empty.")
119
  return "Fetched questions list is empty or invalid format.", None
120
  print(f"Fetched {len(questions_data)} questions.")
121
- except Exception as e:
122
  print(f"Error fetching questions: {e}")
123
  return f"Error 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...")
@@ -132,17 +221,17 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
132
  file_name = item.get("file_name")
133
  full_question_for_agent = question_text
134
  if file_name:
135
- attachment_url = f"{DEFAULT_API_URL}/files/{task_id}"
136
  full_question_for_agent += f"\n\nAttachment '{file_name}' available at EXACT URL: {attachment_url}"
137
- print(f"Running agent on task {task_id}: {full_question_for_agent}", flush=True)
138
  try:
139
  submitted_answer = agent(full_question_for_agent)
140
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
141
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
142
- time.sleep(2) # Decrease or remove if not rate-limited!
143
  except Exception as e:
144
- print(f"Error running agent on task {task_id}: {e}")
145
- results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
146
 
147
  if not answers_payload:
148
  print("Agent did not produce any answers to submit.")
@@ -164,27 +253,28 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
164
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
165
  f"Message: {result_data.get('message', 'No message received.')}"
166
  )
167
- cleaned_final_status = re.sub(r'[^\x20-\x7E\n\r\t]+', '', final_status).strip()
 
 
168
  results_df = pd.DataFrame(results_log)
169
  return cleaned_final_status, results_df
170
  except Exception as e:
171
- print(f"Error submitting answers: {e}")
 
172
  results_df = pd.DataFrame(results_log)
173
- return f"Submission Failed: {e}", results_df
174
 
175
- # --- Build Gradio Interface using Blocks ---
176
  with gr.Blocks() as demo:
177
  gr.Markdown("# Basic Agent Evaluation Runner")
178
  gr.Markdown(
179
  """
180
  **Instructions:**
181
- 1. Log in to your Hugging Face account using the button below.
182
- 2. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
183
- ---
184
- **Note:** Only OpenAI API key is needed!
185
  """
186
  )
187
-
188
  gr.LoginButton()
189
  run_button = gr.Button("Run Evaluation & Submit All Answers")
190
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
 
1
+ import requests
2
  import os
3
  import gradio as gr
 
4
  import pandas as pd
5
  import time
6
  import re
7
+ import json
8
+ import wikipedia
9
+ import speech_recognition as sr
10
+ from pydub import AudioSegment
11
  from langchain_openai import ChatOpenAI
 
12
  from langchain.agents import AgentExecutor, create_react_agent
13
  from langchain.memory import ConversationSummaryMemory
14
+ from langchain.tools import Tool
15
+ from langchain_experimental.utilities import PythonREPL
16
+ from langchain_community.document_loaders import WikipediaLoader
17
+ from langchain.prompts import PromptTemplate
18
 
19
+ # --- Constants ---
20
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
21
 
22
+ # === TOOL: python_repl ===
23
+ python_repl = PythonREPL()
24
+ repl_tool = Tool(
25
+ name="python_repl",
26
+ description="A Python REPL (Read-Eval-Print Loop) for calculations, parsing, and data manipulation. Input must be valid Python. Use print() to output your answer.",
27
+ func=python_repl.run,
28
+ )
29
+
30
+ # === TOOL: file_saver ===
31
+ def download_and_save_file(args: dict) -> str:
32
+ try:
33
+ if isinstance(args, str):
34
+ args = json.loads(args)
35
+ url = args.get("url")
36
+ local_filename = args.get("local_filename")
37
+ if not url or not local_filename:
38
+ return "Error: Both 'url' and 'local_filename' must be provided."
39
+ response = requests.get(url, stream=True, timeout=30)
40
+ response.raise_for_status()
41
+ os.makedirs(os.path.dirname(local_filename) or '.', exist_ok=True)
42
+ with open(local_filename, 'wb') as f:
43
+ for chunk in response.iter_content(chunk_size=8192):
44
+ f.write(chunk)
45
+ return f"File downloaded successfully to {local_filename}"
46
+ except Exception as e:
47
+ return f"Error downloading file: {e}"
48
+
49
+ file_saver_tool = Tool(
50
+ name="file_saver",
51
+ description="Downloads a file from a URL and saves it as the given local filename. Input: JSON with 'url' and 'local_filename'.",
52
+ func=download_and_save_file,
53
+ )
54
+
55
+ # === TOOL: audio_transcriber_tool ===
56
+ def transcribe_audio_from_path(local_audio_path: str, language: str = "en-US") -> str:
57
+ r = sr.Recognizer()
58
+ temp_wav_path = "temp_audio_to_transcribe.wav"
59
+ transcribed_text = ""
60
+ try:
61
+ if local_audio_path.startswith("http://") or local_audio_path.startswith("https://"):
62
+ return "Error: Only local file paths allowed. Use 'file_saver' first."
63
+ if not os.path.exists(local_audio_path):
64
+ return f"Error: File not found: '{local_audio_path}'."
65
+ audio = AudioSegment.from_file(local_audio_path)
66
+ audio.export(temp_wav_path, format="wav")
67
+ with sr.AudioFile(temp_wav_path) as source:
68
+ audio_listened = r.record(source)
69
+ try:
70
+ transcribed_text = r.recognize_google(audio_listened, language=language)
71
+ except sr.UnknownValueError:
72
+ return "Could not understand audio."
73
+ except sr.RequestError as e:
74
+ return f"Could not request results from Google Speech Recognition; {e}"
75
+ except Exception as e:
76
+ return f"Error: {e}"
77
+ finally:
78
+ if os.path.exists(temp_wav_path):
79
+ os.remove(temp_wav_path)
80
+ return transcribed_text.strip()
81
+
82
+ audio_transcriber_tool = Tool(
83
+ name="audio_transcriber_tool",
84
+ description="Transcribes audio from a local file path to text. Input: path to audio file (e.g., 'myfile.mp3'). Use 'file_saver' to download first. Optionally set language.",
85
+ func=transcribe_audio_from_path,
86
+ )
87
+
88
+ # === TOOL: wikipedia_search_tool2 ===
89
+ def wiki_search(query: str) -> str:
90
+ search_docs = WikipediaLoader(query=query, load_max_docs=2).load()
91
+ formatted_search_docs = "\n\n---\n\n".join(
92
+ [
93
+ f'<Document source="{doc.metadata.get("source", "")}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
94
+ for doc in search_docs
95
+ ])
96
+ return formatted_search_docs
97
+
98
+ wikipedia_search_tool2 = Tool(
99
+ name="wikipedia_search_tool2",
100
+ description="Search Wikipedia for a query and return up to 2 results. Input: query string.",
101
+ func=wiki_search,
102
+ )
103
+
104
+ # === PROMPT ===
105
  prompt = PromptTemplate(
106
  input_variables=["input", "agent_scratchpad", "chat_history", "tool_names"],
107
  template="""
108
+ You are a smart and helpful AI Agent/Assistant that excels at fact-based reasoning. You are allowed and encouraged to use one or more tools as needed to answer complex questions and perform tasks.
109
+ STRICT FINAL ANSWER RULES:
110
+ - Final Answer must be a number, a few words, or a comma-separated list, as requested.
111
+ - No units or extra punctuation unless asked.
112
+ Your response must start with 'Thought:' and finish with 'Final Answer:'.
113
+ You have access to the following tools:
114
+ {tools}
115
+ Use this format:
116
+ Thought: [thinking]
117
+ Action: [tool_name]
118
+ Action Input: [input]
119
+ Observation: [result]
120
+ ...
121
+ Thought: [done]
122
+ Final Answer: [concise answer]
123
+
124
+ {chat_history}
125
+ New input: {input}
126
+ ---
127
+ {agent_scratchpad}
128
+ """
129
  )
130
 
131
+ # === AGENT ===
132
  class BasicAgent:
133
  def __init__(
134
  self,
135
+ agent,
136
+ tools,
137
+ verbose=False,
138
+ handle_parsing_errors=True,
139
+ max_iterations=9,
140
+ memory=None
141
  ):
 
 
 
 
 
 
142
  self.agent_obj = AgentExecutor(
143
+ agent=agent,
144
+ tools=tools,
145
+ verbose=verbose,
146
+ handle_parsing_errors=handle_parsing_errors,
147
+ max_iterations=max_iterations,
148
+ memory=memory
149
  )
150
 
151
  def __call__(self, question: str) -> str:
 
157
 
158
  def run_and_submit_all(profile: gr.OAuthProfile | None):
159
  space_id = os.getenv("SPACE_ID")
 
160
  if profile:
161
+ username= f"{profile.username}"
162
  print(f"User logged in: {username}")
163
  else:
164
  print("User not logged in.")
 
168
  questions_url = f"{api_url}/questions"
169
  submit_url = f"{api_url}/submit"
170
 
 
171
  openai_api_key = os.getenv("OPENAI_API_KEY")
172
  if not openai_api_key:
173
  print("OpenAI API key not found in environment variables.")
174
  return "OpenAI API key not found. Please set OPENAI_API_KEY environment variable.", None
175
+ print(f"Using OpenAI API key: {openai_api_key[:4]}... (truncated for security)")
176
 
 
177
  llm_client = ChatOpenAI(model='gpt-4o', temperature=0, api_key=openai_api_key)
178
 
 
 
 
 
 
 
 
 
 
179
  summary_memory = ConversationSummaryMemory(llm=llm_client, memory_key="chat_history")
180
 
181
  summary_react_agent = create_react_agent(
182
  llm=llm_client,
183
+ tools=[repl_tool, file_saver_tool, audio_transcriber_tool, wikipedia_search_tool2],
184
  prompt=prompt
185
  )
186
 
 
187
  try:
188
+ agent = BasicAgent(summary_react_agent, [repl_tool, file_saver_tool, audio_transcriber_tool, wikipedia_search_tool2], True, True, 30, summary_memory)
189
  except Exception as e:
190
  print(f"Error instantiating agent: {e}")
191
  return f"Error initializing agent: {e}", None
192
  agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
193
  print(agent_code)
194
 
 
195
  print(f"Fetching questions from: {questions_url}")
196
  try:
197
  response = requests.get(questions_url, timeout=15)
 
201
  print("Fetched questions list is empty.")
202
  return "Fetched questions list is empty or invalid format.", None
203
  print(f"Fetched {len(questions_data)} questions.")
204
+ except requests.exceptions.RequestException as e:
205
  print(f"Error fetching questions: {e}")
206
  return f"Error fetching questions: {e}", None
207
+ except requests.exceptions.JSONDecodeError as e:
208
+ print(f"Error decoding JSON response from questions endpoint: {e}")
209
+ print(f"Response text: {response.text[:500]}")
210
+ return f"Error decoding server response for questions: {e}", None
211
+ except Exception as e:
212
+ print(f"An unexpected error occurred fetching questions: {e}")
213
+ return f"An unexpected error occurred fetching questions: {e}", None
214
 
 
215
  results_log = []
216
  answers_payload = []
217
  print(f"Running agent on {len(questions_data)} questions...")
 
221
  file_name = item.get("file_name")
222
  full_question_for_agent = question_text
223
  if file_name:
224
+ attachment_url = f"https://agents-course-unit4-scoring.hf.space/files/{task_id}"
225
  full_question_for_agent += f"\n\nAttachment '{file_name}' available at EXACT URL: {attachment_url}"
226
+ print(f"Running agent on task {task_id}: {full_question_for_agent}",flush=True)
227
  try:
228
  submitted_answer = agent(full_question_for_agent)
229
  answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
230
  results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
231
+ time.sleep(1)
232
  except Exception as e:
233
+ print(f"Error running agent on task {task_id}: {e}")
234
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
235
 
236
  if not answers_payload:
237
  print("Agent did not produce any answers to submit.")
 
253
  f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
254
  f"Message: {result_data.get('message', 'No message received.')}"
255
  )
256
+ print("Submission successful.")
257
+ cleaned_final_status = re.sub(r'[^\x20-\x7E\n\r\t]+', '', final_status)
258
+ cleaned_final_status = cleaned_final_status.strip()
259
  results_df = pd.DataFrame(results_log)
260
  return cleaned_final_status, results_df
261
  except Exception as e:
262
+ status_message = f"Submission Failed: {e}"
263
+ print(status_message)
264
  results_df = pd.DataFrame(results_log)
265
+ return status_message, results_df
266
 
267
+ # --- Gradio Interface ---
268
  with gr.Blocks() as demo:
269
  gr.Markdown("# Basic Agent Evaluation Runner")
270
  gr.Markdown(
271
  """
272
  **Instructions:**
273
+ 1. Clone this space and modify the code as needed.
274
+ 2. Log in to your Hugging Face account below.
275
+ 3. Click 'Run Evaluation & Submit All Answers' to see your score!
 
276
  """
277
  )
 
278
  gr.LoginButton()
279
  run_button = gr.Button("Run Evaluation & Submit All Answers")
280
  status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)