Mehedi2 commited on
Commit
cdbaf96
·
verified ·
1 Parent(s): 4dcf91a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +126 -207
app.py CHANGED
@@ -1,222 +1,141 @@
1
  import os
2
- import re
3
- import json
4
- import requests
 
5
  import pandas as pd
6
- from pathlib import Path
7
- from typing import Optional
8
  from dotenv import load_dotenv
9
- import inspect
10
- import gradio as gr
11
-
12
- from langgraph.prebuilt import create_react_agent
13
- from langchain_core.messages import HumanMessage
14
- from langchain_core.tools import tool
15
- from langchain_openai import ChatOpenAI
16
 
17
  load_dotenv()
18
 
19
- # ------------------ LLM ------------------
20
- class OpenRouterLLM(ChatOpenAI):
21
- """Custom OpenRouter LLM wrapper for LangGraph"""
22
- def __init__(self, model: str = "deepseek/deepseek-v3.1-terminus", **kwargs):
23
- api_key = os.getenv("OPENROUTER_API_KEY")
24
- if not api_key:
25
- raise ValueError("OPENROUTER_API_KEY not set in environment variables.")
26
- super().__init__(
27
- model=model,
28
- openai_api_key=api_key,
29
- openai_api_base="https://openrouter.ai/api/v1",
30
- **kwargs
31
- )
32
-
33
- # ------------------ TOOLS ------------------
34
-
35
- SERPAPI_KEY = os.getenv("SERPAPI_KEY")
36
-
37
- @tool
38
- def search_web(query: str) -> str:
39
- """Perform a reliable web search using SerpAPI."""
40
- if not SERPAPI_KEY:
41
- return "Error: SERPAPI_KEY not set."
42
- search_url = "https://serpapi.com/search.json"
43
- params = {"q": query, "api_key": SERPAPI_KEY, "num": 3}
44
- try:
45
- response = requests.get(search_url, params=params, timeout=10)
46
- response.raise_for_status()
47
- data = response.json()
48
- results = []
49
- for item in data.get("organic_results", []):
50
- title = item.get("title", "")
51
- snippet = item.get("snippet", "")
52
- link = item.get("link", "")
53
- results.append(f"{title}\n{snippet}\n{link}")
54
- return "\n\n".join(results) if results else f"No results for '{query}'."
55
- except Exception as e:
56
- return f"Web search error: {str(e)}"
57
 
58
- @tool
59
- def search_wikipedia(query: str) -> str:
60
- """Retrieve full Wikipedia article text."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  try:
62
- url = f"https://en.wikipedia.org/w/api.php"
63
- params = {
64
- "action": "query",
65
- "format": "json",
66
- "prop": "extracts",
67
- "explaintext": True,
68
- "titles": query
69
- }
70
- response = requests.get(url, params=params, timeout=10)
71
- response.raise_for_status()
72
- pages = response.json()["query"]["pages"]
73
- text = next(iter(pages.values())).get("extract", "")
74
- if not text:
75
- return f"No Wikipedia content found for '{query}'."
76
- return text[:2000] # truncate if too long
77
  except Exception as e:
78
- return f"Wikipedia search error: {str(e)}"
 
79
 
80
- @tool
81
- def execute_python(code: str) -> str:
82
- """Execute Python code safely and return output."""
83
  try:
84
- safe_globals = {
85
- '__builtins__': {
86
- 'print': print, 'len': len, 'str': str, 'int': int, 'float': float,
87
- 'bool': bool, 'list': list, 'dict': dict, 'tuple': tuple, 'set': set,
88
- 'range': range, 'sum': sum, 'max': max, 'min': min, 'abs': abs,
89
- 'round': round, 'sorted': sorted, 'enumerate': enumerate, 'zip': zip,
90
- },
91
- 'math': __import__('math'),
92
- 'json': __import__('json'),
93
- 'datetime': __import__('datetime'),
94
- 'random': __import__('random'),
95
- }
96
- import io, sys
97
- old_stdout = sys.stdout
98
- sys.stdout = mystdout = io.StringIO()
99
- try:
100
- exec(code, safe_globals)
101
- output = mystdout.getvalue()
102
- finally:
103
- sys.stdout = old_stdout
104
- return output if output else "Code executed successfully (no output)"
105
  except Exception as e:
106
- return f"Python execution error: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
- @tool
109
- def read_excel_file(file_path: str, sheet_name: Optional[str] = None) -> str:
110
- """Read an Excel file and return contents."""
111
- try:
112
- file_path_obj = Path(file_path)
113
- if not file_path_obj.exists():
114
- return f"Error: File not found at {file_path}"
115
- if sheet_name and sheet_name.isdigit():
116
- sheet_name = int(sheet_name)
117
- elif sheet_name is None:
118
- sheet_name = 0
119
- df = pd.read_excel(file_path, sheet_name=sheet_name)
120
- if len(df) > 20:
121
- result = f"Excel file with {len(df)} rows and {len(df.columns)} columns:\n\n"
122
- result += "First 10 rows:\n" + df.head(10).to_string(index=False)
123
- result += f"\n\n... ({len(df) - 20} rows omitted) ...\n\n"
124
- result += "Last 10 rows:\n" + df.tail(10).to_string(index=False)
125
- else:
126
- result = f"Excel file with {len(df)} rows and {len(df.columns)} columns:\n\n"
127
- result += df.to_string(index=False)
128
- return result
129
- except Exception as e:
130
- return f"Error reading Excel file: {str(e)}"
131
-
132
- @tool
133
- def read_text_file(file_path: str) -> str:
134
- """Read a text file and return contents."""
135
- try:
136
- file_path_obj = Path(file_path)
137
- if not file_path_obj.exists():
138
- return f"Error: File not found at {file_path}"
139
- encodings = ['utf-8', 'utf-16', 'iso-8859-1', 'cp1252']
140
- for encoding in encodings:
141
- try:
142
- with open(file_path_obj, 'r', encoding=encoding) as f:
143
- return f.read()
144
- except UnicodeDecodeError:
145
- continue
146
- return "Error: Could not decode file with any standard encoding"
147
- except Exception as e:
148
- return f"Error reading file: {str(e)}"
149
-
150
- # ------------------ GAIA AGENT ------------------
151
- class GaiaAgent:
152
- """LangGraph-based agent with DeepSeek and enhanced tools."""
153
- def __init__(self):
154
- print("Initializing GaiaAgent with LangGraph and OpenRouter DeepSeek...")
155
- self.llm = OpenRouterLLM(
156
- model="deepseek/deepseek-v3.1-terminus",
157
- temperature=0.1,
158
- max_tokens=2000
159
  )
160
- self.tools = [search_web, search_wikipedia, execute_python, read_excel_file, read_text_file]
161
- prompt_modifier = self._get_system_prompt()
162
-
163
- # Detect correct kwarg for your LangGraph version
164
- sig = inspect.signature(create_react_agent)
165
- accepted = sig.parameters.keys()
166
- kwargs = {}
167
- if "messages_modifier" in accepted:
168
- kwargs["messages_modifier"] = prompt_modifier
169
- elif "state_modifier" in accepted:
170
- kwargs["state_modifier"] = prompt_modifier
171
- elif "prompt" in accepted:
172
- kwargs["prompt"] = prompt_modifier
173
-
174
- self.agent = create_react_agent(self.llm, self.tools, **kwargs)
175
- print("GaiaAgent initialized successfully!")
176
-
177
- def _get_system_prompt(self) -> str:
178
- return """You are an advanced AI agent designed to answer complex questions using all available tools, including web search, Wikipedia, Python execution, Excel and text file reading."""
179
-
180
- def __call__(self, task_id: str, question: str) -> str:
181
- try:
182
- print(f"Processing task {task_id}: {question[:100]}...")
183
- # Combine context from tools for better answers
184
- wiki_text = search_wikipedia(question)
185
- web_text = search_web(question)
186
- combined_input = f"{wiki_text}\n\n{web_text}\n\nQuestion: {question}"
187
- messages = [HumanMessage(content=combined_input)]
188
- result = self.agent.invoke({"messages": messages})
189
- final_message = result["messages"][-1]
190
- answer = final_message.content
191
- return self._clean_answer(answer)
192
- except Exception as e:
193
- return f"Agent error: {e}"
194
-
195
- def _clean_answer(self, answer: str) -> str:
196
- answer = answer.strip()
197
- if "final answer:" in answer.lower():
198
- parts = re.split(r'final answer:', answer, flags=re.IGNORECASE)
199
- if len(parts) > 1:
200
- answer = parts[-1].strip()
201
- prefixes = ["The answer is", "Answer:", "Result:", "Solution:",
202
- "Based on", "Therefore", "In conclusion", "So the answer is"]
203
- for prefix in prefixes:
204
- if answer.lower().startswith(prefix.lower()):
205
- answer = answer[len(prefix):].strip()
206
- if answer.startswith(':'):
207
- answer = answer[1:].strip()
208
- break
209
- if len(answer.split()) <= 3:
210
- answer = answer.strip('"\'.')
211
- return answer
212
-
213
- # ------------------ GRADIO INTERFACE ------------------
214
- agent = GaiaAgent()
215
-
216
- def run_agent(prompt: str) -> str:
217
- return agent("gaia_task", prompt)
218
-
219
- demo = gr.Interface(fn=run_agent, inputs="text", outputs="text", title="GAIA Agent")
220
 
221
- if __name__ == "__main__":
222
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
1
  import os
2
+
3
+ import agent
4
+ import gradio as gr
5
+ import logic
6
  import pandas as pd
 
 
7
  from dotenv import load_dotenv
 
 
 
 
 
 
 
8
 
9
  load_dotenv()
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ def run_and_submit_all(
13
+ profile: gr.OAuthProfile | None,
14
+ ) -> tuple[str, pd.DataFrame | None]:
15
+ """Fetches all questions, runs the BasicAgent on them, submits all answers,
16
+ and displays the results.
17
+
18
+ Args:
19
+ profile: An optional gr.OAuthProfile object containing user information
20
+ if the user is logged in. If None, the user is not logged in.
21
+
22
+ Returns:
23
+ tuple[str, pd.DataFrame | None]: A tuple containing:
24
+ - A string representing the status of the run and submission process.
25
+ This could be a success message, an error message, or a message
26
+ indicating that no answers were produced.
27
+ - A pandas DataFrame containing the results log. This DataFrame will
28
+ be displayed in the Gradio interface. It can be None if an error
29
+ occurred before the agent was run.
30
+ """
31
+ # 0. Get user details
32
+ space_id = os.getenv("SPACE_ID")
33
+ agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
34
+ print(agent_code)
35
+ if profile:
36
+ username = f"{profile.username}"
37
+ print(f"User logged in: {username}")
38
+ else:
39
+ print("User not logged in.")
40
+ return "Please Login to Hugging Face with the button.", None
41
+
42
+ # 1. Instantiate Agent
43
  try:
44
+ gaia_agent = agent.GaiaAgent()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  except Exception as e:
46
+ print(f"Error instantiating agent: {e}")
47
+ return f"Error initializing agent: {e}", None
48
 
49
+ # 2. Fetch Questions
 
 
50
  try:
51
+ questions_data = logic.fetch_all_questions()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  except Exception as e:
53
+ return str(e), None
54
+
55
+ # 3. Run the Agent
56
+ results_log, answers_payload = logic.run_agent(gaia_agent, questions_data)
57
+ if not answers_payload:
58
+ print("Agent did not produce any answers to submit.")
59
+ return "Agent did not produce any answers to submit.", pd.DataFrame(results_log)
60
+
61
+ # 4. Prepare & Submit Answers
62
+ submission_data = {
63
+ "username": username.strip(),
64
+ "agent_code": agent_code,
65
+ "answers": answers_payload,
66
+ }
67
+ print(
68
+ f"Agent finished. Submitting {len(answers_payload)} answers for user '"
69
+ f"{username}'..."
70
+ )
71
+ return logic.submit_answers(submission_data, results_log)
72
+
73
+
74
+ # --- Build Gradio Interface using Blocks ---
75
+ with gr.Blocks() as gaia_ui:
76
+ gr.Markdown("# Basic Agent Evaluation Runner")
77
+ gr.Markdown(
78
+ """
79
+ **Instructions:**
80
+
81
+ 1. Please clone this space, then modify the code to define your agent's
82
+ logic, the tools, the necessary packages, etc ...
83
+ 2. Log in to your Hugging Face account using the button below. This uses
84
+ your HF username for submission.
85
+ 3. Click 'Run Evaluation & Submit All Answers' to fetch questions, run your
86
+ agent, submit answers, and see the score.
87
+
88
+ ---
89
+ **Disclaimers:**
90
+ Once clicking on the "submit button, it can take quite some time ( this is
91
+ the time for the agent to go through all the questions).
92
+ This space provides a basic setup and is intentionally sub-optimal to
93
+ encourage you to develop your own, more robust solution. For instance for the
94
+ delay process of the submit button, a solution could be to cache the answers
95
+ and submit in a separate action or even to answer the questions in async.
96
+ """
97
+ )
98
+
99
+ gr.LoginButton()
100
+
101
+ run_button = gr.Button("Run Evaluation & Submit All Answers")
102
+
103
+ status_output = gr.Textbox(
104
+ label="Run Status / Submission Result", lines=5, interactive=False
105
+ )
106
+ # Removed max_rows=10 from DataFrame constructor
107
+ results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
108
+
109
+ run_button.click(
110
+ fn=run_and_submit_all, inputs=None, outputs=[status_output, results_table]
111
+ )
112
 
113
+ if __name__ == "__main__":
114
+ print("\n" + "-" * 30 + " App Starting " + "-" * 30)
115
+ # Check for SPACE_HOST and SPACE_ID at startup for information
116
+ space_host_startup = os.getenv("SPACE_HOST")
117
+ space_id_startup = os.getenv("SPACE_ID") # Get SPACE_ID at startup
118
+
119
+ if space_host_startup:
120
+ print(f"✅ SPACE_HOST found: {space_host_startup}")
121
+ print(f" Runtime URL should be: https://{space_host_startup}.hf.space")
122
+ else:
123
+ print("ℹ️ SPACE_HOST environment variable not found (running locally?).")
124
+
125
+ if space_id_startup: # Print repo URLs if SPACE_ID is found
126
+ print(f" SPACE_ID found: {space_id_startup}")
127
+ print(f" Repo URL: https://huggingface.co/spaces/{space_id_startup}")
128
+ print(
129
+ f" Repo Tree URL: https://huggingface.co/spaces/"
130
+ f"{space_id_startup}/tree/main"
131
+ )
132
+ else:
133
+ print(
134
+ "ℹ️ SPACE_ID environment variable not found (running locally?). Repo URL "
135
+ "cannot be determined."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
+ print("-" * (60 + len(" App Starting ")) + "\n")
139
+
140
+ print("Launching Gradio Interface for Basic Agent Evaluation...")
141
+ gaia_ui.launch(debug=True, share=True)