Spaces:
Runtime error
Runtime error
| """ | |
| 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() | |