Download app.py from Miladsaeedi70/Final_Assignment_Template: direct link, hf CLI and curl.
- Browser
- Download file 10.3 kB
-
https://huggingface.co/spaces/Miladsaeedi70/Final_Assignment_Template/resolve/54b321b0abe9f0a111b2c24ad0f7d45ca66b3b54/app.py
- Command line
-
hf download hf://spaces/Miladsaeedi70/Final_Assignment_Template@54b321b0abe9f0a111b2c24ad0f7d45ca66b3b54/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Miladsaeedi70/Final_Assignment_Template/resolve/54b321b0abe9f0a111b2c24ad0f7d45ca66b3b54/app.py
10.3 kB
| import os | |
| import tempfile | |
| from pathlib import Path | |
| import gradio as gr | |
| import pandas as pd | |
| import requests | |
| import spaces | |
| DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space" | |
| DEFAULT_SPACE_ID = "Miladsaeedi70/Final_Assignment_Template" | |
| SPACE_OWNER = os.getenv("SPACE_OWNER", "Miladsaeedi70").strip() | |
| _AGENT_INSTANCE = None | |
| def get_agent(): | |
| """Import and initialize the production OpenAI agent lazily.""" | |
| global _AGENT_INSTANCE | |
| if _AGENT_INSTANCE is not None: | |
| return _AGENT_INSTANCE | |
| from agent import GaiaAgent | |
| _AGENT_INSTANCE = GaiaAgent() | |
| return _AGENT_INSTANCE | |
| def validate_profile( | |
| profile: gr.OAuthProfile | None, | |
| ) -> tuple[str | None, str | None]: | |
| """Return (username, error_message) for the authenticated Space user.""" | |
| if profile is None: | |
| return None, "Please log in to Hugging Face first." | |
| username = str(profile.username).strip() | |
| if not username: | |
| return None, "Hugging Face login did not return a username." | |
| if SPACE_OWNER and username.lower() != SPACE_OWNER.lower(): | |
| return ( | |
| None, | |
| "This public Space is restricted to its owner to prevent " | |
| "unauthorized OpenAI API usage.", | |
| ) | |
| return username, None | |
| def test_zero_gpu() -> str: | |
| """ | |
| Small ZeroGPU probe required by the Space hardware configuration. | |
| The full GAIA evaluation is intentionally not decorated because GPT-4.1 | |
| runs through the OpenAI API and does not use the allocated Hugging Face GPU. | |
| """ | |
| return "ZeroGPU function executed successfully." | |
| def run_preflight( | |
| profile: gr.OAuthProfile | None, | |
| ) -> str: | |
| """Validate authentication, dependencies, API key, and model access.""" | |
| username, error_message = validate_profile(profile) | |
| if error_message: | |
| return error_message | |
| try: | |
| agent = get_agent() | |
| result = agent.health_check() | |
| except Exception as error: | |
| return ( | |
| "Preflight failed: " | |
| f"{type(error).__name__}: {error}" | |
| ) | |
| checks = [ | |
| f"User: {username}", | |
| f"Text model: {result['text_model']}", | |
| f"Vision model: {result['vision_model']}", | |
| f"Audio model: {result['audio_model']}", | |
| f"Text response: {result['text_response']}", | |
| f"Stockfish available: {result['stockfish_available']}", | |
| f"FFmpeg available: {result['ffmpeg_available']}", | |
| ] | |
| if result["text_response"].strip().upper() != "OK": | |
| checks.append( | |
| "Warning: the model responded, but not with the expected exact word OK." | |
| ) | |
| return "Preflight completed.\n" + "\n".join(checks) | |
| def download_task_attachment( | |
| api_url: str, | |
| task_id: str, | |
| file_name: str, | |
| output_directory: Path, | |
| ) -> str: | |
| """Download one GAIA attachment and return its local path.""" | |
| safe_name = Path(file_name).name | |
| output_path = output_directory / f"{task_id}_{safe_name}" | |
| response = requests.get( | |
| f"{api_url}/files/{task_id}", | |
| timeout=120, | |
| ) | |
| response.raise_for_status() | |
| if not response.content: | |
| raise RuntimeError("The attachment response was empty.") | |
| content_type = response.headers.get("Content-Type", "").lower() | |
| if "application/json" in content_type: | |
| try: | |
| payload = response.json() | |
| except ValueError: | |
| payload = {} | |
| detail = payload.get("detail") | |
| if detail: | |
| raise RuntimeError(f"Attachment API error: {detail}") | |
| output_path.write_bytes(response.content) | |
| return str(output_path) | |
| def run_and_submit_all( | |
| profile: gr.OAuthProfile | None, | |
| ): | |
| """Run the LangGraph agent on all GAIA questions and submit answers.""" | |
| username, error_message = validate_profile(profile) | |
| if error_message: | |
| return error_message, None | |
| print(f"User logged in: {username}") | |
| api_url = DEFAULT_API_URL | |
| questions_url = f"{api_url}/questions" | |
| submit_url = f"{api_url}/submit" | |
| space_id = os.getenv("SPACE_ID", DEFAULT_SPACE_ID) | |
| agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main" | |
| try: | |
| agent = get_agent() | |
| except Exception as error: | |
| message = ( | |
| "Agent initialization failed: " | |
| f"{type(error).__name__}: {error}" | |
| ) | |
| print(message) | |
| return message, None | |
| try: | |
| response = requests.get(questions_url, timeout=30) | |
| response.raise_for_status() | |
| questions_data = response.json() | |
| except Exception as error: | |
| message = ( | |
| "Could not fetch the questions: " | |
| f"{type(error).__name__}: {error}" | |
| ) | |
| print(message) | |
| return message, None | |
| if not isinstance(questions_data, list) or not questions_data: | |
| return "The questions endpoint returned no questions.", None | |
| results_log: list[dict] = [] | |
| answers_payload: list[dict] = [] | |
| with tempfile.TemporaryDirectory(prefix="gaia_attachments_") as directory: | |
| attachment_directory = Path(directory) | |
| for question_number, item in enumerate(questions_data, start=1): | |
| task_id = str(item.get("task_id", "")).strip() | |
| question_text = str(item.get("question", "")).strip() | |
| file_name = str(item.get("file_name", "") or "").strip() | |
| if not task_id or not question_text: | |
| print(f"Skipping invalid question item: {item}") | |
| continue | |
| print("\n" + "=" * 80) | |
| print(f"QUESTION {question_number}/{len(questions_data)}") | |
| print(f"Task ID: {task_id}") | |
| print(f"Attachment: {file_name or 'None'}") | |
| print(f"Question: {question_text}") | |
| print("=" * 80) | |
| input_file: str | None = None | |
| submitted_answer = "" | |
| error_text = "" | |
| try: | |
| if file_name: | |
| input_file = download_task_attachment( | |
| api_url=api_url, | |
| task_id=task_id, | |
| file_name=file_name, | |
| output_directory=attachment_directory, | |
| ) | |
| print(f"Downloaded attachment: {input_file}") | |
| submitted_answer = agent( | |
| question=question_text, | |
| input_file=input_file, | |
| ) | |
| except Exception as error: | |
| error_text = f"{type(error).__name__}: {error}" | |
| print(f"Agent error for {task_id}: {error_text}") | |
| submitted_answer = "" | |
| submitted_answer = str(submitted_answer or "").strip() | |
| answers_payload.append( | |
| { | |
| "task_id": task_id, | |
| "submitted_answer": submitted_answer, | |
| } | |
| ) | |
| results_log.append( | |
| { | |
| "Task ID": task_id, | |
| "Question": question_text, | |
| "Attachment": file_name, | |
| "Submitted Answer": submitted_answer, | |
| "Error": error_text, | |
| } | |
| ) | |
| print(f"Submitted answer: {submitted_answer or '[blank]'}") | |
| if not answers_payload: | |
| return ( | |
| "The agent did not produce any submission records.", | |
| pd.DataFrame(results_log), | |
| ) | |
| submission_data = { | |
| "username": username, | |
| "agent_code": agent_code, | |
| "answers": answers_payload, | |
| } | |
| try: | |
| response = requests.post( | |
| submit_url, | |
| json=submission_data, | |
| timeout=180, | |
| ) | |
| response.raise_for_status() | |
| result_data = response.json() | |
| final_status = ( | |
| "Submission successful!\n" | |
| f"User: {result_data.get('username', username)}\n" | |
| f"Overall score: {result_data.get('score', 'N/A')}% " | |
| f"({result_data.get('correct_count', '?')}/" | |
| f"{result_data.get('total_attempted', '?')} correct)\n" | |
| f"Message: {result_data.get('message', 'No message received.')}" | |
| ) | |
| return final_status, pd.DataFrame(results_log) | |
| except requests.HTTPError as error: | |
| response_text = error.response.text[:1000] if error.response else "" | |
| message = ( | |
| "Submission failed: " | |
| f"HTTP {getattr(error.response, 'status_code', 'unknown')} - " | |
| f"{response_text}" | |
| ) | |
| return message, pd.DataFrame(results_log) | |
| except Exception as error: | |
| message = ( | |
| "Submission failed: " | |
| f"{type(error).__name__}: {error}" | |
| ) | |
| return message, pd.DataFrame(results_log) | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# GAIA Final Assignment Agent") | |
| gr.Markdown( | |
| """ | |
| Log in with Hugging Face, then run the complete 20-question evaluation. | |
| The Space downloads task attachments, runs the LangGraph agent, and submits | |
| only the final answers to the course scorer. | |
| Only the Space owner can run the evaluation, which protects the private | |
| OpenAI API key used by this public Space. | |
| """ | |
| ) | |
| gr.LoginButton() | |
| zero_gpu_button = gr.Button( | |
| "1. Test ZeroGPU", | |
| ) | |
| preflight_button = gr.Button( | |
| "2. Test OpenAI Configuration", | |
| ) | |
| run_button = gr.Button( | |
| "3. Run Evaluation & Submit All Answers", | |
| variant="primary", | |
| ) | |
| status_output = gr.Textbox( | |
| label="Preflight / Submission Status", | |
| lines=9, | |
| interactive=False, | |
| ) | |
| results_table = gr.DataFrame( | |
| label="Questions and Agent Answers", | |
| wrap=True, | |
| ) | |
| zero_gpu_button.click( | |
| fn=test_zero_gpu, | |
| outputs=status_output, | |
| ) | |
| preflight_button.click( | |
| fn=run_preflight, | |
| outputs=status_output, | |
| ) | |
| run_button.click( | |
| fn=run_and_submit_all, | |
| outputs=[status_output, results_table], | |
| ) | |
| demo.queue(default_concurrency_limit=1) | |
| if __name__ == "__main__": | |
| print("Starting GAIA Final Assignment Space") | |
| print("SPACE_ID:", os.getenv("SPACE_ID", DEFAULT_SPACE_ID)) | |
| print("SPACE_OWNER:", SPACE_OWNER or "[not restricted]") | |
| print("OPENAI_API_KEY configured:", bool(os.getenv("OPENAI_API_KEY"))) | |
| demo.launch() | |