Spaces:
Runtime error
Runtime error
Nicolas Fremondiere commited on
Commit ·
d919051
1
Parent(s): 81917a3
agent v_1
Browse filesAll the common features are present
Video/audio/image analysis
Code analysis
Websearch/wikipedia search
- .gitignore +2 -0
- agent/agent.py +97 -0
- agent/agent_code.py +45 -0
- agent/agent_multimedia.py +108 -0
- agent/agent_websearch.py +199 -0
- agent/get_question/hf_api.py +82 -0
- agent/prompts.yaml +68 -0
- agent/ressources_getter.py +75 -0
- app.py +3 -11
- requirements.txt +16 -1
.gitignore
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
__pycache__
|
agent/agent.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from smolagents import Tool, tool
|
| 2 |
+
import os
|
| 3 |
+
import asyncio
|
| 4 |
+
|
| 5 |
+
from Final_Assignment_Template.agent.ressources_getter import save_file, \
|
| 6 |
+
get_prompt_with_file_content, extract_text_from_file, convert_excel_to_text, delete_tmp_files
|
| 7 |
+
from get_question.hf_api import get_file_by_task_id
|
| 8 |
+
from Final_Assignment_Template.agent.agent_websearch import create_wikipedia_agent
|
| 9 |
+
from Final_Assignment_Template.agent.agent_multimedia import create_multimedia_agent
|
| 10 |
+
from Final_Assignment_Template.agent.agent_code import create_code_analyzer_agent
|
| 11 |
+
from smolagents import ToolCallingAgent, LiteLLMModel
|
| 12 |
+
from dotenv import load_dotenv
|
| 13 |
+
|
| 14 |
+
load_dotenv()
|
| 15 |
+
|
| 16 |
+
agent_wikipedia = create_wikipedia_agent()
|
| 17 |
+
agent_multimedia = create_multimedia_agent()
|
| 18 |
+
agent_code = create_code_analyzer_agent()
|
| 19 |
+
|
| 20 |
+
class WikipediaAgentTool(Tool):
|
| 21 |
+
name = "WikipediaAgentTool"
|
| 22 |
+
description = "Delegates tasks to the WebSearch agent."
|
| 23 |
+
inputs = {"query": {"type": "string", "description": "Search query for Wikipedia or Web search."}}
|
| 24 |
+
output_type = "string"
|
| 25 |
+
def forward(self, query: str) -> str:
|
| 26 |
+
return agent_wikipedia.run(query)
|
| 27 |
+
|
| 28 |
+
class MediaAgentTool(Tool):
|
| 29 |
+
name = "MediaAgentTool"
|
| 30 |
+
description = """Delegates tasks to the Media agent. It can search for videos on YouTube to download them localy.
|
| 31 |
+
It can also analyze local video,image and music content."""
|
| 32 |
+
inputs = {"query": {"type": "string", "description": "Search query with a Youtube url or query with the file path."}}
|
| 33 |
+
output_type = "string"
|
| 34 |
+
|
| 35 |
+
def forward(self, query: str) -> str:
|
| 36 |
+
# Utilise l'agent vidéo pour rechercher sur YouTube
|
| 37 |
+
return agent_multimedia.run(query)
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class CodeAgentTool(Tool):
|
| 41 |
+
name = "CodeAgentTool"
|
| 42 |
+
description = """Delegates tasks to the Code agent. It can execute Python code and return the output."""
|
| 43 |
+
inputs = {"query": {"type": "string", "description": "Query with file path of the code."}}
|
| 44 |
+
output_type = "string"
|
| 45 |
+
|
| 46 |
+
def forward(self, query: str) -> str:
|
| 47 |
+
# Utilise l'agent code pour exécuter du code Python
|
| 48 |
+
return agent_code.run(query)
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
gemini_flash_manager_model = LiteLLMModel(model_id="gemini/gemini-2.5-flash", api_key=os.getenv("GOOGLE_API_KEY"))
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
manager_agent = ToolCallingAgent(
|
| 56 |
+
tools=[WikipediaAgentTool(),MediaAgentTool(),CodeAgentTool(),extract_text_from_file,convert_excel_to_text,delete_tmp_files], # Les agents workers sont des outils pour le manager
|
| 57 |
+
model=gemini_flash_manager_model,
|
| 58 |
+
name="ManagerAgent",
|
| 59 |
+
description=(
|
| 60 |
+
"Je suis un agent manager. Mon rôle est de comprendre les requêtes complexes, "
|
| 61 |
+
"de les décomposer en tâches plus petites et de déléguer ces tâches "
|
| 62 |
+
"aux agents spécialisés (WikiAgent) pour obtenir la meilleure réponse. "
|
| 63 |
+
"Je coordonne leurs actions et synthétise les résultats."
|
| 64 |
+
"Après avoir répondu à la requête, je supprime les fichiers temporaires téléchargés pour économiser de l'espace disque."
|
| 65 |
+
"Si tu ne trouve pas une réponse satisfaisante sous 5 étapes ou que tu n'as pas les outils pour y répondre, renvoie une chaine de caractères vide."
|
| 66 |
+
)
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
# Pour interagir avec l'agent manager
|
| 70 |
+
async def run_multi_agent_system(prompt: str):
|
| 71 |
+
print(f"\nRequête au Manager : {prompt}")
|
| 72 |
+
return manager_agent.run(prompt)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class BasicAgent:
|
| 76 |
+
task_id:str
|
| 77 |
+
file_content_type:str
|
| 78 |
+
agent = manager_agent
|
| 79 |
+
def __init__(self):
|
| 80 |
+
print("BasicAgent initialized.")
|
| 81 |
+
def __call__(self, question: str, task_id :str) -> str:
|
| 82 |
+
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
| 83 |
+
file_bytes,file_name=get_file_by_task_id(task_id)
|
| 84 |
+
print(file_name)
|
| 85 |
+
file_path = save_file(file_bytes,file_name)
|
| 86 |
+
prompt = get_prompt_with_file_content(question,file_path)
|
| 87 |
+
answer = asyncio.run(run_multi_agent_system(prompt))
|
| 88 |
+
print(f"Agent returning fixed answer: {answer}")
|
| 89 |
+
return answer
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
# if __name__ == "__main__":
|
| 93 |
+
# agent = BasicAgent()
|
| 94 |
+
# question = "Review the chess position provided in the image. It is black's turn. Provide the correct next move for black which guarantees a win. Please provide your response in algebraic notation."
|
| 95 |
+
# task_id = "cca530fc-4052-43b2-b130-b30968d8aa44"
|
| 96 |
+
# response = agent(question,task_id)
|
| 97 |
+
# print(response)
|
agent/agent_code.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
from dotenv import load_dotenv
|
| 4 |
+
from smolagents import CodeAgent, LiteLLMModel, tool
|
| 5 |
+
|
| 6 |
+
load_dotenv() # Charge les variables d'environnement
|
| 7 |
+
llm_model = LiteLLMModel(model_id="mistral/codestral-latest", api_key=os.getenv("MISTRAL_API_KEY"))
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def create_code_analyzer_agent():
|
| 11 |
+
"""
|
| 12 |
+
Crée un agent simple pour exécuter du code et obtenir sa sortie.
|
| 13 |
+
|
| 14 |
+
Returns:
|
| 15 |
+
CodeAgent: Agent configuré pour l'exécution de code
|
| 16 |
+
"""
|
| 17 |
+
# Initialiser le modèle Mistral Codestral
|
| 18 |
+
model = LiteLLMModel(
|
| 19 |
+
model_id="mistral/codestral-latest",
|
| 20 |
+
temperature=0.1, # Déterministe pour l'exécution
|
| 21 |
+
max_tokens=2000,
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
# Instructions système simples et directes
|
| 25 |
+
system_prompt = """
|
| 26 |
+
Tu es un exécuteur de code Python. Ton rôle est simple : exécuter le code fourni et donner sa sortie finale.
|
| 27 |
+
|
| 28 |
+
Quand on te donne du code à analyser :
|
| 29 |
+
1. Exécute directement le code Python
|
| 30 |
+
2. Capture toute la sortie (print, résultats, etc.)
|
| 31 |
+
3. Retourne la sortie finale
|
| 32 |
+
|
| 33 |
+
Sois concis et direct dans tes réponses. Concentre-toi uniquement sur l'exécution et le résultat.
|
| 34 |
+
"""
|
| 35 |
+
|
| 36 |
+
code_analyzer_agent = CodeAgent(
|
| 37 |
+
model=model,
|
| 38 |
+
tools=[],
|
| 39 |
+
description=system_prompt,
|
| 40 |
+
max_steps=3, # Peu d'étapes nécessaires
|
| 41 |
+
)
|
| 42 |
+
|
| 43 |
+
return code_analyzer_agent
|
| 44 |
+
|
| 45 |
+
|
agent/agent_multimedia.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Fonction pour lire et encoder une image en base64
|
| 2 |
+
import base64
|
| 3 |
+
import os
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
import yt_dlp
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
from smolagents import tool, ToolCallingAgent, LiteLLMModel
|
| 9 |
+
import google.generativeai as genai
|
| 10 |
+
from ressources_getter import DOWNLOAD_FOLDER, delete_tmp_files, create_download_folder_if_not_exist
|
| 11 |
+
import mimetypes
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
load_dotenv()
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
@tool
|
| 18 |
+
def download_video_youtube(url : str)-> str | None:
|
| 19 |
+
"""
|
| 20 |
+
Télécharge une vidéo YouTube dans un dossier local.
|
| 21 |
+
Args:
|
| 22 |
+
url (str): URL de la vidéo YouTube
|
| 23 |
+
Returns:
|
| 24 |
+
file_path (str): Chemin du fichier téléchargé ou None en cas d'erreur
|
| 25 |
+
"""
|
| 26 |
+
try:
|
| 27 |
+
# Créer le dossier de téléchargement s'il n'existe pas
|
| 28 |
+
create_download_folder_if_not_exist()
|
| 29 |
+
file_path = f'{DOWNLOAD_FOLDER}/tmp_video.mp4'
|
| 30 |
+
# Configuration pour yt-dlp
|
| 31 |
+
ydl_opts = {
|
| 32 |
+
'outtmpl': file_path, # Format du nom de fichier
|
| 33 |
+
'format': 'best[height<=720]', # Qualité maximale 720p (ajustable)
|
| 34 |
+
'noplaylist': True, # Télécharger seulement la vidéo, pas la playlist
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
# Télécharger la vidéo
|
| 38 |
+
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
|
| 39 |
+
print(f"Téléchargement de: {url}")
|
| 40 |
+
ydl.download([url])
|
| 41 |
+
print("Téléchargement terminé avec succès!")
|
| 42 |
+
return file_path
|
| 43 |
+
|
| 44 |
+
except Exception as e:
|
| 45 |
+
print(f"Erreur lors du téléchargement: {str(e)}")
|
| 46 |
+
return None
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
@tool
|
| 50 |
+
def analyze_media_content(media_path: str, user_prompt: str) -> str:
|
| 51 |
+
"""
|
| 52 |
+
Analyse le contenu du média en utilisant Gemini 2.5 Flash via le SDK Google Generative AI.
|
| 53 |
+
(Ce n'est pas LiteLLM qui fait l'appel multimodal ici, mais le SDK direct pour gérer les parties vidéo).
|
| 54 |
+
Args:
|
| 55 |
+
media_path (str): Chemin du fichier local à analyser.
|
| 56 |
+
user_prompt (str): Requête de l'utilisateur pour guider l'analyse.
|
| 57 |
+
Returns:
|
| 58 |
+
str: Résultat de l'analyse du fichier.
|
| 59 |
+
"""
|
| 60 |
+
try:
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
with open(media_path, "rb") as file:
|
| 64 |
+
file_bytes = file.read()
|
| 65 |
+
encoded_video = base64.b64encode(file_bytes).decode('utf-8')
|
| 66 |
+
|
| 67 |
+
# Déterminer le type MIME du fichier
|
| 68 |
+
mime_type, encoding = mimetypes.guess_type(media_path)
|
| 69 |
+
|
| 70 |
+
file_part = {
|
| 71 |
+
"inline_data": {
|
| 72 |
+
"mime_type": mime_type,
|
| 73 |
+
"data": encoded_video
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
genai.configure(api_key=os.getenv("GOOGLE_API_KEY")) # Assure que l'API Key est configurée
|
| 77 |
+
model = genai.GenerativeModel('gemini-2.5-flash') # Utilise le modèle directement via le SDK
|
| 78 |
+
response = model.generate_content([user_prompt, file_part])
|
| 79 |
+
return response.text
|
| 80 |
+
|
| 81 |
+
except Exception as e:
|
| 82 |
+
return f"Erreur lors de l'analyse de la vidéo : {e}"
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def create_multimedia_agent():
|
| 86 |
+
"""
|
| 87 |
+
Crée un agent multimédia capable de télécharger et d'analyser des vidéos YouTube.
|
| 88 |
+
Il peut également analyser des fichiers multimédias locaux (vidéos, images, musique).
|
| 89 |
+
Returns:
|
| 90 |
+
BasicAgent: Instance de l'agent multimédia.
|
| 91 |
+
"""
|
| 92 |
+
gemini_flash_vlm_model = LiteLLMModel(model_id="gemini/gemini-2.5-flash", api_key=os.getenv("GOOGLE_API_KEY"))
|
| 93 |
+
|
| 94 |
+
system_prompt = """Tu es un expert en analyse de vidéo,image et fichier son. Ton rôle est d'analyser les fichiers fournies en utilisant les outils à ta disposition.
|
| 95 |
+
Lorsque tu reçois un lien d'une vidéo youtube, utilise la fonction 'download_video_youtube' pour télécharger la vidéo.
|
| 96 |
+
Si tu as un fichier video,image ou son local, utilise la fonction 'analyze_media_content' pour analyser le contenu.
|
| 97 |
+
Utilise tes outils pour répondre aux questions de l'utilisateur concernant le contenu du fichier.
|
| 98 |
+
Fait bien attention à supprimer les fichiers temporaires téléchargées après analyse pour économiser de l'espace disque.
|
| 99 |
+
Fournis un réponse concise et sans points ou virgules.
|
| 100 |
+
"""
|
| 101 |
+
|
| 102 |
+
# Crée l'agent en lui passant l'instance de LiteLLMModel
|
| 103 |
+
video_agent = ToolCallingAgent(
|
| 104 |
+
model=gemini_flash_vlm_model, # Passe l'instance LiteLLMModel ici
|
| 105 |
+
tools=[analyze_media_content, download_video_youtube,delete_tmp_files], # Liste des outils que l'agent peut utiliser
|
| 106 |
+
description=system_prompt,
|
| 107 |
+
)
|
| 108 |
+
return video_agent
|
agent/agent_websearch.py
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import wikipedia
|
| 2 |
+
import requests
|
| 3 |
+
from bs4 import BeautifulSoup
|
| 4 |
+
import pandas as pd
|
| 5 |
+
from typing import List, Dict, Any, Optional
|
| 6 |
+
import os
|
| 7 |
+
from dotenv import load_dotenv
|
| 8 |
+
from smolagents import CodeAgent, LiteLLMModel, tool, DuckDuckGoSearchTool
|
| 9 |
+
import re
|
| 10 |
+
from datetime import datetime
|
| 11 |
+
|
| 12 |
+
# Configuration de Wikipedia en français
|
| 13 |
+
wikipedia.set_lang("fr")
|
| 14 |
+
|
| 15 |
+
# Initialisation de l'outil de recherche DuckDuckGo
|
| 16 |
+
search_tool = DuckDuckGoSearchTool(5)
|
| 17 |
+
|
| 18 |
+
load_dotenv() # Charge les variables d'environnement
|
| 19 |
+
|
| 20 |
+
@tool
|
| 21 |
+
def search_internet(query: str) -> List[Dict[str, str]]:
|
| 22 |
+
"""
|
| 23 |
+
Recherche des informations sur internet via DuckDuckGo.
|
| 24 |
+
|
| 25 |
+
Args:
|
| 26 |
+
query: Terme de recherche
|
| 27 |
+
|
| 28 |
+
Returns:
|
| 29 |
+
Liste de dictionnaires contenant les résultats de recherche
|
| 30 |
+
"""
|
| 31 |
+
try:
|
| 32 |
+
# Utilisation de DuckDuckGoSearchTool
|
| 33 |
+
results = search_tool(query)
|
| 34 |
+
return results
|
| 35 |
+
except Exception as e:
|
| 36 |
+
return [{'error': f'Erreur lors de la recherche: {str(e)}'}]
|
| 37 |
+
|
| 38 |
+
|
| 39 |
+
@tool
|
| 40 |
+
def get_wikipedia_page(title: str, lang: str = "fr") -> Dict[str, Any]:
|
| 41 |
+
"""
|
| 42 |
+
Récupère une page Wikipedia complète avec son contenu et ses tableaux sous forme d'un dictionnaire.
|
| 43 |
+
|
| 44 |
+
Args:
|
| 45 |
+
title: Titre de la page Wikipedia
|
| 46 |
+
lang: Langue de Wikipedia (par défaut: français)
|
| 47 |
+
|
| 48 |
+
Returns:
|
| 49 |
+
Dictionnaire contenant les informations de la page et ses tableaux
|
| 50 |
+
"""
|
| 51 |
+
try:
|
| 52 |
+
wikipedia.set_lang(lang)
|
| 53 |
+
page = wikipedia.page(title)
|
| 54 |
+
|
| 55 |
+
# Récupération du HTML de la page pour extraire les tableaux
|
| 56 |
+
response = requests.get(page.url)
|
| 57 |
+
soup = BeautifulSoup(response.content, 'html.parser')
|
| 58 |
+
|
| 59 |
+
# Extraction des tableaux avec leurs titres
|
| 60 |
+
tables = []
|
| 61 |
+
wiki_tables = soup.find_all('table', class_='wikitable')
|
| 62 |
+
|
| 63 |
+
for i, table in enumerate(wiki_tables):
|
| 64 |
+
table_data = []
|
| 65 |
+
headers = []
|
| 66 |
+
table_title = ""
|
| 67 |
+
|
| 68 |
+
# Recherche du titre du tableau
|
| 69 |
+
# Chercher dans les éléments précédents pour trouver un titre
|
| 70 |
+
current_element = table.find_previous_sibling()
|
| 71 |
+
title_found = False
|
| 72 |
+
|
| 73 |
+
while current_element and not title_found:
|
| 74 |
+
if current_element.name in ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']:
|
| 75 |
+
table_title = current_element.get_text(strip=True)
|
| 76 |
+
title_found = True
|
| 77 |
+
elif current_element.name == 'p':
|
| 78 |
+
# Parfois le titre est dans un paragraphe juste avant
|
| 79 |
+
text = current_element.get_text(strip=True)
|
| 80 |
+
if len(text) < 100 and text.endswith(':'):
|
| 81 |
+
table_title = text.rstrip(':')
|
| 82 |
+
title_found = True
|
| 83 |
+
elif current_element.name == 'caption':
|
| 84 |
+
# Certains tableaux ont une balise caption
|
| 85 |
+
table_title = current_element.get_text(strip=True)
|
| 86 |
+
title_found = True
|
| 87 |
+
current_element = current_element.find_previous_sibling()
|
| 88 |
+
|
| 89 |
+
# Vérifier si le tableau a une caption directe
|
| 90 |
+
caption = table.find('caption')
|
| 91 |
+
if caption and not table_title:
|
| 92 |
+
table_title = caption.get_text(strip=True)
|
| 93 |
+
|
| 94 |
+
# Si aucun titre trouvé, chercher dans les éléments suivants
|
| 95 |
+
if not table_title:
|
| 96 |
+
# Regarder les éléments th avec colspan ou les premiers éléments
|
| 97 |
+
first_row = table.find('tr')
|
| 98 |
+
if first_row:
|
| 99 |
+
first_cell = first_row.find(['th', 'td'])
|
| 100 |
+
if first_cell and first_cell.get('colspan'):
|
| 101 |
+
potential_title = first_cell.get_text(strip=True)
|
| 102 |
+
if len(potential_title) < 100:
|
| 103 |
+
table_title = potential_title
|
| 104 |
+
|
| 105 |
+
# Valeur par défaut si aucun titre trouvé
|
| 106 |
+
if not table_title:
|
| 107 |
+
table_title = f"Tableau {i + 1}"
|
| 108 |
+
|
| 109 |
+
# Extraction des en-têtes
|
| 110 |
+
header_row = table.find('tr')
|
| 111 |
+
if header_row:
|
| 112 |
+
for th in header_row.find_all(['th', 'td']):
|
| 113 |
+
headers.append(th.get_text(strip=True))
|
| 114 |
+
|
| 115 |
+
# Extraction des données
|
| 116 |
+
rows = table.find_all('tr')
|
| 117 |
+
data_rows = []
|
| 118 |
+
|
| 119 |
+
# Déterminer quelle ligne contient les données (pas les en-têtes)
|
| 120 |
+
start_row = 1 if headers else 0
|
| 121 |
+
|
| 122 |
+
for row in rows[start_row:]:
|
| 123 |
+
cells = row.find_all(['td', 'th'])
|
| 124 |
+
if cells:
|
| 125 |
+
row_data = {}
|
| 126 |
+
for j, cell in enumerate(cells):
|
| 127 |
+
header = headers[j] if j < len(headers) else f'Colonne_{j + 1}'
|
| 128 |
+
cell_text = cell.get_text(strip=True)
|
| 129 |
+
row_data[header] = cell_text
|
| 130 |
+
if any(row_data.values()): # Ignorer les lignes vides
|
| 131 |
+
data_rows.append(row_data)
|
| 132 |
+
|
| 133 |
+
tables.append({
|
| 134 |
+
'table_index': i,
|
| 135 |
+
'table_title': table_title,
|
| 136 |
+
'headers': headers,
|
| 137 |
+
'data': data_rows,
|
| 138 |
+
'row_count': len(data_rows),
|
| 139 |
+
'column_count': len(headers)
|
| 140 |
+
})
|
| 141 |
+
|
| 142 |
+
return {
|
| 143 |
+
'title': page.title,
|
| 144 |
+
'url': page.url,
|
| 145 |
+
'summary': page.summary,
|
| 146 |
+
'content': page.content,
|
| 147 |
+
'links': page.links[:20], # Limite aux 20 premiers liens
|
| 148 |
+
'categories': page.categories[:10], # Limite aux 10 premières catégories
|
| 149 |
+
'images': page.images[:5] if page.images else [], # Limite aux 5 premières images
|
| 150 |
+
'tables': tables,
|
| 151 |
+
'table_count': len(tables),
|
| 152 |
+
'page_length': len(page.content),
|
| 153 |
+
'has_tables': len(tables) > 0
|
| 154 |
+
}
|
| 155 |
+
except wikipedia.exceptions.DisambiguationError as e:
|
| 156 |
+
return {
|
| 157 |
+
'error': 'Ambiguité détectée',
|
| 158 |
+
'options': e.options[:10], # Limite aux 10 premières options
|
| 159 |
+
'type': 'disambiguation'
|
| 160 |
+
}
|
| 161 |
+
except wikipedia.exceptions.PageError:
|
| 162 |
+
return {
|
| 163 |
+
'error': f'Page "{title}" non trouvée',
|
| 164 |
+
'type': 'page_not_found'
|
| 165 |
+
}
|
| 166 |
+
except Exception as e:
|
| 167 |
+
return {
|
| 168 |
+
'error': f'Erreur: {str(e)}',
|
| 169 |
+
'type': 'general_error'
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
# Configuration du modèle LiteLLM
|
| 174 |
+
def create_wikipedia_agent():
|
| 175 |
+
"""
|
| 176 |
+
Crée un agent Wikipedia avec tous les outils nécessaires.
|
| 177 |
+
"""
|
| 178 |
+
# Initialisation du modèle (ajustez selon votre configuration)
|
| 179 |
+
model = LiteLLMModel(model_id="gemini/gemini-2.5-flash", api_key=os.getenv("GOOGLE_API_KEY"))
|
| 180 |
+
|
| 181 |
+
system_prompt = """
|
| 182 |
+
Tu es un agent de recherche d'information, tu es capable de trouver des informations sur Wikipédia ou par recherche internet.
|
| 183 |
+
Tu peux exécuter des recherches, récupérer des pages Wikipedia, extraire des tableaux.
|
| 184 |
+
Pour trouver un article, tu peux rechercher sur internet avec le plus de détails puis trouver le premier lien Wikipedia pertinent.
|
| 185 |
+
Si tu ne trouves pas d'outils spécifiques à une tâche, tu peux utiliser la recherche internet pour trouver des informations pertinentes.
|
| 186 |
+
Tu dois toujours fournir des réponses claires et concises, en citant les sources lorsque c'est possible.
|
| 187 |
+
"""
|
| 188 |
+
# Création de l'agent avec les outils
|
| 189 |
+
return CodeAgent(
|
| 190 |
+
tools=[
|
| 191 |
+
search_internet,
|
| 192 |
+
get_wikipedia_page,
|
| 193 |
+
# get_featured_articles_by_year,
|
| 194 |
+
# search_wikipedia_category
|
| 195 |
+
],
|
| 196 |
+
model=model,
|
| 197 |
+
description=system_prompt,
|
| 198 |
+
additional_authorized_imports=["wikipedia", "requests", "bs4", "pandas"]
|
| 199 |
+
)
|
agent/get_question/hf_api.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
|
| 3 |
+
import requests
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
# (Keep Constants as is)
|
| 7 |
+
# --- Constants ---
|
| 8 |
+
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def get_question() :
|
| 12 |
+
questions_url = f"{DEFAULT_API_URL}/questions"
|
| 13 |
+
|
| 14 |
+
print(f"Fetching questions from: {questions_url}")
|
| 15 |
+
try:
|
| 16 |
+
response = requests.get(questions_url, timeout=15)
|
| 17 |
+
response.raise_for_status()
|
| 18 |
+
questions_data = response.json()
|
| 19 |
+
if not questions_data:
|
| 20 |
+
print("Fetched questions list is empty.")
|
| 21 |
+
return "Fetched questions list is empty or invalid format.", None
|
| 22 |
+
print(f"Fetched {len(questions_data)} questions.")
|
| 23 |
+
return questions_data
|
| 24 |
+
except requests.exceptions.RequestException as e:
|
| 25 |
+
print(f"Error fetching questions: {e}")
|
| 26 |
+
return f"Error fetching questions: {e}", None
|
| 27 |
+
except requests.exceptions.JSONDecodeError as e:
|
| 28 |
+
print(f"Error decoding JSON response from questions endpoint: {e}")
|
| 29 |
+
print(f"Response text: {response.text[:500]}")
|
| 30 |
+
return f"Error decoding server response for questions: {e}", None
|
| 31 |
+
except Exception as e:
|
| 32 |
+
print(f"An unexpected error occurred fetching questions: {e}")
|
| 33 |
+
return f"An unexpected error occurred fetching questions: {e}", None
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def get_random_question():
|
| 37 |
+
random_question_url = f"{DEFAULT_API_URL}/random-question"
|
| 38 |
+
print(f"Fetching a random question from: {random_question_url}")
|
| 39 |
+
try:
|
| 40 |
+
response = requests.get(random_question_url, timeout=15)
|
| 41 |
+
response.raise_for_status()
|
| 42 |
+
questions_data = response.json()
|
| 43 |
+
if not questions_data:
|
| 44 |
+
print("Fetched questions list is empty.")
|
| 45 |
+
return "Fetched questions list is empty or invalid format.", None
|
| 46 |
+
return questions_data
|
| 47 |
+
except requests.exceptions.RequestException as e:
|
| 48 |
+
print(f"Error fetching a random question: {e}")
|
| 49 |
+
return f"Error fetching a random question: {e}", None
|
| 50 |
+
except requests.exceptions.JSONDecodeError as e:
|
| 51 |
+
print(f"Error decoding JSON response from a random question endpoint: {e}")
|
| 52 |
+
print(f"Response text: {response.text[:500]}")
|
| 53 |
+
return f"Error decoding server response for a random question: {e}", None
|
| 54 |
+
except Exception as e:
|
| 55 |
+
print(f"An unexpected error occurred fetching a random question: {e}")
|
| 56 |
+
return f"An unexpected error occurred fetching a random question: {e}", None
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def get_file_by_task_id(task_id:str):
|
| 60 |
+
file_by_task_id_url = f"{DEFAULT_API_URL}/files/{task_id}"
|
| 61 |
+
print(f"Fetching a file from: {file_by_task_id_url}")
|
| 62 |
+
try:
|
| 63 |
+
response = requests.get(file_by_task_id_url, timeout=15)
|
| 64 |
+
|
| 65 |
+
response.raise_for_status()
|
| 66 |
+
content_disp = response.headers.get("Content-Disposition")
|
| 67 |
+
file_name = re.findall('filename=(.+)', content_disp)
|
| 68 |
+
questions_data = response.content
|
| 69 |
+
if not questions_data or not file_name:
|
| 70 |
+
print("No file to fetch.")
|
| 71 |
+
return "No file to fetch.", None
|
| 72 |
+
return questions_data, file_name[0].replace('"', '').strip()
|
| 73 |
+
except requests.exceptions.RequestException as e:
|
| 74 |
+
print(f"Error fetching a file: {e}")
|
| 75 |
+
return f"Error fetching a file: {e}", None
|
| 76 |
+
except requests.exceptions.JSONDecodeError as e:
|
| 77 |
+
print(f"Error decoding JSON response from the file by task id endpoint: {e}")
|
| 78 |
+
print(f"Response text: {response.text[:500]}")
|
| 79 |
+
return f"Error decoding server response for the file by task id: {e}", None
|
| 80 |
+
except Exception as e:
|
| 81 |
+
print(f"An unexpected error occurred fetching a file: {e}")
|
| 82 |
+
return f"An unexpected error occurred fetching a file: {e}", None
|
agent/prompts.yaml
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
description: You are a GAIA benchmark AI assistant, very precise, no nonsense. Your sole purpose is to output the minimal, final answer in the format: [ANSWER]. You
|
| 2 |
+
must NEVER output explanations, intermediate steps, reasoning, or comments — only
|
| 3 |
+
the answer, strictly enclosed in `[ANSWER]`.
|
| 4 |
+
rules:
|
| 5 |
+
- id: format
|
| 6 |
+
description: Control output format and token usage.
|
| 7 |
+
constraints:
|
| 8 |
+
- limit_token_used: 65536
|
| 9 |
+
- output_only_final_answer: true
|
| 10 |
+
- wrap_answer_in_brackets: true
|
| 11 |
+
- no_whitespace_outside_brackets: true
|
| 12 |
+
- no_follow_ups_justifications_clarifications: true
|
| 13 |
+
- id: numerical_answers
|
| 14 |
+
description: Guidelines for numerical answers.
|
| 15 |
+
constraints:
|
| 16 |
+
- use_digits_only: true
|
| 17 |
+
- no_commas_symbols_units_unless_required: true
|
| 18 |
+
- no_approximate_words: true
|
| 19 |
+
- id: string_answers
|
| 20 |
+
description: Guidelines for string answers.
|
| 21 |
+
constraints:
|
| 22 |
+
- omit_articles: true
|
| 23 |
+
- use_full_words: true
|
| 24 |
+
- use_text_for_numbers_if_specified: true
|
| 25 |
+
- sort_sets_lists_alphabetically_if_not_specified: true
|
| 26 |
+
- id: lists
|
| 27 |
+
description: Guidelines for list answers.
|
| 28 |
+
constraints:
|
| 29 |
+
- output_comma_separated: true
|
| 30 |
+
- no_conjunctions: true
|
| 31 |
+
- sort_alphabetically_or_numerically: true
|
| 32 |
+
- no_braces_or_brackets_unless_asked: true
|
| 33 |
+
- id: sources
|
| 34 |
+
description: Guidelines for using sources like Wikipedia or web tools.
|
| 35 |
+
constraints:
|
| 36 |
+
- extract_only_precise_fact: true
|
| 37 |
+
- ignore_unrelated_content: true
|
| 38 |
+
- id: file_analysis
|
| 39 |
+
description: Guidelines for using the run_query_with_file tool.
|
| 40 |
+
constraints:
|
| 41 |
+
- use_run_query_with_file_tool: true
|
| 42 |
+
- append_taskid_to_url: true
|
| 43 |
+
- include_exact_answer_only: true
|
| 44 |
+
- no_summarizing_excessive_quoting_or_interpreting: true
|
| 45 |
+
- id: video
|
| 46 |
+
description: Guidelines for using the relevant video tool.
|
| 47 |
+
constraints:
|
| 48 |
+
- use_relevant_video_tool: true
|
| 49 |
+
- include_exact_answer_only: true
|
| 50 |
+
- no_summarizing_excessive_quoting_or_interpreting: true
|
| 51 |
+
- id: minimalism
|
| 52 |
+
description: General minimalism guidelines.
|
| 53 |
+
constraints:
|
| 54 |
+
- no_assumptions_unless_logically_demanded: true
|
| 55 |
+
- choose_narrowest_most_literal_interpretation: true
|
| 56 |
+
- output_unknown_if_answer_not_found: true
|
| 57 |
+
examples:
|
| 58 |
+
- question: What is 2 + 2?
|
| 59 |
+
answer: "[ANSWER]4"
|
| 60 |
+
- question: How many studio albums were published by Mercedes Sosa between 2000 and
|
| 61 |
+
2009 (inclusive)? Use 2022 English Wikipedia.
|
| 62 |
+
answer: "[ANSWER]3"
|
| 63 |
+
- question: Given the following group table on set S = {a, b, c, d, e}, identify
|
| 64 |
+
any subset involved in counterexamples to commutativity.
|
| 65 |
+
answer: "[ANSWER]b, e"
|
| 66 |
+
- question: How many at bats did the Yankee with the most walks in the 1977 regular
|
| 67 |
+
season have that same season?
|
| 68 |
+
answer: "[ANSWER]519"
|
agent/ressources_getter.py
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import os
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
|
| 5 |
+
import pandas as pd
|
| 6 |
+
from smolagents import tool
|
| 7 |
+
|
| 8 |
+
DOWNLOAD_FOLDER = "./download"
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
def create_download_folder_if_not_exist():
|
| 12 |
+
os.makedirs(DOWNLOAD_FOLDER,exist_ok=True)
|
| 13 |
+
|
| 14 |
+
def save_file(binary_file,file_name:str):
|
| 15 |
+
create_download_folder_if_not_exist()
|
| 16 |
+
if binary_file is not None and file_name is not None :
|
| 17 |
+
file_path = os.path.join(DOWNLOAD_FOLDER,file_name)
|
| 18 |
+
open(file_path, 'wb').write(binary_file)
|
| 19 |
+
return file_path
|
| 20 |
+
else :
|
| 21 |
+
print("Pas de fichier")
|
| 22 |
+
return None
|
| 23 |
+
|
| 24 |
+
def get_prompt_with_file_content(prompt:str,file_path:str):
|
| 25 |
+
full_prompt = prompt
|
| 26 |
+
if file_path:
|
| 27 |
+
file_extension = os.path.splitext(file_path)[1].lower()
|
| 28 |
+
print(f"--- Fichier fourni : {file_path} (Type: {file_extension}) ---")
|
| 29 |
+
full_prompt = (
|
| 30 |
+
f"{prompt}\n\n"
|
| 31 |
+
f"Voici le chemin du fichier joint : {file_path}\n"
|
| 32 |
+
)
|
| 33 |
+
return full_prompt
|
| 34 |
+
|
| 35 |
+
@tool
|
| 36 |
+
def extract_text_from_file(file_path: str) -> str:
|
| 37 |
+
"""
|
| 38 |
+
Extrait le texte d'un fichier.
|
| 39 |
+
Ne fonctionne qu'avec les fichier texte (txt, csv, json,etc.).
|
| 40 |
+
Args:
|
| 41 |
+
file_path (str): Chemin du fichier à traiter.
|
| 42 |
+
Returns:
|
| 43 |
+
str: Contenu textuel extrait du fichier.
|
| 44 |
+
"""
|
| 45 |
+
with open(file_path, 'r', encoding='utf-8') as f:
|
| 46 |
+
return f.read()
|
| 47 |
+
|
| 48 |
+
@tool
|
| 49 |
+
def convert_excel_to_text(file_path: str) -> str:
|
| 50 |
+
"""
|
| 51 |
+
Convertit un fichier Excel en texte brut.Ne fonctionne qu'avec les fichiers Excel (.xlsx, .xls).
|
| 52 |
+
Args:
|
| 53 |
+
file_path (str): Chemin du fichier Excel à convertir.
|
| 54 |
+
Returns:
|
| 55 |
+
str: Contenu textuel extrait du fichier Excel.
|
| 56 |
+
"""
|
| 57 |
+
try:
|
| 58 |
+
df = pd.read_excel(file_path)
|
| 59 |
+
return df.to_string(index=False)
|
| 60 |
+
except Exception as e:
|
| 61 |
+
return f"Erreur lors de la conversion du fichier Excel : {e}"
|
| 62 |
+
|
| 63 |
+
@tool
|
| 64 |
+
def delete_tmp_files() -> None:
|
| 65 |
+
"""
|
| 66 |
+
Supprime les fichiers temporaires.
|
| 67 |
+
"""
|
| 68 |
+
try:
|
| 69 |
+
folder = Path(DOWNLOAD_FOLDER)
|
| 70 |
+
for file in folder.iterdir():
|
| 71 |
+
if file.is_file():
|
| 72 |
+
file.unlink()
|
| 73 |
+
print(f"Fichier temporaire supprimé : {file.name}")
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f"Erreur lors de la suppression du fichier : {e}")
|
app.py
CHANGED
|
@@ -4,20 +4,12 @@ import requests
|
|
| 4 |
import inspect
|
| 5 |
import pandas as pd
|
| 6 |
|
|
|
|
|
|
|
| 7 |
# (Keep Constants as is)
|
| 8 |
# --- Constants ---
|
| 9 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 10 |
|
| 11 |
-
# --- Basic Agent Definition ---
|
| 12 |
-
# ----- THIS IS WERE YOU CAN BUILD WHAT YOU WANT ------
|
| 13 |
-
class BasicAgent:
|
| 14 |
-
def __init__(self):
|
| 15 |
-
print("BasicAgent initialized.")
|
| 16 |
-
def __call__(self, question: str) -> str:
|
| 17 |
-
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
| 18 |
-
fixed_answer = "This is a default answer."
|
| 19 |
-
print(f"Agent returning fixed answer: {fixed_answer}")
|
| 20 |
-
return fixed_answer
|
| 21 |
|
| 22 |
def run_and_submit_all( profile: gr.OAuthProfile | None):
|
| 23 |
"""
|
|
@@ -80,7 +72,7 @@ def run_and_submit_all( profile: gr.OAuthProfile | None):
|
|
| 80 |
print(f"Skipping item with missing task_id or question: {item}")
|
| 81 |
continue
|
| 82 |
try:
|
| 83 |
-
submitted_answer = agent(question_text)
|
| 84 |
answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
|
| 85 |
results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
|
| 86 |
except Exception as e:
|
|
|
|
| 4 |
import inspect
|
| 5 |
import pandas as pd
|
| 6 |
|
| 7 |
+
from Final_Assignment_Template.agent.agent import BasicAgent
|
| 8 |
+
|
| 9 |
# (Keep Constants as is)
|
| 10 |
# --- Constants ---
|
| 11 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
def run_and_submit_all( profile: gr.OAuthProfile | None):
|
| 15 |
"""
|
|
|
|
| 72 |
print(f"Skipping item with missing task_id or question: {item}")
|
| 73 |
continue
|
| 74 |
try:
|
| 75 |
+
submitted_answer = agent(question_text,task_id)
|
| 76 |
answers_payload.append({"task_id": task_id, "submitted_answer": submitted_answer})
|
| 77 |
results_log.append({"Task ID": task_id, "Question": question_text, "Submitted Answer": submitted_answer})
|
| 78 |
except Exception as e:
|
requirements.txt
CHANGED
|
@@ -1,2 +1,17 @@
|
|
| 1 |
gradio
|
| 2 |
-
requests
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
gradio
|
| 2 |
+
requests
|
| 3 |
+
tools
|
| 4 |
+
hf_xet
|
| 5 |
+
wikipedia
|
| 6 |
+
langchain_community
|
| 7 |
+
langchain[google-genai]
|
| 8 |
+
smolagents[toolkit]
|
| 9 |
+
smolagents
|
| 10 |
+
litellm
|
| 11 |
+
python-dotenv
|
| 12 |
+
wikipedia-api
|
| 13 |
+
beautifulsoup4
|
| 14 |
+
duckduckgo-search
|
| 15 |
+
yt_dlp
|
| 16 |
+
google-generativeai
|
| 17 |
+
openpyxl
|