""" app.py ====== Gradio app for the Hugging Face Agents Course - Unit 4 (GAIA leaderboard). This app exposes the agent (whichever framework solution is shipped in this Space: smolagents / LangGraph / LlamaIndex) through a simple UI: * fetch the 20 evaluation questions from the scoring API, * run the agent on a single question, or on all questions, * locally self-score (optional, needs HF_TOKEN + GAIA dataset access), * submit the answers to the leaderboard. Environment variables (set as Space secrets): LLM_API_KEY required - key for an OpenAI-compatible endpoint LLM_BASE_URL optional - default https://api.openai.com/v1 LLM_MODEL optional - default gpt-4o-mini HF_TOKEN optional - GAIA-dataset file fallback + local self-scoring VISION_MODEL optional - vision model for image questions WHISPER_MODEL optional - default 'small' (use 'base'/'tiny' on CPU) """ from __future__ import annotations import os import gradio as gr import pandas as pd import requests import gaia_common as gc # --- pick whichever framework solution is bundled in this Space ------------- SOLUTION_MODULES = ["solution_smolagents", "solution_langgraph", "solution_llamaindex"] for _mod in SOLUTION_MODULES: try: solution = __import__(_mod) FRAMEWORK = _mod break except ImportError: continue else: raise RuntimeError("No framework solution module found in this Space.") def make_agent(): if FRAMEWORK == "solution_smolagents": return solution.GAIAAgent() if FRAMEWORK == "solution_langgraph": return solution.GAIALangGraphAgent() return solution.GAIALlamaIndexAgent() # --- core functions --------------------------------------------------------- def build_question_options() -> list[str]: try: qs = gc.fetch_questions() if qs: return [f"{q['task_id']} :: {q['question'][:80]}" for q in qs] except Exception as e: print(f"Could not fetch questions at startup: {e}") return ["Questions unavailable at startup - reload after the API is reachable"] def _run_single(task_id: str, question: str, agent) -> str: answer = agent(task_id, question) return gc.normalize_final_answer(answer) def run_single(selection: str, profile: gr.OAuthProfile | None): if not profile: return "Please login with the Login button (required for submission).", None if not selection: return "Please choose a question from the dropdown.", None task_id = selection.split(" :: ")[0] questions = {q["task_id"]: q["question"] for q in gc.fetch_questions()} question = questions.get(task_id, "") try: agent = make_agent() answer = _run_single(task_id, question, agent) return f"QUESTION:\n{question}\n\nANSWER:\n{answer}", pd.DataFrame( [{"task_id": task_id, "submitted_answer": answer}] ) except Exception as e: return f"Agent error: {e}", None def run_all(submit: bool, profile: gr.OAuthProfile | None) -> tuple[str, pd.DataFrame]: if not profile: return "Please login with the Login button.", None if not os.environ.get("LLM_API_KEY") and not os.environ.get("HF_TOKEN"): return ( "No LLM credentials found. Set the Space secrets LLM_API_KEY " "(OpenAI-compatible endpoint) to run the agent.", None, ) agent_code = f"https://huggingface.co/spaces/{os.getenv('SPACE_ID', '?')}/tree/main" username = profile.username questions = gc.fetch_questions() rows = [] answers_payload = [] agent = make_agent() for item in questions: task_id = item["task_id"] question = item["question"] try: answer = agent(task_id, question) except Exception as e: answer = f"AGENT ERROR: {e}" rows.append({"Task ID": task_id, "Question": question, "Submitted Answer": answer}) answers_payload.append({"task_id": task_id, "submitted_answer": answer}) status = f"Agent finished {len(answers_payload)} questions.\n" if submit: try: res = gc.submit_answers(username, agent_code, answers_payload) status += ( f"SUBMITTED for {res.get('username')} -> " f"score {res.get('score')}% ({res.get('correct_count')} correct)." ) except Exception as e: status += f"Submission failed: {e}" else: local = gc.self_score(answers_payload) if local.get("total"): status += f"LOCAL self-score: {local['score']}% ({local['correct']}/{local['total']})." else: status += "Local self-scoring skipped (set HF_TOKEN + accept GAIA dataset gating)." return status, pd.DataFrame(rows) def run_all_and_submit(profile: gr.OAuthProfile | None): return run_all(True, profile) def run_all_selfscore(profile: gr.OAuthProfile | None): return run_all(False, profile) # --- UI --------------------------------------------------------------------- with gr.Blocks(title="GAIA Agent - Unit 4") as demo: gr.Markdown( f"# GAIA Level-1 Agent · framework: `{FRAMEWORK}`\n\n" "Course **Unit 4 hands-on** — answers 20 GAIA level-1 questions and submits " "them to the leaderboard. The agent uses the canonical GAIA system prompt " "and a toolbelt: web search, page fetch, file download (with GAIA-dataset " "fallback), whisper transcription, vision analysis and python execution." ) with gr.Row(): gr.LoginButton() questions_dd = gr.Dropdown( label="Pick a question", choices=build_question_options(), allow_custom_value=False, ) run_single_btn = gr.Button("Run single question") single_out = gr.Textbox(label="Single-question result", lines=6, interactive=False) with gr.Row(): run_all_btn = gr.Button("Run all 20 questions (self-score if possible)") submit_btn = gr.Button("Run all 20 questions AND submit to leaderboard") status_out = gr.Textbox(label="Status / submission result", lines=8, interactive=False) results_table = gr.DataFrame(label="Questions and agent answers", wrap=True) run_single_btn.click(run_single, inputs=[questions_dd], outputs=[single_out]) run_all_btn.click(run_all_selfscore, inputs=[], outputs=[status_out, results_table]) submit_btn.click(run_all_and_submit, inputs=[], outputs=[status_out, results_table]) gr.Markdown( "### Instructions\n" "1. This Space runs a real agent — it calls an LLM API and may take several minutes " "for all 20 questions (audio transcription and YouTube downloads are the slowest).\n" "2. Set Space secrets: `LLM_API_KEY` (required), optionally `LLM_BASE_URL`, " "`LLM_MODEL`, `HF_TOKEN`, `VISION_MODEL`, `WHISPER_MODEL`.\n" "3. Log in, then click **Run all & submit**.\n\n" "> Keep this Space public so your code link on the leaderboard verifies your submission." ) if __name__ == "__main__": demo.launch()