| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- import os
- from typing import Annotated, Sequence, TypedDict, Optional , List
- from dotenv import load_dotenv
- from langchain_openai import ChatOpenAI
- from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
- from langgraph.graph.message import add_messages
- # Import de tes outils corrigés
- from tools import excel_code_interpreter, convert_csv_to_excel , generate_excel_chart , search_tool , inspect_data
- load_dotenv()
- # 1. Définition du State
- class AgentState(TypedDict):
- messages: Annotated[Sequence[BaseMessage], add_messages]
- current_df_path: Optional[str]
- generated_charts : List[str]
- # 2. Configuration du Modèle et des Outils
- model_gpt = ChatOpenAI(model="o3-mini")
- tools = [ search_tool , excel_code_interpreter, convert_csv_to_excel , generate_excel_chart , inspect_data ]
- model_with_tools = model_gpt.bind_tools(tools)
- # 3. Définition des Nœuds
- def agent_analyseur(state: AgentState):
- prompt = (
- "Tu es l'Analyseur Stratégique. Ton rôle est de décomposer la demande utilisateur en étapes techniques claires.\n"
- "RÈGLES CRITIQUES :\n"
- "1. Si le fichier est en .csv, ordonne IMMÉDIATEMENT sa conversion via 'convert_csv_to_excel'. Ne demande pas la permission.\n"
- "2. Définis un plan d'action claire \n"
- "3. Ne pose JAMAIS de questions sur les données (prix, stock). L'Exécuteur doit les trouver lui-même via les outils.\n"
- "4. Sois concis : Ton message doit être une directive pour l'Exécuteur, pas une conversation avec l'utilisateur."
- )
- msg = [SystemMessage(content=prompt)] + state["messages"]
- response = model_gpt.invoke(msg)
- return {"messages": [response]}
- def agent_executor(state: AgentState):
- # 1. On récupère le chemin actuel depuis le State
- # Si current_df_path est None, on met data.xlsx par défaut
- file_path = state.get("current_df_path") or "data.xlsx"
- # 2. On construit un prompt qui contient le VRAI chemin
- prompt = (
- f"Tu es un Data Scientist expert spécialisé en automatisation. Le fichier cible se trouve dans le dossier 'data/' : '{file_path}'.\n"
- "PROTOCOLE D'ACTION IMPÉRATIF :\n"
- "1. INSPECTION PRÉALABLE : Avant de générer le moindre code Python, appelle TOUJOURS 'inspect_data'.\n Tu dois connaître les colonnes réelles avant de coder.\n"
- "2. ACTION D'ABORD : Si tu n'as pas les données externes, appelle 'search_tool' immédiatement.\n"
- "3. ZÉRO SIMULATION : Il est strictement interdit d'inventer des prix ou des stocks. Si l'outil 'search_tool' donne une plage de prix (ex: 30-40€), calcule la moyenne (35€).\n"
- "4. LOGIQUE PANDAS : Ne fais aucun calcul manuel. Utilise 'df' pour filtrer le produit exact (ex: df[df['Produit'] == 'Souris']).\n"
- "5. VARIABLE RESULT : Ton script Python DOIT se terminer par 'result = ...'. C'est cette variable qui sera transmise au système.\n"
- "6. PERSISTANCE : Si un graphique est demandé, utilise 'plt.savefig('outputs/nom_du_graphe.png')'.\n"
- "Tu es un moteur d'exécution froid et précis."
- )
- # 3. Préparation des messages
- messages = [SystemMessage(content=prompt)] + state["messages"]
-
- # 4. Appel du modèle avec les outils
- response = model_with_tools.invoke(messages)
-
- return {"messages": [response]}
- def agent_reporter(state : AgentState) :
- prompt_reporter = (
- "Tu es l'Agent de Reporting. Ton rôle est de traduire les résultats techniques en une synthèse claire.\n"
- "CONSIGNES :\n"
- "1. FIDÉLITÉ : Ne parle que des données réellement trouvées et calculées par l'Exécuteur.\n"
- "2. STRUCTURE : Présente les faits marquants, puis les chiffres clés, puis les livrables (graphiques/fichiers).\n"
- "3. ADAPTATION : Si l'analyse porte sur des ventes, utilise un vocabulaire commercial. Si c'est de l'actuariat, utilise un vocabulaire technique.\n"
- "4. NEUTRALITÉ : Ne propose pas de texte de remplissage si les données sont manquantes. Sois factuel."
- )
- messages = [SystemMessage(content=prompt_reporter)] + state["messages"]
- response = model_gpt.invoke(messages)
- return{"messages" : [response]}
|