Procházet zdrojové kódy

Version works : Validé dans la presentation Teams Dataltist

Abdenbi IABBADENE před 3 týdny
rodič
revize
0d39ba0050

+ 89 - 43
Agents.py

@@ -7,6 +7,11 @@ from langgraph.graph.message import add_messages
 from langchain_google_genai import ChatGoogleGenerativeAI 
 from langchain_groq import ChatGroq 
 from langfuse import get_client
+import pandas as pd
+from langfuse.langchain import CallbackHandler
+ 
+# Initialize Langfuse CallbackHandler for Langchain (tracing)
+langfuse_handler = CallbackHandler()
 
 
 
@@ -28,25 +33,53 @@ model =ChatGroq(model="llama-3.3-70b-versatile")
 
 #model_llama=ChatGoogleGenerativeAI(model="gemini-2.5-flash")
 
-model_gpt = ChatOpenAI(model="o3-mini") 
+model_gpt = ChatOpenAI(model="gpt-5.3-codex" ) 
+
+model_gpt_5 = ChatOpenAI(model="o4-mini" )
 tools = [ search_tool  , excel_code_interpreter,  inspect_data ]
-model_with_tools = model.bind_tools(tools)
+model_with_tools = model_gpt.bind_tools(tools)
 
 
 
 
 # 3. Définition des Nœuds
 def agent_analyseur(state: AgentState):
+    # --- PHASE D'INSPECTION AUTOMATIQUE ---
+    # On récupère le chemin du fichier depuis le state
+    file_path = state.get("current_df_path")
+    inspection_info = ""
+    
+    if file_path and os.path.exists(file_path):
+        try:
+            # Lecture des 5 premières lignes pour comprendre la structure
+            df_temp = pd.read_csv(file_path, nrows=5) if file_path.endswith('.csv') else pd.read_excel(file_path, nrows=5)
+            columns_list = df_temp.columns.tolist()
+            sample_data = df_temp.head(2).to_string()
+            inspection_info = f"\n\n### DONNÉES RÉELLES DU FICHIER :\n- Colonnes détectées : {columns_list}\n- Aperçu des données :\n{sample_data}"
+        except Exception as e:
+            inspection_info = f"\n\n⚠️ Erreur lors de l'inspection du fichier : {e}"
+
+    # --- CONSTRUCTION DU PROMPT AVEC LES DONNÉES RÉELLES ---
     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"
+            "Tu es l'Analyseur Stratégique de Dataltist. Ton rôle est de définir le 'QUOI' faire, pas le 'COMMENT'.\n\n"
+            "### RÈGLES D'OR :\n"
+            "1. PAS DE CODE : Ne génère JAMAIS de blocs de code Python (```python). C'est le rôle de l'Exécuteur.\n"
+            "2. PLAN D'ACTION : Liste les étapes logiques en utilisant les noms de colonnes exacts.\n"
+            "3. INSPECTION : Base-toi uniquement sur les colonnes détectées ci-dessous.\n"
+            "4. CONCISION : Sois une tour de contrôle, donne des ordres clairs et précis.\n"
+            f"{inspection_info}"
+        )
     
-        "1. Définis un plan d'action claire \n"
-        "2. Ne pose JAMAIS de questions sur les données (prix, stock). L'Exécuteur doit les trouver lui-même via les outils.\n"
-        "3. Sois concis : Ton message doit être une directive pour l'Exécuteur, pas une conversation avec l'utilisateur."
-    )
+    config_analyseur = {
+        "callbacks": [langfuse_handler],
+        "metadata": {"agent_name": "Analyseur"},
+        "tags": ["Dataltist", "Planning"]
+    }
+
     msg = [SystemMessage(content=prompt)] + state["messages"]
-    response = model.invoke(msg)
+    response = model.invoke(msg , config=config_analyseur)
+    
+    # On retourne la réponse de l'IA qui contient maintenant le plan basé sur les vraies colonnes
     return {"messages": [response]}
 
 
@@ -55,30 +88,39 @@ 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"
+    clean_path = file_path.replace("\\", "/")
 
     # 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"
+        f"Tu es un Data Scientist expert spécialisé en automatisation. Le fichier cible est disponible ici : '{file_path}'.\n\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 etre complis avec tout les imports et  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."
-        "STRUCTURE DE TA RÉPONSE POST-OUTIL :\n"
+        "1. CONFIANCE STRATÉGIQUE : Utilise les noms de colonnes fournis par l'Analyseur ( Obligatoire , change pas ).\n"
+        "2. RECHERCHE EXTERNE : Utilise 'search_tool' si des données manquent.\n"
+        "3. ZÉRO SIMULATION : Ne jamais inventer de données.\n"
+        "4. LOGIQUE PANDAS : Utilise 'df' pour filtrer les données exactes.\n"
+        "5. CODE AUTONOME : Ton script Python doit être complet et prêt à l'exécution. \n"
+        f"   - Tu DOIS impérativement définir la variable `file_path = '{clean_path}'` au début de ton code.\n"
+        "   - Inclus tous les imports (pandas as pd, matplotlib.pyplot as plt, etc.).\n"
+        "   - Termine impérativement par 'result = ...'.\n"
+        "6. PERSISTANCE : Utilise 'plt.savefig('outputs/nom_du_graphe.png')' et ferme la figure avec 'plt.close()'.\n\n"
+        "Tu es un moteur d'exécution froid et précis. Pas de discours.\n"
+        "STRUCTURE DE RÉPONSE :\n"
         "- 'Statut : Code exécuté avec succès.'\n"
         "- 'Fichiers : [liste des .png générés]'\n"
         "- 'Validation : Les données de [Colonnes] ont été traitées.'\n"
-        "PAS DE DISCOURS, PAS D'ÉTAPES."
     )
 
     # 3. Préparation des messages
     messages = [SystemMessage(content=prompt)] + state["messages"]
+
+    config_executor= {
+        "callbacks": [langfuse_handler],
+        "metadata": {"agent_name": "executor"},
+        "tags": ["Dataltist", "executor"]
+    }
     
     # 4. Appel du modèle avec les outils
-    response = model_with_tools.invoke(messages)
+    response = model_with_tools.invoke(messages , config= config_executor )
     
     return {"messages": [response]}
 
@@ -87,30 +129,34 @@ def agent_executor(state: AgentState):
 def agent_reporter(state : AgentState) : 
 
     prompt_reporter = (
-        "Tu es l'Agent de Reporting.\n"
-        "Ton rôle est de transformer les résultats techniques fournis par l'Exécuteur en un compte rendu court, clair et factuel.\n\n"
-
-        "RÈGLES STRICTES :\n"
-        "- N'invente aucune information.\n"
-        "- Ne répète pas les mêmes informations.\n"
-        "- Évite les phrases génériques ou marketing.\n"
-        "- Sois concis et direct.\n"
-        "- Utilise uniquement les données réellement calculées.\n\n"
-
-        "FORMAT DE SORTIE OBLIGATOIRE :\n"
-        "1) Résultats clés\n"
-        "- Liste courte des résultats principaux (produits les plus vendus, top commerciaux, etc.)\n\n"
-        "2) Observations\n"
-        "- Interprétation courte basée uniquement sur les résultats.\n\n"
-        "3) Livrables générés\n"
-        "- Liste des graphiques et fichiers créés avec leurs chemins exacts.\n\n"
-
-        "IMPORTANT :\n"
-        "- Maximum 6 à 8 lignes au total.\n"
-        "- Pas de conclusion inutile.\n"
-        "- Pas de texte explicatif long."
+        "Tu es l'Agent de Reporting de Dataltist.\n"
+        "Ton rôle : Convertir les logs de l'Exécuteur en une synthèse factuelle pour l'utilisateur.\n\n"
+
+        "RÈGLES CRITIQUES (ANTI-SILENCE) :\n"
+        "- DISPONIBILITÉ : Tu dois TOUJOURS générer une réponse, même pour confirmer une erreur ou une absence de données.\n"
+        "- STRUCTURE : Utilise des tirets pour lister les points clés.\n"
+        "- SYNTHÈSE : Si l'Exécuteur donne 'result = 42', écris 'Résultat : 42'.\n"
+        "- FICHIERS : Liste uniquement le nom des fichiers (ex: graphe_incendie.png), JAMAIS le chemin 'outputs/'.\n\n"
+
+        "FORMAT IMPÉRATIF :\n"
+        "1. Résumé des données traitées.\n"
+        "2. Valeurs calculées (moyennes, totaux, etc.).\n"
+        "3. Liste des visuels générés (si présents).\n\n"
+        "4. L'affichage doit etre claire , tu laisse les espaces .\n\n"
+
+        "INTERDICTIONS :\n"
+        "- Pas de politesse inutile ('Voici le rapport...', 'J'espère que...').\n"
+        "- Pas de répétition des étapes techniques de l'agent.\n"
+        "- Pas de phrases vides si l'exécution a échoué : explique brièvement l'échec."
+
+        "RÈGLES D'AFFICHAGE DES FICHIERS :\n"
+        "1. CITATION : Si l'Exécuteur a généré des fichiers (images ou données), cite-les obligatoirement.\n"
+        "2. FORMAT : Utilise TOUJOURS ce format exact pour introduire un fichier : \n"
+        "   '📊 Visualisation générée : [nom_du_fichier.png]'\n"
+        "   '📥 Fichier disponible : [nom_du_fichier.csv/xlsx]'\n"
+        "3. SANS CHEMIN : Ne mentionne JAMAIS le dossier 'outputs/' ou 'data/'. Utilise uniquement le nom final du fichier.\n\n"
     )
     messages = [SystemMessage(content=prompt_reporter)] + state["messages"]
 
-    response = model.invoke(messages) 
+    response = model.invoke(messages  ) 
     return{"messages" : [response]}

binární
__pycache__/Agents.cpython-313.pyc


binární
__pycache__/suggestions.cpython-313.pyc


binární
__pycache__/tools.cpython-313.pyc


binární
__pycache__/workflow_Agent.cpython-313.pyc


+ 55 - 0
pricing.py

@@ -0,0 +1,55 @@
+import matplotlib.pyplot as plt
+
+# ---------------------------
+# Données complètes pour agents IA avec prix
+# ---------------------------
+agents_detailed = [
+    # Planificateur / Brain
+    ["Planificateur", "GPT-5.2", "Très puissant", "Élevé", "Décomposition tâches complexes", "Idéal grandes entreprises", 1.75, 14.00],
+    ["Planificateur", "Claude Opus 4.6", "Puissant", "Moyen", "Raisonnement long, multi-étapes", "Bon pour workflows longs", 5.00, 25.00],
+    ["Planificateur", "Gemini 3.1 Pro", "Très puissant", "Élevé", "Multimodal, long contexte", "Excellente intégration multimédia", 2.00, 12.00],
+    ["Planificateur", "GPT-5.1 Codex", "Puissant", "Moyen", "Planification + code workflow", "Idéal pour automatisation", 1.75, 14.00],
+    ["Planificateur", "GPT-4.1", "Correct", "Bas", "Raisonnement basique, rapide", "Projets limités / budget réduit", 3.00, 12.00],
+
+    # Exécutant / Tool Agent
+    ["Exécutant", "GPT-5.1 Codex Max", "Très puissant", "Élevé", "Génération de code multi-fichiers", "Idéal pour Excel, graphiques", 1.75, 14.00],
+    ["Exécutant", "Claude Sonnet 4.6", "Puissant", "Moyen", "Manipulation fichiers et outils", "Bon pour automatisation des tâches", 3.00, 15.00],
+    ["Exécutant", "Gemini 3.1 Pro", "Très puissant", "Élevé", "Exécution multimodale, scripts complexes", "Gestion de workflows lourds", 2.00, 12.00],
+    ["Exécutant", "GPT-4.1", "Correct", "Bas", "Scripts simples et rapides", "Projets simples, faible budget", 3.00, 12.00],
+    ["Exécutant", "GPT-5 mini", "Bas", "Très bas", "Scripts simples, rapide", "Prototypage rapide", 0.25, 2.00],
+
+    # Rapporteur / Résumeur
+    ["Rapporteur", "GPT-5.2", "Très puissant", "Élevé", "Synthèse logique et claire", "Rapports clients complexes", 1.75, 14.00],
+    ["Rapporteur", "GPT-4.1", "Puissant", "Moyen", "Rapports structurés", "Rapports quotidiens / semi-complexes", 3.00, 12.00],
+    ["Rapporteur", "Claude Sonnet 4.6", "Puissant", "Moyen", "Rapports détaillés", "Bon pour multi-étapes", 3.00, 15.00],
+    ["Rapporteur", "Gemini 3.1 Pro", "Très puissant", "Élevé", "Synthèse multimodale", "Rapports complexes multimédia", 2.00, 12.00],
+    ["Rapporteur", "GPT-5 mini", "Correct", "Bas", "Rapports courts rapides", "Projets simples", 0.25, 2.00],
+]
+
+# ---------------------------
+# Création du tableau
+# ---------------------------
+fig, ax = plt.subplots(figsize=(20, 15))
+ax.axis('off')
+
+# Colonnes du tableau
+columns = ["Rôle Agent", "Modèle", "Puissance", "Coût", "Points forts", "Contexte d'usage", "Input ($/1M tokens)", "Output ($/1M tokens)"]
+
+# Création du tableau matplotlib
+table = ax.table(
+    cellText=agents_detailed,
+    colLabels=columns,
+    loc='center',
+    cellLoc='center',
+    colColours=["#FFD700", "#ADD8E6", "#90EE90", "#FFB6C1", "#E0FFFF", "#FFFACD", "#FFE4B5", "#FFDAB9"]
+)
+
+# Style et formatage
+table.auto_set_font_size(False)
+table.set_fontsize(9)
+table.auto_set_column_width(list(range(len(columns))))
+ax.set_title("🤖 Tableau complet des modèles pour agents IA avec prix Input/Output", fontsize=16, fontweight='bold')
+
+# Affichage
+plt.tight_layout()
+plt.show()

+ 53 - 0
suggestions.py

@@ -0,0 +1,53 @@
+def get_suggestions(filename):
+    fname = filename.lower()
+    
+    # --- CATEGORIE 1 : BANQUE / FINANCE ---
+    if any(word in fname for word in ["bank", "banque", "loan", "credit", "finance"]):
+        return [
+            "📊 Décris-moi la structure de ce dataset bancaire",
+            "🎓 Quel niveau d'éducation a le solde (balance) moyen le plus élevé ?",
+            "📈 Graphique : Corrélation entre l'âge et le solde moyen",
+            "🎯 Jobs les plus communs pour les clients ayant accepté la campagne (target 'yes')",
+            "🔮 Prédiction : Relation entre nombre de contacts et succès de la campagne",
+            "🧼 Nettoie les données et crée un tableau récapitulatif par niveau d'études"
+        ]
+    
+    # --- CATEGORIE 2 : RETAIL / E-COMMERCE ---
+    elif any(word in fname for word in ["retail", "vente", "sales", "shop", "online"]):
+        return [
+            "💰 Quel mois a généré le chiffre d'affaires (CA) le plus élevé ?",
+            "📅 Courbe d'évolution : Revenus mensuels vs Quantités vendues",
+            "⏰ Is revenue higher in the morning or afternoon? (Analyse horaire)",
+            "🌍 Top 5 des pays générant le plus de profit",
+            "🛒 Panier moyen : Analyse de la valeur des transactions par client",
+            "📦 Quels sont les 3 produits les plus vendus par catégorie ?"
+        ]
+
+    # --- CATEGORIE 3 : RESSOURCES HUMAINES (RH) ---
+    elif any(word in fname for word in ["hr", "rh", "employee", "salary", "churn"]):
+        return [
+            "👥 Répartition des employés par département et par genre",
+            "💸 Analyse des salaires : Moyenne par niveau d'expérience",
+            "📉 Facteurs principaux influençant le départ des employés (Churn)",
+            "🏠 Corrélation entre le télétravail et la performance perçue",
+            "📊 Graphique : Satisfaction au travail vs Ancienneté"
+        ]
+
+    # --- CATEGORIE 4 : ASSURANCE (Ton projet Dataltist !) ---
+    elif any(word in fname for word in ["insurance", "assurance", "claim", "premium", "fire"]):
+        return [
+            "🔥 Prédiction des primes d'assurance incendie",
+            "📋 Analyse des sinistres par région géographique",
+            "⚖️ Ratio sinistre/prime par type de contrat",
+            "📉 Évolution des demandes d'indemnisation sur l'année",
+            "🧼 Créer un segment de clients à 'Haut Risque'"
+        ]
+
+    # --- PAR DÉFAUT (GÉNÉRIQUE) ---
+    return [
+        "🔍 Fais une analyse exploratoire (EDA) complète",
+        "🔗 Quelles sont les 5 corrélations les plus fortes ?",
+        "📉 Résumé statistique des variables numériques",
+        "🧼 Identifie et liste les valeurs manquantes ou aberrantes",
+        "📊 Génère un dashboard visuel des indicateurs clés"
+    ]

+ 42 - 0
test__.py

@@ -0,0 +1,42 @@
+import os
+from langfuse import Langfuse
+
+# 1. On définit les clés manuellement pour être SÛR à 100%
+# Remplace les pointillés par tes vraies clés
+PUBLIC_KEY = "pk-lf-f07364b3-d0a6-4252-8d65-447500b27cb7"
+SECRET_KEY = "sk-lf-da8a0214-de29-43e0-9c53-f85f8371a37f"
+HOST = "https://cloud.langfuse.com"
+
+print("--- Démarrage du test d'authentification Langfuse ---")
+
+try:
+    # 2. Initialisation explicite
+    langfuse = Langfuse(
+        public_key=PUBLIC_KEY,
+        secret_key=SECRET_KEY,
+        host=HOST,
+        debug=True # Active le mode debug pour voir ce qui se passe
+    )
+
+    # 3. Test d'envoi d'une trace simple
+    print("Tentative d'envoi d'une trace de test...")
+    trace = langfuse.trace(name="Test Authentification Dataltist")
+    
+    # 4. Envoi d'un score de test
+    print("Tentative d'envoi d'un score...")
+    langfuse.score(
+        trace_id=trace.id,
+        name="test_score",
+        value=1
+    )
+
+    # 5. Forcer l'envoi vers le serveur
+    langfuse.flush()
+    
+    print("\n✅ SUCCÈS : Aucune erreur d'authentification détectée.")
+    print(f"Vérifie ton dashboard Langfuse, tu devrais voir une trace nommée 'Test Authentification Dataltist'.")
+    print(f"ID de la trace envoyée : {trace.id}")
+
+except Exception as e:
+    print(f"\n❌ ÉCHEC : Une erreur est survenue.")
+    print(f"Détails de l'erreur : {str(e)}")

binární
~$Rapport_Analytique.xlsx