tools.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import os
  2. import pandas as pd
  3. from langchain_core.tools import tool
  4. from langchain_community.tools import DuckDuckGoSearchRun
  5. import matplotlib.pyplot as plt
  6. import seaborn as sns
  7. import matplotlib
  8. matplotlib.use('Agg') # Force Matplotlib à ne pas ouvrir de fenêtre graphique
  9. @tool
  10. def convert_csv_to_excel(csv_path: str):
  11. """Convertit un fichier CSV en Excel (.xlsx)."""
  12. if not os.path.exists(csv_path):
  13. return f"Désolé, je ne trouve pas le fichier '{csv_path}'. Vérifiez qu'il est bien présent dans le dossier du projet."
  14. try:
  15. df = pd.read_csv(csv_path)
  16. new_path = csv_path.replace(".csv", ".xlsx")
  17. df.to_excel(new_path, index=False)
  18. return f"Succès : Le fichier a été converti en {new_path}"
  19. except Exception as e:
  20. return f"Erreur lors de la lecture du CSV : {str(e)}"
  21. BASE_DIR = os.path.dirname(os.path.abspath(__file__))
  22. @tool
  23. def inspect_data(file_name: str):
  24. """
  25. Explore le fichier situé dans le dossier 'data/' pour retourner les colonnes et un aperçu.
  26. Passer uniquement le nom du fichier (ex: 'data.csv').
  27. """
  28. # 1. On nettoie le nom du fichier au cas où l'IA ajoute des guillemets
  29. clean_name = file_name.strip().replace("'", "").replace('"', "")
  30. # 2. On construit le chemin ABSOLU vers le dossier data
  31. # On suppose que ton script est à la racine du projet
  32. data_path = os.path.join(os.getcwd(), "data", clean_name)
  33. try:
  34. # 3. Vérification de l'existence du fichier
  35. if not os.path.exists(data_path):
  36. return f"Erreur : Le fichier '{clean_name}' est introuvable dans le dossier data/."
  37. # 4. Lecture selon l'extension (Note : correction de 'endiwith' en 'endswith')
  38. if data_path.lower().endswith(".csv"):
  39. df = pd.read_csv(data_path) # Utilisation de la variable data_path, PAS de la chaîne "file_path"
  40. elif data_path.lower().endswith((".xlsx", ".xls")):
  41. df = pd.read_excel(data_path)
  42. else:
  43. return "Format de fichier non supporté. Utilisez .csv ou .xlsx"
  44. # 5. Extraction des infos
  45. columns_names = df.columns.tolist()
  46. preview = df.head(3).to_string()
  47. return f"Colonnes trouvées : {columns_names}\n\nAperçu des données :\n{preview}"
  48. except Exception as e:
  49. return f"Erreur lors de l'inspection : {str(e)}"
  50. @tool
  51. def excel_code_interpreter(file_path: str, code: str):
  52. """Exécute du code Python sur le fichier (CSV ou Excel) chargé dans 'df'."""
  53. # Nettoyage du nom de fichier
  54. file_name = os.path.basename(file_path.strip().replace("'", "").replace('"', ""))
  55. # 1. Définition de la priorité : Dossier 'data' d'abord
  56. data_folder_path = os.path.join(BASE_DIR, "data", file_name)
  57. root_path = os.path.join(BASE_DIR, file_name)
  58. # Choix du chemin
  59. if os.path.exists(data_folder_path):
  60. full_path = data_folder_path
  61. elif os.path.exists(root_path):
  62. full_path = root_path
  63. else:
  64. # Si rien n'est trouvé, on aide l'agent avec un message clair
  65. files_in_data = os.listdir(os.path.join(BASE_DIR, "data")) if os.path.exists(os.path.join(BASE_DIR, "data")) else "Dossier data absent"
  66. return f"ERREUR : Fichier '{file_name}' introuvable. Contenu de 'data/': {files_in_data}"
  67. try:
  68. # Lecture selon l'extension
  69. if file_name.endswith('.csv'):
  70. df = pd.read_csv(full_path)
  71. else:
  72. df = pd.read_excel(full_path)
  73. safe_globals={"__builtins__" :{}}
  74. # Injection des bibliothèques pour l'IA
  75. local_vars = {"df": df, "pd": pd, "plt": plt, "result": None}
  76. exec(code, safe_globals , local_vars)
  77. return str(local_vars.get("result", "Exécution terminée."))
  78. except Exception as e:
  79. return f"ERREUR PYTHON : {str(e)}"
  80. @tool
  81. def generate_excel_chart(file_path: str, code: str, output_image: str = "chart.png"):
  82. """
  83. Exécute du code Python pour générer un graphique Matplotlib/Seaborn à partir du fichier Excel.
  84. Le DataFrame est chargé dans 'df'.
  85. IMPORTANT : Le code doit finir par plt.savefig(output_image).
  86. """
  87. # Force le mode sans interface graphique (important pour les scripts automatisés)
  88. plt.switch_backend('Agg')
  89. plt.clf() # Nettoie les anciens graphiques en mémoire
  90. full_path = os.path.join(BASE_DIR, file_path)
  91. try:
  92. df = pd.read_excel(full_path)
  93. # Environnement d'exécution pour l'IA
  94. local_vars = {
  95. "df": df,
  96. "plt": plt,
  97. "sns": sns,
  98. "output_image": output_image
  99. }
  100. exec(code, {}, local_vars)
  101. if os.path.exists(output_image):
  102. return f"Succès : Graphique généré et enregistré sous '{output_image}'."
  103. else:
  104. return "Erreur : Le code a été exécuté mais aucun fichier image n'a été créé."
  105. except Exception as e:
  106. return f"Erreur lors de la génération du graphique : {str(e)}"
  107. ddg = DuckDuckGoSearchRun()
  108. @tool
  109. def search_tool(query : str) :
  110. """Recherche sur le web. Limité pour économiser les tokens."""
  111. try:
  112. results = ddg.run(query)
  113. if not results:
  114. return "Aucun résultat trouvé."
  115. # 1. On nettoie les espaces superflus pour gagner des tokens
  116. clean_results = " ".join(results.split())
  117. # 2. On limite intelligemment (ex: 1200 chars pour plus de contexte)
  118. # Mais on s'assure de ne pas couper un mot au milieu
  119. limit = 1200
  120. if len(clean_results) <= limit:
  121. return clean_results
  122. return clean_results[:limit] + "... [Résultat tronqué pour économie]"
  123. except Exception as e:
  124. return f"Erreur lors de la recherche : {str(e)}"