az1fr3's picture
Update app.py
7a60cf2 verified
import os
import sys
import requests
import json
import traceback
from datetime import datetime
import re
import markdownify
import wikipediaapi
import trafilatura
import gradio as gr
import pandas as pd
import time
from smolagents import CodeAgent, LiteLLMModel, tool, DuckDuckGoSearchTool, FinalAnswerTool
@tool
def get_wikipedia_article(search_query: str) -> str:
"""
Searches for a Wikipedia article by its exact title or a close topic and returns its full, clean content.
This is the preferred tool for questions that likely have a Wikipedia page.
Args:
search_query (str): The title or main subject to search for on Wikipedia (e.g., "Mercedes Sosa").
"""
print(f"--- Herramienta: Buscando en Wikipedia: '{search_query}' ---")
try:
wiki_wiki = wikipediaapi.Wikipedia(
language='en',
user_agent='GAIA-Agent-Course-Test/1.0 (tu_email@ejemplo.com)'
)
page = wiki_wiki.page(search_query)
if page.exists():
print(f"--- Herramienta: Página de Wikipedia encontrada: '{page.title}' ---")
return page.text
else:
return f"Error: La página de Wikipedia para '{search_query}' no fue encontrada."
except Exception as e:
return f"An error occurred while fetching from Wikipedia: {e}"
@tool
def visit_and_get_html(url: str) -> str:
"""
Visits a webpage using robust headers and returns its raw HTML content for further processing.
Args:
url (str): The URL of the webpage to visit.
"""
print(f"--- Herramienta: Visitando URL {url} para obtener HTML ---")
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.9',
'Referer': 'https://www.google.com/',
}
response = requests.get(url, headers=headers, timeout=20)
response.raise_for_status()
return response.text
except requests.exceptions.RequestException as e:
error_message = f"Error fetching the webpage {url}: {e}"
print(error_message)
return error_message
@tool
def extract_main_content(html_content: str) -> str:
"""
Extracts the main article text from raw HTML content, removing boilerplate like menus, ads, and footers.
Args:
html_content (str): The raw HTML of a webpage.
"""
print("--- Herramienta: Extrayendo contenido principal del HTML con Trafilatura... ---")
if not html_content or not isinstance(html_content, str) or "Error" in html_content:
return "Error: No valid HTML content provided to extract."
return trafilatura.extract(html_content)
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY")
os.environ["GEMINI_API_KEY"] = GEMINI_API_KEY
GEMINI_MODEL_ID = "gemini/gemini-1.5-flash-latest"
llm_provider = None
agente_principal = None
if GEMINI_API_KEY:
try:
llm_provider = LiteLLMModel(model_id=GEMINI_MODEL_ID, temperature=0.1, max_tokens=8192)
print(f"LLM ({GEMINI_MODEL_ID}) configurado para usar la API de Google a través de LiteLLM.")
agente_principal = CodeAgent(
model=llm_provider,
name="AgenteGAIA",
description="Soy un agente autónomo diseñado para resolver preguntas del benchmark GAIA. Utilizo mis herramientas para investigar y encontrar la respuesta correcta.",
tools=[
get_wikipedia_article,
DuckDuckGoSearchTool(),
visit_and_get_html,
extract_main_content,
FinalAnswerTool()
],
additional_authorized_imports=["re"],
verbosity_level=2,
max_steps=15
)
print("AgenteGAIA Principal inicializado.")
except Exception as e:
print(f"CRITICAL ERROR: No se pudo inicializar el agente o el LLM: {e}")
traceback.print_exc()
else:
print("CRITICAL ERROR: Clave API 'GEMINI_API_KEY' no se encontró en los Secrets del Space.")
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
def run_and_submit_all(profile: gr.OAuthProfile | None):
"""
Fetches all questions, runs `agente_principal` on them, submits the answers.
"""
if not profile:
return "Por favor, inicia sesión con tu perfil de Hugging Face.", pd.DataFrame()
if not agente_principal:
return "Error: El agente principal no está inicializado. Revisa los logs y la API Key.", pd.DataFrame()
username = profile.username
space_id = os.getenv("SPACE_ID")
code_link = f"https://huggingface.co/spaces/{space_id}" if space_id else "No se pudo obtener el link al Space."
print(f"Iniciando evaluación para el usuario: {username}")
# 1. Obtener todas las preguntas del examen
questions_url = f"{DEFAULT_API_URL}/questions"
try:
response = requests.get(questions_url)
response.raise_for_status()
all_questions = response.json()
print(f"Se obtuvieron {len(all_questions)} preguntas del examen.")
except Exception as e:
return f"Error al obtener las preguntas: {e}", pd.DataFrame()
# 2. Iterar, ejecutar el agente y recopilar respuestas
all_answers = []
results_for_display = []
gaia_rules_prompt = "1. Answer Format: Numbers must be plain digits. Strings must omit articles.\n2. Response Content: ONLY the final answer, without prefixes or explanations."
main_task_prompt_template = """
Your mission is to accurately answer the question "{question_text}" using your available tools and a robust, multi-step reasoning process.
**YOUR OVERALL PLAN:**
1. **STRATEGY - WIKIPEDIA FIRST:** Check if the question mentions 'Wikipedia' or is about a topic likely to have a detailed Wikipedia page. If so, your first attempt should be to use your `get_wikipedia_article` tool with a relevant search query.
2. **STRATEGY - WEB SEARCH FALLBACK:** If the Wikipedia tool fails or does not provide enough information, your code must then use the `DuckDuckGoSearchTool` to find alternative sources.
3. **INFORMATION EXTRACTION:**
- If you have content from Wikipedia, analyze it directly.
- If you have a URL from web search, you MUST use the following sequence: First, call `visit_and_get_html` with the URL. Second, call `extract_main_content` on the resulting HTML to get clean text.
4. **SYNTHESIZE & VERIFY:** Analyze the clean text you have obtained. Generate Python code (using string methods or the `re` module) to find the specific information needed. If you can, visit a second source to verify your finding.
5. **FINAL ANSWER:** Once confident in your answer, call your `final_answer` tool with ONLY the final, clean value, formatted perfectly according to the GAIA rules below.
**GAIA RULES FOR FINAL ANSWER:**
{gaia_rules_prompt}
**INSTRUCTION FOR YOUR CURRENT ACTION:**
Begin with STEP 1. Follow the plan meticulously, starting with the "Wikipedia-First" approach. Generate your thoughts and the Python code for the NEXT logical step.
"""
for i, question in enumerate(all_questions):
task_id = question['task_id']
question_text = question['question']
print(f"\n--- Procesando Pregunta {i+1}/{len(all_questions)} (ID: {task_id}) ---")
current_prompt = main_task_prompt_template.format(question_text=question_text, gaia_rules_prompt=gaia_rules_prompt)
agent_answer = None
try:
agent_answer = agente_principal.run(current_prompt)
print(f"Respuesta del Agente: {agent_answer}")
except Exception as e:
agent_answer = f"Error al ejecutar el agente: {e}"
print(agent_answer)
traceback.print_exc()
submission_answer = {"task_id": task_id, "submitted_answer": agent_answer}
all_answers.append(submission_answer)
results_for_display.append({"Question": question_text, "Agent's Answer": agent_answer})
print("--- Pausando por 5 segundos para no exceder el límite de la API... ---")
time.sleep(5)
submission_file = "submission.jsonl"
with open(submission_file, 'w') as f:
for answer in all_answers:
f.write(json.dumps(answer) + '\n')
print(f"Archivo de envío '{submission_file}' creado con {len(all_answers)} respuestas.")
try:
payload = {"username": username, "agent_code": code_link}
with open(submission_file, 'rb') as f:
files = {'answers': (submission_file, f, 'application/jsonl')}
submit_url = f"{DEFAULT_API_URL}/submit"
response = requests.post(submit_url, data=payload, files=files)
response.raise_for_status()
submission_result = response.json()
print("¡Resultados enviados exitosamente!")
return f"¡Éxito! Tu puntaje final es: {submission_result.get('score', 'N/A')}", pd.DataFrame(results_for_display)
except Exception as e:
error_msg = f"Error al enviar los resultados: {e}"
print(error_msg)
return error_msg, pd.DataFrame(results_for_display)
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# AZUFR3 AGENT DAEMON - Ecosistema de Agentes para el Examen Final de GAIA")
gr.Markdown("Inicia sesión con tu perfil de Hugging Face y haz clic en el botón para ejecutar tu agente en las 20 preguntas del examen y enviar tus resultados. La ejecución puede tardar varios minutos.")
login_button = gr.LoginButton()
run_button = gr.Button("Ejecutar Evaluación y Enviar Todas las Respuestas", variant="primary")
status_output = gr.Textbox(label="Estado de la Ejecución / Resultado del Envío", lines=5, interactive=False)
results_table = gr.DataFrame(label="Preguntas y Respuestas del Agente", wrap=True, column_widths=["50%", "50%"])
run_button.click(
fn=run_and_submit_all,
outputs=[status_output, results_table]
)
if __name__ == "__main__":
demo.launch()