osma77 commited on
Commit
2024f4f
·
verified ·
1 Parent(s): 39ad83f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +2 -431
app.py CHANGED
@@ -69,8 +69,8 @@ class BasicAgent:
69
  self.tools = [
70
  WikipediaSearchTool(),
71
  # DuckDuckGoSearchTool(),
72
- PythonInterpreterTool(),
73
- VisitWebpageTool()
74
  ]
75
 
76
  # Create CodeAgent
@@ -117,435 +117,6 @@ class BasicAgent:
117
 
118
 
119
 
120
-
121
- # # from langgraph.gr import StateGraph, END
122
- # from langgraph.graph import StateGraph, END
123
- # from langchain_core.messages import HumanMessage, AIMessage
124
- # from langchain_openai import AzureChatOpenAI
125
- # from langchain_community.tools import WikipediaQueryRun, DuckDuckGoSearchRun
126
- # from langchain_community.utilities import WikipediaAPIWrapper, DuckDuckGoSearchAPIWrapper
127
- # from langchain_experimental.tools import PythonREPLTool
128
- # from langchain_core.tools import tool
129
- # import os
130
- # import math
131
- # import numpy as np
132
- # import re
133
- # from typing import Optional, Dict, Any, List
134
- # from langchain_core.agents import AgentAction, AgentFinish
135
-
136
- # class BasicAgent:
137
- # def __init__(self, model_id: Optional[str] = None, api_key: Optional[str] = None):
138
- # """
139
- # Initialize BasicAgent optimized for GAIA benchmark success.
140
- # """
141
-
142
- # # Initialize model
143
- # self.model = AzureChatOpenAI(
144
- # deployment_name="o3-mini",
145
- # azure_endpoint=os.environ.get("AZURE_OPENAI_ENDPOINT"),
146
- # api_key=os.environ.get("AZURE_OPENAI_API_KEY"),
147
- # api_version="2024-12-01-preview"
148
- # )
149
-
150
- # # Initialize tools
151
- # self.tools = self._initialize_tools()
152
-
153
- # # Create LangGraph workflow
154
- # self.workflow = self._create_workflow()
155
- # self.app = self.workflow.compile()
156
-
157
- # def _initialize_tools(self):
158
- # """Initialize tools with GAIA-specific optimizations."""
159
-
160
- # @tool
161
- # def web_search(query: str) -> str:
162
- # """
163
- # Search for current information on the web. Use specific, targeted queries.
164
- # Best for: recent events, current data, specific facts, news.
165
- # """
166
- # try:
167
- # ddg = DuckDuckGoSearchAPIWrapper(max_results=5)
168
- # results = ddg.run(query)
169
- # return results[:1500]
170
- # except Exception as e:
171
- # return f"Search failed: {str(e)}"
172
-
173
- # @tool
174
- # def wikipedia_search(query: str) -> str:
175
- # """
176
- # Search Wikipedia for established facts, definitions, historical data.
177
- # Best for: biographical info, historical events, scientific concepts, definitions.
178
- # """
179
- # try:
180
- # wiki = WikipediaAPIWrapper(top_k_results=2, doc_content_chars_max=1000)
181
- # result = wiki.run(query)
182
- # return result
183
- # except Exception as e:
184
- # return f"Wikipedia search failed: {str(e)}"
185
-
186
- # @tool
187
- # def python_calculator(code: str) -> str:
188
- # """
189
- # Execute Python code for calculations, data processing, file operations.
190
- # Best for: complex math, data analysis, file processing, calculations.
191
- # Always include print() statements to see results.
192
- # """
193
- # try:
194
- # # Enhanced Python environment
195
- # exec_globals = {
196
- # '__builtins__': __builtins__,
197
- # 'math': math,
198
- # 'np': np,
199
- # 'numpy': np,
200
- # 'pd': None, # Will try to import if needed
201
- # 'os': os,
202
- # 're': re
203
- # }
204
-
205
- # # Try to import common libraries
206
- # try:
207
- # import pandas as pd
208
- # exec_globals['pd'] = pd
209
- # exec_globals['pandas'] = pd
210
- # except:
211
- # pass
212
-
213
- # # Capture output
214
- # import io
215
- # import sys
216
- # old_stdout = sys.stdout
217
- # sys.stdout = captured_output = io.StringIO()
218
-
219
- # # Execute code
220
- # exec(code, exec_globals)
221
-
222
- # # Get output
223
- # sys.stdout = old_stdout
224
- # output = captured_output.getvalue()
225
-
226
- # return output if output.strip() else "Code executed successfully (no output)"
227
-
228
- # except Exception as e:
229
- # return f"Python execution error: {str(e)}"
230
-
231
- # @tool
232
- # def simple_math(expression: str) -> str:
233
- # """
234
- # Evaluate simple mathematical expressions quickly.
235
- # Best for: basic arithmetic, simple calculations.
236
- # Examples: "2+3*4", "sqrt(16)", "sin(pi/4)"
237
- # """
238
- # try:
239
- # # Safe evaluation environment
240
- # allowed_names = {
241
- # k: v for k, v in math.__dict__.items() if not k.startswith("__")
242
- # }
243
- # allowed_names.update({
244
- # "abs": abs, "round": round, "min": min, "max": max,
245
- # "sum": sum, "pow": pow, "divmod": divmod
246
- # })
247
-
248
- # result = eval(expression, {"__builtins__": {}}, allowed_names)
249
- # return str(result)
250
- # except Exception as e:
251
- # return f"Math error: {str(e)}"
252
-
253
- # @tool
254
- # def file_analyzer(task: str) -> str:
255
- # """
256
- # Analyze files in the current directory.
257
- # Best for: examining uploaded files, extracting data from files.
258
- # """
259
- # try:
260
- # # List available files
261
- # files = [f for f in os.listdir('.') if os.path.isfile(f)]
262
-
263
- # result = f"Available files: {files}\n"
264
- # result += f"Task: {task}\n"
265
- # result += "Use python_calculator for detailed file processing."
266
-
267
- # return result
268
- # except Exception as e:
269
- # return f"File analysis error: {str(e)}"
270
-
271
- # return [
272
- # # web_search,
273
- # wikipedia_search, python_calculator
274
- # # , simple_math
275
- # # , file_analyzer
276
- # ]
277
-
278
- # def _create_workflow(self):
279
- # """Create optimized LangGraph workflow."""
280
- # workflow = StateGraph(dict)
281
-
282
- # workflow.add_node("planner", self._planner_node)
283
- # workflow.add_node("executor", self._executor_node)
284
- # workflow.add_node("validator", self._validator_node)
285
-
286
- # workflow.set_entry_point("planner")
287
-
288
- # workflow.add_conditional_edges(
289
- # "planner",
290
- # self._plan_decision,
291
- # {
292
- # "execute": "executor",
293
- # "final": "validator"
294
- # }
295
- # )
296
-
297
- # workflow.add_conditional_edges(
298
- # "executor",
299
- # self._execution_decision,
300
- # {
301
- # "continue": "planner",
302
- # "validate": "validator"
303
- # }
304
- # )
305
-
306
- # workflow.add_edge("validator", END)
307
-
308
- # return workflow
309
-
310
- # def _planner_node(self, state: Dict[str, Any]) -> Dict[str, Any]:
311
- # """Enhanced planning node focused on GAIA success patterns."""
312
- # messages = state.get("messages", [])
313
- # step_count = state.get("step_count", 0)
314
- # max_steps = state.get("max_steps", 4)
315
- # plan_history = state.get("plan_history", [])
316
-
317
- # if step_count >= max_steps:
318
- # return {
319
- # **state,
320
- # "final_answer": "Maximum steps reached. Providing best available answer.",
321
- # "action_type": "final"
322
- # }
323
-
324
- # planning_prompt = f"""
325
- # You are a general AI assistant. I will ask you a question.
326
- # Report your thoughts, and finish your answer with the following template:
327
- # FINAL ANSWER: [YOUR FINAL ANSWER]. YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
328
- # If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
329
- # If you are asked for a string, don't use articles,
330
- # neither abbreviations (e.g. for cities),
331
- # and write the digits in plain text unless specified otherwise.
332
- # If you are asked for a comma separated list,
333
- # apply the above rules depending of whether the element to be put in the list is a number or a string.
334
-
335
- # QUESTION: {messages[0]['content'] if messages else 'No question provided'}
336
-
337
- # EXECUTION HISTORY: {plan_history}\n
338
-
339
- # RÈGLES ABSOLUES:
340
- # 1. Lis la question 3 fois avant de commencer
341
- # 2. Décompose TOUJOURS la question en sous-problèmes identifiables
342
- # 3. Vérifie CHAQUE information avec au moins 2 sources différentes
343
- # 4. Pour les calculs: utilise OBLIGATOIREMENT Python pour tous les calculs numériques
344
- # 5. Pour les dates: vérifie l'année actuelle (nous sommes en 2025)
345
- # 6. JAMAIS de réponse approximative - sois précis au maximum
346
-
347
- # PROCESSUS OBLIGATOIRE:
348
- # 1. ANALYSE: Que demande exactement la question? Quel type de réponse?
349
- # 2. RECHERCHE: Quelles informations spécifiques me manquent?
350
- # 3. VÉRIFICATION: Les sources sont-elles cohérentes entre elles?
351
- # 4. CALCUL: Si nécessaire, utilise Python pour calculs précis
352
- # 5. SYNTHÈSE: Donne une réponse finale précise et concise
353
-
354
- # FORMAT DE RÉPONSE FINAL:
355
- # - Si c'est un nombre: donne UNIQUEMENT le nombre (ex: "42")
356
- # - Si c'est un nom: donne UNIQUEMENT le nom (ex: "Paris")
357
- # - Si c'est une date: format précis demandé
358
- # - Pas d'explication supplémentaire dans la réponse finale
359
- # """
360
-
361
- # response = self.model.invoke([{"role": "system", "content": planning_prompt}])
362
- # content = response.content.strip()
363
-
364
- # if content.startswith("FINAL:"):
365
- # answer = content.replace("FINAL:", "").strip()
366
- # return {
367
- # **state,
368
- # "final_answer": answer,
369
- # "action_type": "final",
370
- # "step_count": step_count
371
- # }
372
- # elif content.startswith("EXECUTE:"):
373
- # # Parse execution command
374
- # try:
375
- # parts = content.replace("EXECUTE:", "").split("|")
376
- # tool_name = parts[0].split()[0].strip()
377
- # input_part = [p for p in parts if p.strip().startswith("INPUT:")][0]
378
- # tool_input = input_part.replace("INPUT:", "").strip()
379
- # goal_part = [p for p in parts if p.strip().startswith("GOAL:")][0] if len(parts) > 2 else ""
380
- # goal = goal_part.replace("GOAL:", "").strip() if goal_part else ""
381
-
382
- # return {
383
- # **state,
384
- # "current_tool": tool_name,
385
- # "current_input": tool_input,
386
- # "current_goal": goal,
387
- # "action_type": "execute",
388
- # "step_count": step_count + 1
389
- # }
390
- # except Exception as e:
391
- # return {
392
- # **state,
393
- # "final_answer": f"Planning error: {str(e)}",
394
- # "action_type": "final"
395
- # }
396
- # else:
397
- # return {
398
- # **state,
399
- # "final_answer": content,
400
- # "action_type": "final"
401
- # }
402
-
403
- # def _executor_node(self, state: Dict[str, Any]) -> Dict[str, Any]:
404
- # """Execute the planned action."""
405
- # tool_name = state.get("current_tool", "")
406
- # tool_input = state.get("current_input", "")
407
- # goal = state.get("current_goal", "")
408
- # plan_history = state.get("plan_history", [])
409
-
410
- # # Find and execute tool
411
- # tool_map = {tool.name: tool for tool in self.tools}
412
-
413
- # # Add flexible matching
414
- # tool_matches = {
415
- # # "web_search": ["web", "search", "google", "internet"],
416
- # "wikipedia_search": ["wiki", "wikipedia"],
417
- # "python_calculator": ["python", "code", "calc", "calculate"],
418
- # # "simple_math": ["math", "arithmetic"],
419
- # # "file_analyzer": ["file", "analyze"]
420
- # }
421
-
422
- # matched_tool = None
423
- # for tool_real_name, aliases in tool_matches.items():
424
- # if tool_name.lower() in aliases or tool_name.lower() == tool_real_name.lower():
425
- # matched_tool = tool_map.get(tool_real_name)
426
- # break
427
-
428
- # if not matched_tool:
429
- # matched_tool = tool_map.get(tool_name)
430
-
431
- # if matched_tool:
432
- # try:
433
- # result = matched_tool.run(tool_input)
434
- # execution_record = f"STEP: Used {tool_name} with '{tool_input}' -> {result[:200]}..."
435
- # plan_history.append(execution_record)
436
-
437
- # return {
438
- # **state,
439
- # "last_result": result,
440
- # "plan_history": plan_history,
441
- # "action_type": "continue"
442
- # }
443
- # except Exception as e:
444
- # error_msg = f"Tool {tool_name} failed: {str(e)}"
445
- # plan_history.append(f"ERROR: {error_msg}")
446
- # return {
447
- # **state,
448
- # "last_result": error_msg,
449
- # "plan_history": plan_history,
450
- # "action_type": "validate"
451
- # }
452
- # else:
453
- # available = list(tool_map.keys())
454
- # error_msg = f"Tool '{tool_name}' not found. Available: {available}"
455
- # plan_history.append(f"ERROR: {error_msg}")
456
- # return {
457
- # **state,
458
- # "last_result": error_msg,
459
- # "plan_history": plan_history,
460
- # "action_type": "validate"
461
- # }
462
-
463
- # def _validator_node(self, state: Dict[str, Any]) -> Dict[str, Any]:
464
- # """Validate and finalize the answer."""
465
- # final_answer = state.get("final_answer", "")
466
- # plan_history = state.get("plan_history", [])
467
- # last_result = state.get("last_result", "")
468
-
469
- # if not final_answer and last_result:
470
- # # Extract answer from last result
471
- # validation_prompt = f"""Extract the EXACT answer from this result for the GAIA question.
472
-
473
- # QUESTION: {state.get('messages', [{}])[0].get('content', '')}
474
- # TOOL RESULT: {last_result}
475
-
476
- # Provide ONLY the precise answer - no explanations, no context, just the exact answer required.
477
- # Examples:
478
- # - If asked for a number: "42"
479
- # - If asked for a name: "John Smith"
480
- # - If asked for a date: "1969"
481
- # - If asked for a yes/no: "Yes"
482
-
483
- # EXACT ANSWER:"""
484
-
485
- # response = self.model.invoke([{"role": "user", "content": validation_prompt}])
486
- # final_answer = response.content.strip()
487
-
488
- # # Clean up the answer
489
- # final_answer = self._clean_answer(final_answer)
490
-
491
- # return {
492
- # **state,
493
- # "final_answer": final_answer,
494
- # "completed": True
495
- # }
496
-
497
- # def _clean_answer(self, answer: str) -> str:
498
- # """Clean and format the final answer for GAIA."""
499
- # if not answer:
500
- # return "No answer found"
501
-
502
- # # Remove common prefixes
503
- # prefixes = [
504
- # "the answer is", "answer:", "final answer:", "result:",
505
- # "exact answer:", "solution:", "response:", "output:"
506
- # ]
507
-
508
- # cleaned = answer.strip()
509
- # for prefix in prefixes:
510
- # if cleaned.lower().startswith(prefix):
511
- # cleaned = cleaned[len(prefix):].strip()
512
-
513
- # # Remove quotes if they wrap the entire answer
514
- # if cleaned.startswith('"') and cleaned.endswith('"'):
515
- # cleaned = cleaned[1:-1]
516
- # if cleaned.startswith("'") and cleaned.endswith("'"):
517
- # cleaned = cleaned[1:-1]
518
-
519
- # return cleaned
520
-
521
- # def _plan_decision(self, state: Dict[str, Any]) -> str:
522
- # """Decide whether to execute or finalize."""
523
- # return state.get("action_type", "execute")
524
-
525
- # def _execution_decision(self, state: Dict[str, Any]) -> str:
526
- # """Decide next step after execution."""
527
- # return state.get("action_type", "continue")
528
-
529
- # def run(self, question: str, max_steps: int = 4) -> str:
530
- # """
531
- # Run the agent with GAIA-optimized settings.
532
- # """
533
- # initial_state = {
534
- # "messages": [{"role": "user", "content": question}],
535
- # "step_count": 0,
536
- # "max_steps": max_steps,
537
- # "plan_history": [],
538
- # "completed": False
539
- # }
540
-
541
- # try:
542
- # result = self.app.invoke(initial_state)
543
- # return result.get("final_answer", "No answer generated")
544
-
545
- # except Exception as e:
546
- # return f"Error: {str(e)}"
547
-
548
-
549
 
550
 
551
 
 
69
  self.tools = [
70
  WikipediaSearchTool(),
71
  # DuckDuckGoSearchTool(),
72
+ # PythonInterpreterTool(),
73
+ # VisitWebpageTool()
74
  ]
75
 
76
  # Create CodeAgent
 
117
 
118
 
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
 
122