rnrahate007 commited on
Commit
f268128
·
verified ·
1 Parent(s): 13c8ea6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +263 -48
app.py CHANGED
@@ -2,67 +2,282 @@ import os
2
  import gradio as gr
3
  import requests
4
  import pandas as pd
 
5
 
6
- # --- Updated Imports for Modern LangChain (v1.0+) ---
7
- from langchain_google_genai import ChatGoogleGenerativeAI
8
- from langchain_community.tools import DuckDuckGoSearchRun
9
- from langgraph.prebuilt import create_react_agent
10
- from langchain_core.messages import SystemMessage
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
  # --- Constants ---
13
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
14
 
15
- # --- Modern LangGraph Gemini Agent ---
16
- class GeminiAgent:
17
  def __init__(self):
18
- api_key = os.getenv("GEMINI_API_KEY")
19
- if not api_key:
20
  raise ValueError("GEMINI_API_KEY not set")
 
 
 
 
21
 
22
- # Initialize Gemini 2.5 Flash
23
- self.llm = ChatGoogleGenerativeAI(
24
- model="gemini-2.5-flash",
25
- temperature=0,
26
- google_api_key=api_key
27
- )
28
-
29
- # Equip the agent with Web Search
30
- self.search_tool = DuckDuckGoSearchRun()
31
- self.tools = [self.search_tool]
32
-
33
- # Define the System Prompt
34
- system_prompt = """You are an expert assistant for the GAIA benchmark.
35
- You must use your tools to find accurate, up-to-date information before answering.
36
- Do not guess. If you need to perform math, search for the formula or calculation.
37
- Provide ONLY a short, factual answer (e.g., a specific number, name, or exact phrase).
38
- No explanations, just the direct answer."""
39
-
40
- # Create the LangGraph Agent (replaces AgentExecutor)
41
- self.agent_executor = create_react_agent(
42
- self.llm,
43
- self.tools,
44
- state_modifier=SystemMessage(content=system_prompt)
45
- )
46
-
47
- print("LangGraph Agent initialized with Gemini 2.5 Flash")
48
 
49
  def __call__(self, question: str) -> str:
50
  print(f"Agent processing question: {question[:50]}...")
51
 
52
- try:
53
- # LangGraph expects input formatted as a list of messages
54
- response = self.agent_executor.invoke({
55
- "messages": [("user", question)]
56
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
- # The final answer is the content of the last message in the sequence
59
- answer = response["messages"][-1].content.strip()
60
 
61
- if not answer:
62
- answer = "0"
63
-
64
- return answer
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  except Exception as e:
67
- print("Agent execution error:", e)
68
- return f"Error occurred: {e}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  import gradio as gr
3
  import requests
4
  import pandas as pd
5
+ import time
6
 
7
+ # --- Built-in Tool: Wikipedia Search using standard 'requests' ---
8
+ def search_wikipedia(query: str) -> str:
9
+ """A simple search tool using the Wikipedia API without extra libraries."""
10
+ print(f" -> Tool Executing Search for: {query}")
11
+ url = "https://en.wikipedia.org/w/api.php"
12
+ params = {
13
+ "action": "query",
14
+ "format": "json",
15
+ "list": "search",
16
+ "srsearch": query,
17
+ "utf8": 1,
18
+ "srlimit": 3 # Return top 3 snippets
19
+ }
20
+ try:
21
+ response = requests.get(url, params=params, timeout=5)
22
+ data = response.json()
23
+ snippets = [item['snippet'].replace('<span class="searchmatch">', '').replace('</span>', '') for item in data['query']['search']]
24
+ if not snippets:
25
+ return "Observation: No results found."
26
+ return "Observation: " + " | ".join(snippets)
27
+ except Exception as e:
28
+ return f"Observation: Search error - {e}"
29
 
30
  # --- Constants ---
31
  DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
32
 
33
+ # --- Vanilla Gemini ReAct Agent Definition ---
34
+ class GeminiReActAgent:
35
  def __init__(self):
36
+ self.api_key = os.getenv("GEMINI_API_KEY")
37
+ if not self.api_key:
38
  raise ValueError("GEMINI_API_KEY not set")
39
+
40
+ # Direct REST API endpoint for Gemini 2.5 Flash
41
+ self.url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent?key={self.api_key}"
42
+ print("Vanilla ReAct Gemini Agent initialized.")
43
 
44
+ def call_gemini(self, history) -> str:
45
+ """Helper to make direct HTTP requests to the Gemini API."""
46
+ payload = {
47
+ "contents": history,
48
+ "generationConfig": {
49
+ "temperature": 0.0,
50
+ # Tell Gemini to stop generating when it's time for an observation
51
+ "stopSequences": ["Observation:"]
52
+ }
53
+ }
54
+ try:
55
+ response = requests.post(self.url, json=payload, timeout=20)
56
+ response.raise_for_status()
57
+ data = response.json()
58
+ return data["candidates"][0]["content"]["parts"][0]["text"].strip()
59
+ except Exception as e:
60
+ print(f"Gemini API Error: {e}")
61
+ if hasattr(e, 'response') and e.response is not None:
62
+ print(e.response.text)
63
+ return "Error"
 
 
 
 
 
 
64
 
65
  def __call__(self, question: str) -> str:
66
  print(f"Agent processing question: {question[:50]}...")
67
 
68
+ system_instruction = """You are an expert assistant for the GAIA benchmark.
69
+ You must provide a short, factual, direct answer. No explanations.
70
+ You have access to a Wikipedia search tool to find current facts.
71
+
72
+ To use the tool, you MUST output exactly this format:
73
+ Thought: <your reasoning>
74
+ Action: Search
75
+ Action Input: <search query>
76
+
77
+ If you know the answer or have found it from the search, output exactly:
78
+ Thought: <final reasoning>
79
+ Final Answer: <the short, direct answer>"""
80
+
81
+ # Initialize conversation state
82
+ history = [
83
+ {"role": "user", "parts": [{"text": system_instruction + "\n\nQuestion: " + question}]}
84
+ ]
85
+
86
+ # The ReAct Loop (Max 5 iterations to prevent infinite loops)
87
+ for iteration in range(5):
88
+ time.sleep(1) # Pace requests to respect API limits
89
 
90
+ reply = self.call_gemini(history)
 
91
 
92
+ if reply == "Error":
93
+ return "0"
 
 
94
 
95
+ # Add model's reply to history
96
+ history.append({"role": "model", "parts": [{"text": reply}]})
97
+
98
+ # 1. Check if the model arrived at the final answer
99
+ if "Final Answer:" in reply:
100
+ answer = reply.split("Final Answer:")[-1].strip()
101
+ return answer if answer else "0"
102
+
103
+ # 2. Check if the model wants to use the Search tool
104
+ elif "Action: Search" in reply and "Action Input:" in reply:
105
+ query_lines = [line for line in reply.split('\n') if "Action Input:" in line]
106
+ if query_lines:
107
+ query = query_lines[0].split("Action Input:")[-1].strip()
108
+ observation = search_wikipedia(query)
109
+
110
+ # Feed the search results back into the model's context
111
+ history.append({"role": "user", "parts": [{"text": observation}]})
112
+ continue
113
+
114
+ # 3. Fallback if the model breaks formatting
115
+ else:
116
+ history.append({
117
+ "role": "user",
118
+ "parts": [{"text": "Format error. Please use 'Action: Search' or 'Final Answer:'"}]
119
+ })
120
+
121
+ # Fallback if loops exhaust
122
+ return "0"
123
+
124
+ def run_and_submit_all(profile: gr.OAuthProfile | None):
125
+ # --- Determine HF Space Runtime URL and Repo URL ---
126
+ space_id = os.getenv("SPACE_ID")
127
+
128
+ if profile:
129
+ username = f"{profile.username}"
130
+ print(f"User logged in: {username}")
131
+ else:
132
+ print("User not logged in.")
133
+ return "Please Login to Hugging Face with the button.", None
134
+
135
+ api_url = DEFAULT_API_URL
136
+ questions_url = f"{api_url}/questions"
137
+ submit_url = f"{api_url}/submit"
138
+
139
+ # 1. Instantiate Agent
140
+ try:
141
+ agent = GeminiReActAgent()
142
+ except Exception as e:
143
+ print(f"Error instantiating agent: {e}")
144
+ return f"Error initializing agent: {e}", None
145
+
146
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
147
+ print(agent_code)
148
+
149
+ # 2. Fetch Questions
150
+ print(f"Fetching questions from: {questions_url}")
151
+ try:
152
+ response = requests.get(questions_url, timeout=15)
153
+ response.raise_for_status()
154
+ questions_data = response.json()
155
+ if not questions_data:
156
+ print("Fetched questions list is empty.")
157
+ return "Fetched questions list is empty or invalid format.", None
158
+ print(f"Fetched {len(questions_data)} questions.")
159
+ except requests.exceptions.RequestException as e:
160
+ print(f"Error fetching questions: {e}")
161
+ return f"Error fetching questions: {e}", None
162
+ except requests.exceptions.JSONDecodeError as e:
163
+ print(f"Error decoding JSON response from questions endpoint: {e}")
164
+ print(f"Response text: {response.text[:500]}")
165
+ return f"Error decoding server response for questions: {e}", None
166
+ except Exception as e:
167
+ print(f"An unexpected error occurred fetching questions: {e}")
168
+ return f"An unexpected error occurred fetching questions: {e}", None
169
+
170
+ # 3. Run your Agent
171
+ results_log = []
172
+ answers_payload = []
173
+ print(f"Running agent on {len(questions_data)} questions...")
174
+ for item in questions_data:
175
+ task_id = item.get("task_id")
176
+ question_text = item.get("question")
177
+ if not task_id or question_text is None:
178
+ print(f"Skipping item with missing task_id or question: {item}")
179
+ continue
180
+ try:
181
+ submitted_answer = agent(question_text)
182
+ answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
183
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
184
  except Exception as e:
185
+ print(f"Error running agent on task {task_id}: {e}")
186
+ results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
187
+
188
+ if not answers_payload:
189
+ print("Agent did not produce any answers to submit.")
190
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
191
+
192
+ # 4. Prepare Submission
193
+ submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload}
194
+ status_update = f"Agent finished. Submitting {len(answers_payload)} answers for user '{username}'..."
195
+ print(status_update)
196
+
197
+ # 5. Submit
198
+ print(f"Submitting {len(answers_payload)} answers to: {submit_url}")
199
+ try:
200
+ response = requests.post(submit_url, json=submission_data, timeout=60)
201
+ response.raise_for_status()
202
+ result_data = response.json()
203
+ final_status = (
204
+ f"Submission Successful!\n"
205
+ f"User: {result_data.get('username')}\n"
206
+ f"Overall Score: {result_data.get('score', 'N/A')}% "
207
+ f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n"
208
+ f"Message: {result_data.get('message', 'No message received.')}"
209
+ )
210
+ print("Submission successful.")
211
+ results_df = pd.DataFrame(results_log)
212
+ return final_status, results_df
213
+ except requests.exceptions.HTTPError as e:
214
+ error_detail = f"Server responded with status {e.response.status_code}."
215
+ try:
216
+ error_json = e.response.json()
217
+ error_detail += f" Detail: {error_json.get('detail', e.response.text)}"
218
+ except requests.exceptions.JSONDecodeError:
219
+ error_detail += f" Response: {e.response.text[:500]}"
220
+ status_message = f"Submission Failed: {error_detail}"
221
+ print(status_message)
222
+ results_df = pd.DataFrame(results_log)
223
+ return status_message, results_df
224
+ except requests.exceptions.Timeout:
225
+ status_message = "Submission Failed: The request timed out."
226
+ print(status_message)
227
+ results_df = pd.DataFrame(results_log)
228
+ return status_message, results_df
229
+ except requests.exceptions.RequestException as e:
230
+ status_message = f"Submission Failed: Network error - {e}"
231
+ print(status_message)
232
+ results_df = pd.DataFrame(results_log)
233
+ return status_message, results_df
234
+ except Exception as e:
235
+ status_message = f"An unexpected error occurred during submission: {e}"
236
+ print(status_message)
237
+ results_df = pd.DataFrame(results_log)
238
+ return status_message, results_df
239
+
240
+ # --- Build Gradio Interface using Blocks ---
241
+ with gr.Blocks() as demo:
242
+ gr.Markdown("# Gemini Agent Evaluation Runner")
243
+ gr.Markdown(
244
+ """
245
+ **Instructions:**
246
+ 1. Please clone this space, then modify the code to define your agent's logic, the tools, the necessary packages, etc ...
247
+ 2. Log in to your Hugging Face account using the button below. This uses your HF username for submission.
248
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your agent, submit answers, and see the score.
249
+ ---
250
+ **Disclaimers:**
251
+ 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).
252
+ 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.
253
+ """
254
+ )
255
+ gr.LoginButton()
256
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
257
+ status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
258
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
259
+ run_button.click(
260
+ fn=run_and_submit_all,
261
+ outputs=[status_output, results_table]
262
+ )
263
+
264
+ if __name__ == "__main__":
265
+ print("\n" + "-"*30 + " App Starting " + "-"*30)
266
+ space_host_startup = os.getenv("SPACE_HOST")
267
+ space_id_startup = os.getenv("SPACE_ID")
268
+
269
+ if space_host_startup:
270
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
271
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
272
+ else:
273
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
274
+
275
+ if space_id_startup:
276
+ print(f"✅ SPACE_ID found: {space_id_startup}")
277
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
278
+ print(f" Repo Tree URL: https://huggingface.co/spaces/{space_id_startup}/tree/main")
279
+ else:
280
+ print("ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL cannot be determined.")
281
+ print("-"*(60 + len(" App Starting ")) + "\n")
282
+ print("Launching Gradio Interface for Gemini Agent Evaluation...")
283
+ demo.launch(debug=True, share=False)