brunopaschoal's picture
GAIA agent: smolagents CodeAgent + Gemini
969f7c5 verified
Raw History Blame Contribute Delete
4.04 kB
"""Unit 4: fetch the 20 GAIA questions, answer them with the agent, submit for the certificate.
Local: py -3.12 app.py -> answer all questions (cached in answers.json)
py -3.12 app.py --only 3 9 -> (re)answer only those question numbers
py -3.12 app.py --submit -> submit the cached answers and print the score
Space: same code with a Gradio login + button (runs when SPACE_ID is set).
"""
import json
import os
import sys
from pathlib import Path
import requests
API = "https://agents-course-unit4-scoring.hf.space"
USERNAME = "brunopaschoal"
AGENT_CODE = "https://huggingface.co/spaces/brunopaschoal/Final_Assignment/tree/main"
HERE = Path(__file__).parent
CACHE = HERE / "answers.json"
FILES = HERE / "files"
TEXT_FILES = (".py", ".txt", ".csv", ".md", ".json")
def get_questions() -> list[dict]:
r = requests.get(f"{API}/questions", timeout=30)
r.raise_for_status()
return r.json()
def build_prompt(q: dict) -> str:
prompt = q["question"]
if not q.get("file_name"):
return prompt
FILES.mkdir(exist_ok=True)
path = FILES / q["file_name"]
if not path.exists():
r = requests.get(f"{API}/files/{q['task_id']}", timeout=60)
if r.ok:
path.write_bytes(r.content)
else: # course server often 404s; same file is in the (gated) GAIA validation set
from huggingface_hub import hf_hub_download
hf_hub_download("gaia-benchmark/GAIA", f"2023/validation/{q['file_name']}", repo_type="dataset", local_dir=HERE / "gaia")
path.write_bytes((HERE / "gaia/2023/validation" / q["file_name"]).read_bytes())
prompt += f"\n\nAttached file: {path.resolve().as_posix()}"
if path.suffix in TEXT_FILES: # the agent's sandbox can't open() files, so inline text files
prompt += f"\nFile contents:\n```\n{path.read_text(encoding='utf-8', errors='replace')}\n```"
return prompt
def answer_all(only: set[int] | None = None) -> dict:
from agent import build_agent, clean_answer
cache = json.loads(CACHE.read_text(encoding="utf-8")) if CACHE.exists() else {}
for i, q in enumerate(get_questions(), 1):
if (only and i not in only) or (not only and q["task_id"] in cache):
continue
print(f"\n===== Question {i}/20 =====\n{q['question'][:200]}")
try:
cache[q["task_id"]] = clean_answer(build_agent().run(build_prompt(q)))
except Exception as e: # one failure (e.g. quota) must not lose the other answers
print(f"!! Question {i} failed: {e}")
continue
CACHE.write_text(json.dumps(cache, indent=2, ensure_ascii=False), encoding="utf-8")
print(f">> Answer {i}: {cache[q['task_id']]}")
return cache
def submit(cache: dict, username: str = USERNAME) -> str:
answers = [{"task_id": t, "submitted_answer": a} for t, a in cache.items()]
r = requests.post(f"{API}/submit", json={"username": username, "agent_code": AGENT_CODE, "answers": answers}, timeout=120)
r.raise_for_status()
d = r.json()
return f"Score: {d.get('score')}% ({d.get('correct_count')}/{d.get('total_attempted')} correct). {d.get('message', '')}"
def launch_space():
import gradio as gr
def run(profile: gr.OAuthProfile | None):
if not profile:
return "Please log in with Hugging Face first."
return submit(answer_all(), profile.username)
with gr.Blocks() as demo:
gr.Markdown("# GAIA agent (HF Agents course, Unit 4)\nsmolagents CodeAgent + Gemini. Log in, then run.")
gr.LoginButton()
out = gr.Textbox(label="Result")
gr.Button("Run evaluation & submit").click(run, outputs=out)
demo.launch()
if __name__ == "__main__":
if os.environ.get("SPACE_ID"):
launch_space()
elif "--submit" in sys.argv:
print(submit(json.loads(CACHE.read_text(encoding="utf-8"))))
else:
only = {int(a) for a in sys.argv[sys.argv.index("--only") + 1:]} if "--only" in sys.argv else None
answer_all(only)