import os import gradio as gr import requests import torch from transformers import AutoTokenizer, AutoModelForCausalLM import pandas as pd import json # --- Constants --- DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space" # --- Initialize Model --- model_name = "mosaicml/mpt-7b-chat" tokenizer = AutoTokenizer.from_pretrained(model_name) # Offload folder pour éviter crash GPU offload_folder = "offload" os.makedirs(offload_folder, exist_ok=True) model = AutoModelForCausalLM.from_pretrained( model_name, device_map="auto", offload_folder=offload_folder, torch_dtype=torch.float16, ) # --- Define a simple tool for demonstration --- def AddTwoNumbers(a: int, b: int) -> int: return a + b # --- Reasoning Agent Definition --- class ReasoningAgent: def __init__(self): print("ReasoningAgent initialized.") self.tools_description = ( "You have one tool available:\n" "- AddTwoNumbers(a, b): returns the sum of two integers a and b.\n" "Use this tool if you need to add numbers." ) def __call__(self, question: str) -> str: print(f"\n=== New Question ===\n{question}\n") # Prompt structuré prompt = f""" You are an AI reasoning agent. {self.tools_description} Answer the question in the following JSON format: {{ "thought": "Describe your reasoning step by step", "action": "Action you decide to take (like calling a tool) or 'None' if no action", "observation": "Result of the action (or empty if no action)", "answer": "Final answer to the user" }} Question: {question} """ inputs = tokenizer(prompt, return_tensors="pt").to(model.device) output = model.generate(**inputs, max_new_tokens=300) text_output = tokenizer.decode(output[0], skip_special_tokens=True) print(f"Raw model output:\n{text_output[:1000]}...\n") # on affiche un gros morceau du texte # Parser le JSON try: parsed = json.loads(text_output) except json.JSONDecodeError as e: print(f"⚠️ JSON decode error: {e}") parsed = {"thought": "", "action": "None", "observation": "", "answer": text_output} thought = parsed.get("thought", "") action = parsed.get("action", "None") observation = parsed.get("observation", "") answer = parsed.get("answer", "No answer returned.") # Exécution de l'outil si nécessaire if action.startswith("AddTwoNumbers"): try: numbers = action[action.find("(")+1:action.find(")")].split(",") a, b = int(numbers[0].strip()), int(numbers[1].strip()) observation = AddTwoNumbers(a, b) parsed["observation"] = str(observation) print(f"✅ Tool executed: {action} -> {observation}") except Exception as e: observation = f"⚠️ Error executing tool: {e}" parsed["observation"] = observation print(observation) # Print du raisonnement actuel print(f"💭 Thought: {thought}") print(f"🔧 Action: {action}") print(f"👀 Observation: {observation}") print(f"📝 Answer: {answer}\n{'-'*50}\n") return answer # --- Main Evaluation & Submission Function --- def run_and_submit_all(profile: gr.OAuthProfile | None): space_id = os.getenv("SPACE_ID") if profile: username = f"{profile.username}" print(f"User logged in: {username}") else: print("User not logged in.") return "Please Login to Hugging Face with the button.", None questions_url = f"{DEFAULT_API_URL}/questions" submit_url = f"{DEFAULT_API_URL}/submit" # Instantiate Agent try: agent = ReasoningAgent() except Exception as e: return f"Error initializing agent: {e}", None agent_code = f"https://huggingface.co/spaces/{space_id}/tree/main" # Fetch Questions try: response = requests.get(questions_url, timeout=15) response.raise_for_status() questions_data = response.json() if not questions_data: return "Fetched questions list is empty or invalid format.", None except Exception as e: return f"Error fetching questions: {e}", None # Run Agent results_log = [] answers_payload = [] for item in questions_data: task_id = item.get("task_id") question_text = item.get("question") if not task_id or question_text is None: continue 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}" }) if not answers_payload: return "Agent did not produce any answers to submit.", pd.DataFrame(results_log) # Submit submission_data = {"username": username.strip(), "agent_code": agent_code, "answers": answers_payload} try: response = requests.post(submit_url, json=submission_data, timeout=60) response.raise_for_status() result_data = response.json() final_status = ( f"Submission Successful!\n" f"User: {result_data.get('username')}\n" f"Overall Score: {result_data.get('score', 'N/A')}% " f"({result_data.get('correct_count', '?')}/{result_data.get('total_attempted', '?')} correct)\n" f"Message: {result_data.get('message', 'No message received.')}" ) results_df = pd.DataFrame(results_log) return final_status, results_df except Exception as e: results_df = pd.DataFrame(results_log) return f"Submission Failed: {e}", results_df # --- Build Gradio Interface --- with gr.Blocks() as demo: gr.Markdown("# Reasoning Agent with Tool Example") gr.Markdown(""" **Instructions:** 1. Log in to Hugging Face. 2. Click 'Run Evaluation & Submit All Answers'. 3. The agent can use the AddTwoNumbers tool if needed. """) 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]) # --- Launch App --- if __name__ == "__main__": demo.launch(debug=True, share=False)