Spaces:
Sleeping
Sleeping
File size: 8,154 Bytes
47a60a5 10e9b7d eccf8e4 3c4371f 47a60a5 31243f4 47a60a5 31243f4 47a60a5 31243f4 47a60a5 36ed51a 31243f4 eccf8e4 47a60a5 31243f4 47a60a5 31243f4 47a60a5 31243f4 7d65c66 31243f4 7d65c66 47a60a5 e80aab9 47a60a5 e80aab9 47a60a5 e80aab9 47a60a5 7e4a06b 31243f4 9088b99 7d65c66 47a60a5 e80aab9 47a60a5 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# app.py (Final version)
import os
import gradio as gr
import requests
import pandas as pd
import base64
import json
import operator
from typing import Annotated, List, TypedDict
from dotenv import load_dotenv
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tools import tool
from langchain_google_genai import ChatGoogleGenerativeAI
from langgraph.graph import END, StateGraph
from langgraph.prebuilt import ToolNode
API_BASE_URL = "https://agents-course-unit4-scoring.hf.space"
class GaiaLangGraphAgent:
def __init__(self):
print("Initializing GaiaLangGraphAgent...")
load_dotenv()
class AgentState(TypedDict):
question: str
intermediate_steps: Annotated[List[BaseMessage], operator.add]
self.AgentState = AgentState
web_search_tool = TavilySearchResults(max_results=4)
@tool
def calculator(expression: str) -> str:
"""Evaluates a simple mathematical expression."""
try:
import numexpr
return str(numexpr.evaluate(expression).item())
except Exception as e: return f"Error: {e}"
llm_vision = ChatGoogleGenerativeAI(model="gemini-1.5-pro-latest")
def get_file_path(file_name: str) -> str:
if not os.path.exists("task_files"): os.makedirs("task_files")
return os.path.join("task_files", file_name)
@tool
def file_reader(file_name: str) -> str:
"""Reads a file, downloading if necessary. Handles text and images."""
local_path = get_file_path(file_name)
if not os.path.exists(local_path):
download_url = f"{API_BASE_URL}/files/{file_name}"
print(f"Downloading: {download_url}")
try:
response = requests.get(download_url); response.raise_for_status()
with open(local_path, "wb") as f: f.write(response.content)
except Exception as e: return f"Error downloading {file_name}: {e}"
try:
if any(file_name.lower().endswith(ext) for ext in ['.png', '.jpg', '.jpeg', '.webp']):
with open(local_path, "rb") as image_file: b64_image = base64.b64encode(image_file.read()).decode('utf-8')
vision_prompt = HumanMessage(content=[
{"type": "text", "text": "Describe this image in detail, focusing on text or identifiable objects."},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64_image}"}}
])
return llm_vision.invoke([vision_prompt]).content
else:
with open(local_path, 'r', encoding='utf-8') as f: return f.read()
except Exception as e: return f"Error processing {file_name}: {e}"
tools = [web_search_tool, file_reader, calculator]
llm = ChatGoogleGenerativeAI(model="gemini-1.5-flash-latest", temperature=0, convert_system_message_to_human=True)
llm_with_tools = llm.bind_tools(tools)
planner_prompt = ChatPromptTemplate.from_messages([
("system", """You are a world-class AI assistant.
**Principles:** 1. Analyze the question for nuances. 2. Create multi-step plans. 3. Use tools intelligently (search, file read, calculator) or solve logic puzzles directly. 4. Provide exact-match answers.
**Execution:** Loop through plan->act cycles until you have the final answer."""),
("human", "{question}\n\n{intermediate_steps}"),
])
def planner_node(state: AgentState):
print("\n---PLANNER---")
chain = planner_prompt | llm_with_tools
response = chain.invoke(state)
print(f"Planner decision: {'Tool call' if response.tool_calls else 'Final Answer'}")
return {'intermediate_steps': [response]}
tool_node = ToolNode(tools)
def should_continue(state: AgentState):
last_message = state['intermediate_steps'][-1]
if isinstance(last_message, AIMessage):
if len(getattr(last_message, "tool_calls", [])) > 0: return "action"
return END
workflow = StateGraph(AgentState)
workflow.add_node("planner", planner_node)
workflow.add_node("action", tool_node)
workflow.set_entry_point("planner")
workflow.add_conditional_edges("planner", should_continue)
workflow.add_edge("action", "planner")
self.app = workflow.compile()
print("GaiaLangGraphAgent initialized successfully.")
def __call__(self, question: str) -> str:
print(f"\n>>>>>> AGENT EXECUTING FOR QUESTION: {question[:70]}...")
initial_state = {"question": question, "intermediate_steps": []}
final_state = self.app.invoke(initial_state, config={"recursion_limit": 15})
final_answer = final_state["intermediate_steps"][-1].content
print(f"<<<<<< AGENT FINISHED. FINAL ANSWER: {final_answer}")
return final_answer
def run_and_submit_all(profile: gr.OAuthProfile | None):
if not profile: return "Please Login to Hugging Face with the button first.", None
space_id = os.getenv("SPACE_ID")
if not space_id: return "CRITICAL ERROR: SPACE_ID not found. Run this from a deployed Hugging Face Space.", None
username = profile.username
print(f"User logged in: {username}")
questions_url = f"{API_BASE_URL}/questions"
submit_url = f"{API_BASE_URL}/submit"
try:
agent = GaiaLangGraphAgent()
except Exception as e: return f"Error initializing agent: {e}", None
agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main"
print(f"Fetching questions from: {questions_url}")
try:
response = requests.get(questions_url, timeout=20); response.raise_for_status()
questions_data = response.json()
except Exception as e: return f"Error fetching questions: {e}", None
results_log, answers_payload = [], []
print(f"Running agent on {len(questions_data)} questions. This may take several minutes...")
for item in questions_data:
task_id, question_text = item.get("task_id"), item.get("question")
try:
submitted_answer = agent(question_text)
answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
except Exception as e:
results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": f"AGENT ERROR: {e}"})
submission_data = {"username": username, "agent_code": agent_code, "answers": answers_payload}
print(f"Submitting {len(answers_payload)} answers...")
try:
response = requests.post(submit_url, json=submission_data, timeout=60); response.raise_for_status()
result_data = response.json()
final_status = (f"Submission Successful!\nUser: {result_data.get('username')}\n"
f"Score: {result_data.get('score', 'N/A')}% "
f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)")
return final_status, pd.DataFrame(results_log)
except Exception as e: return f"Submission Failed: {e}", pd.DataFrame(results_log)
with gr.Blocks() as demo:
gr.Markdown("# GAIA - Advanced Agent Runner")
gr.Markdown("Log in and click 'Run' to evaluate the agent.")
gr.LoginButton()
run_button = gr.Button("Run Evaluation & Submit All Answers")
status_output = gr.Textbox(label="Run Status / Submission Result", lines=5, interactive=False)
results_table = gr.DataFrame(label="Questions and Agent Answers", wrap=True)
run_button.click(fn=run_and_submit_all, outputs=[status_output, results_table])
if __name__ == "__main__":
print("Launching Gradio Interface...")
demo.launch() |