mirror of
https://github.com/Ladebeze66/llm_ticket3.git
synced 2025-12-13 10:46:51 +01:00
1704-14:04
This commit is contained in:
parent
9885f14e3b
commit
f7986bf84c
@ -5,6 +5,7 @@ import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from loaders.ticket_data_loader import TicketDataLoader
|
||||
from ..utils.pipeline_logger import sauvegarder_donnees
|
||||
|
||||
logger = logging.getLogger("AgentTicketAnalyser")
|
||||
|
||||
@ -20,7 +21,7 @@ class AgentTicketAnalyser(BaseAgent):
|
||||
# Configuration adaptée à l'analyse structurée pour Mistral Large
|
||||
self.temperature = 0.1
|
||||
self.top_p = 0.8
|
||||
self.max_tokens = 6000
|
||||
self.max_tokens = 4000
|
||||
|
||||
# Prompt système clair, structuré, optimisé pour une analyse exhaustive
|
||||
self.system_prompt = """Tu es un expert en analyse de tickets pour le support informatique de BRG-Lab (client : CBAO).
|
||||
@ -28,8 +29,9 @@ class AgentTicketAnalyser(BaseAgent):
|
||||
Tu dois :
|
||||
1. Identifier le client et résumer la demande.
|
||||
2. Reformuler les questions implicites du ticket (à partir du `name` et `description`).
|
||||
3. Nettoyer et structurer les échanges client/support en conservant les informations utiles (liens, modules, options, erreurs).
|
||||
4. Extraire les éléments à observer dans les captures (pour l'agent image).
|
||||
3. Nettoyer et structurer les échanges client/support en conservant les informations utiles (liens, modules, options, erreurs) et en évitant d'introduire des éléments non pertinents.
|
||||
4. Conserver tous les messages, même ceux qui semblent moins pertinents, pour maintenir le contexte complet de la discussion, y compris les détails spécifiques comme les couleurs ou les termes techniques.
|
||||
5. Extraire les éléments à observer dans les captures (pour l'agent image).
|
||||
|
||||
Structure de sortie :
|
||||
1. Résumé du contexte
|
||||
@ -41,7 +43,10 @@ IMPORTANT :
|
||||
- Ne propose pas de solution
|
||||
- Garde tous les liens et noms de modules
|
||||
- Ne transforme pas les propos sauf pour supprimer les bruits inutiles (signatures, mails automatiques)
|
||||
- Ne reformule pas les messages sauf si cela clarifie les intentions sans altérer leur sens
|
||||
- Ne reformule pas les messages sauf si cela clarifie les intentions sans altérer leur sens.
|
||||
- Assure-toi que tous les messages sont inclus dans le fil de discussion, même s'ils semblent redondants ou peu clairs.
|
||||
- Évite d'introduire des éléments fictifs ou non mentionnés dans les messages d'origine.
|
||||
- Conserve le contenu intégral des messages, même s'ils contiennent des éléments de discussion qui semblent hors sujet.
|
||||
"""
|
||||
|
||||
self.ticket_loader = TicketDataLoader()
|
||||
@ -78,6 +83,23 @@ IMPORTANT :
|
||||
response = self.llm.interroger(prompt)
|
||||
logger.info("Analyse du ticket terminée avec succès")
|
||||
print(f" Analyse terminée: {len(response)} caractères")
|
||||
|
||||
# Sauvegarde dans pipeline
|
||||
result = {
|
||||
"prompt": prompt,
|
||||
"response": response,
|
||||
"metadata": {
|
||||
"timestamp": self._get_timestamp(),
|
||||
"source_agent": self.nom,
|
||||
"ticket_id": ticket_code,
|
||||
"model_info": {
|
||||
"model": getattr(self.llm, "modele", str(type(self.llm))),
|
||||
**getattr(self.llm, "params", {})
|
||||
}
|
||||
}
|
||||
}
|
||||
sauvegarder_donnees(ticket_code, "analyse_ticket", result, base_dir="reports", is_resultat=True)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur d'analyse: {str(e)}")
|
||||
return f"ERREUR: {str(e)}"
|
||||
@ -128,12 +150,11 @@ IMPORTANT :
|
||||
for i, msg in enumerate(messages):
|
||||
if not isinstance(msg, dict):
|
||||
continue
|
||||
auteur = msg.get("from", "inconnu")
|
||||
auteur = msg.get("author_id", "inconnu")
|
||||
role = "CLIENT" if "client" in auteur.lower() else "SUPPORT" if "support" in auteur.lower() else "AUTRE"
|
||||
date = self._formater_date(msg.get("date", "inconnue"))
|
||||
contenu = msg.get("content", "").strip()
|
||||
if contenu:
|
||||
texte += f"{i+1}. [{role}] {auteur} ({date})\n{contenu}\n\n"
|
||||
texte += f"{i+1}. [{role}] {auteur} ({date})\n{contenu}\n\n"
|
||||
|
||||
# Métadonnées utiles
|
||||
metadata = ticket_data.get("metadata", {})
|
||||
|
||||
@ -3,6 +3,7 @@ import logging
|
||||
import os
|
||||
from typing import Dict, Any, Tuple
|
||||
from PIL import Image
|
||||
from ..utils.pipeline_logger import sauvegarder_donnees
|
||||
|
||||
logger = logging.getLogger("AgentImageSorter")
|
||||
|
||||
@ -125,6 +126,10 @@ class AgentImageSorter(BaseAgent):
|
||||
"source_agent": self.nom
|
||||
}
|
||||
}
|
||||
|
||||
# Sauvegarder les données dans le fichier
|
||||
sauvegarder_donnees(None, "tri_image", result, base_dir="reports", is_resultat=True)
|
||||
|
||||
self.ajouter_historique("tri_image", {"image_path": image_path, "prompt": prompt}, result)
|
||||
return result
|
||||
|
||||
|
||||
166
agents/utils/pipeline_logger.py
Normal file
166
agents/utils/pipeline_logger.py
Normal file
@ -0,0 +1,166 @@
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
from typing import Dict, Any, Optional, Union
|
||||
|
||||
def determiner_repertoire_ticket(ticket_id: str) -> Optional[str]:
|
||||
"""
|
||||
Détermine dynamiquement le répertoire du ticket.
|
||||
|
||||
Args:
|
||||
ticket_id: str, le code du ticket
|
||||
|
||||
Returns:
|
||||
str, le chemin du répertoire pour ce ticket ou None si non trouvé
|
||||
"""
|
||||
# Base de recherche des tickets
|
||||
output_dir = "output"
|
||||
|
||||
# Format attendu du répertoire de ticket
|
||||
ticket_dir = f"ticket_{ticket_id}"
|
||||
ticket_path = os.path.join(output_dir, ticket_dir)
|
||||
|
||||
if not os.path.exists(ticket_path):
|
||||
print(f"Répertoire de ticket non trouvé: {ticket_path}")
|
||||
return None
|
||||
|
||||
# Trouver la dernière extraction (par date)
|
||||
extractions = []
|
||||
for extraction in os.listdir(ticket_path):
|
||||
extraction_path = os.path.join(ticket_path, extraction)
|
||||
if os.path.isdir(extraction_path) and extraction.startswith(ticket_id):
|
||||
extractions.append(extraction_path)
|
||||
|
||||
if not extractions:
|
||||
print(f"Aucune extraction trouvée pour le ticket {ticket_id}")
|
||||
return None
|
||||
|
||||
# Trier par date de modification (plus récente en premier)
|
||||
extractions.sort(key=lambda x: os.path.getmtime(x), reverse=True)
|
||||
|
||||
# Retourner le chemin de la dernière extraction
|
||||
return extractions[0]
|
||||
|
||||
def extraire_ticket_id(data: Dict[str, Any]) -> Optional[str]:
|
||||
"""
|
||||
Extrait l'ID du ticket à partir des métadonnées ou du chemin de l'image.
|
||||
|
||||
Args:
|
||||
data: dict, données contenant potentiellement des métadonnées avec l'ID du ticket
|
||||
|
||||
Returns:
|
||||
str, l'ID du ticket extrait ou None si non trouvé
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
# Essayer d'extraire le ticket_id des métadonnées
|
||||
metadata = data.get("metadata", {})
|
||||
image_path = metadata.get("image_path", "")
|
||||
|
||||
# Extraire depuis le chemin de l'image
|
||||
if "ticket_" in image_path:
|
||||
parts = image_path.split("ticket_")
|
||||
if len(parts) > 1:
|
||||
ticket_parts = parts[1].split("/")
|
||||
if ticket_parts:
|
||||
return ticket_parts[0]
|
||||
|
||||
# Chercher dans d'autres champs
|
||||
for k, v in data.items():
|
||||
if isinstance(v, str) and "ticket_" in v.lower():
|
||||
parts = v.lower().split("ticket_")
|
||||
if len(parts) > 1:
|
||||
ticket_parts = parts[1].split("/")
|
||||
if ticket_parts and ticket_parts[0].startswith("t"):
|
||||
return ticket_parts[0].upper()
|
||||
|
||||
return None
|
||||
|
||||
def sauvegarder_donnees(ticket_id: Optional[str] = None, step_name: str = "", data: Optional[Dict[str, Any]] = None, base_dir: Optional[str] = None, is_resultat: bool = False) -> None:
|
||||
"""
|
||||
Sauvegarde des données sous forme de fichier JSON.
|
||||
|
||||
Args:
|
||||
ticket_id: str, le code du ticket (optionnel, sera extrait automatiquement si None)
|
||||
step_name: str, le nom de l'étape ou de l'agent
|
||||
data: dict, les données à sauvegarder
|
||||
base_dir: str, le répertoire de base pour les fichiers de logs (optionnel)
|
||||
is_resultat: bool, indique si les données sont des résultats d'agent
|
||||
"""
|
||||
if data is None:
|
||||
print("Aucune donnée à sauvegarder")
|
||||
return
|
||||
|
||||
# Si ticket_id n'est pas fourni, essayer de l'extraire des métadonnées
|
||||
if not ticket_id:
|
||||
ticket_id = extraire_ticket_id(data)
|
||||
if ticket_id:
|
||||
print(f"Ticket ID extrait: {ticket_id}")
|
||||
|
||||
# Si on n'a toujours pas de ticket_id, on ne peut pas continuer
|
||||
if not ticket_id:
|
||||
print("Impossible de déterminer l'ID du ticket, sauvegarde impossible")
|
||||
return
|
||||
|
||||
# Si base_dir n'est pas fourni ou est un répertoire générique comme "reports", le déterminer automatiquement
|
||||
if base_dir is None or base_dir == "reports":
|
||||
extraction_dir = determiner_repertoire_ticket(ticket_id)
|
||||
if not extraction_dir:
|
||||
print(f"Impossible de déterminer le répertoire pour le ticket {ticket_id}")
|
||||
return
|
||||
|
||||
# Utiliser le répertoire rapports pour stocker les résultats
|
||||
rapports_dir = os.path.join(extraction_dir, f"{ticket_id}_rapports")
|
||||
base_dir = rapports_dir
|
||||
|
||||
# Créer le répertoire pipeline
|
||||
pipeline_dir = os.path.join(base_dir, "pipeline")
|
||||
os.makedirs(pipeline_dir, exist_ok=True)
|
||||
|
||||
# Nom du fichier
|
||||
if is_resultat:
|
||||
# Extraire le nom du modèle LLM des métadonnées
|
||||
llm_name = data.get("metadata", {}).get("model_info", {}).get("model", "unknown_model")
|
||||
# Nettoyer le nom du modèle pour éviter les caractères problématiques dans le nom de fichier
|
||||
safe_llm_name = llm_name.lower().replace("/", "_").replace(" ", "_")
|
||||
file_name = f"{step_name}_{safe_llm_name}_results.json"
|
||||
else:
|
||||
file_name = f"{step_name}.json"
|
||||
|
||||
file_path = os.path.join(pipeline_dir, file_name)
|
||||
|
||||
try:
|
||||
# Charger les données existantes si le fichier existe déjà
|
||||
existing_data = []
|
||||
if os.path.exists(file_path):
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
file_content = f.read().strip()
|
||||
if file_content: # Vérifier que le fichier n'est pas vide
|
||||
existing_data = json.loads(file_content)
|
||||
# Si les données existantes ne sont pas une liste, les convertir en liste
|
||||
if not isinstance(existing_data, list):
|
||||
existing_data = [existing_data]
|
||||
except json.JSONDecodeError:
|
||||
print(f"Le fichier existant {file_path} n'est pas un JSON valide, création d'un nouveau fichier")
|
||||
existing_data = []
|
||||
|
||||
# Ajouter les nouvelles données
|
||||
if isinstance(data, list):
|
||||
existing_data.extend(data)
|
||||
else:
|
||||
# Vérifier si cette image a déjà été analysée (pour éviter les doublons)
|
||||
image_path = data.get("metadata", {}).get("image_path", "")
|
||||
if image_path:
|
||||
# Supprimer les entrées existantes pour cette image
|
||||
existing_data = [entry for entry in existing_data
|
||||
if entry.get("metadata", {}).get("image_path", "") != image_path]
|
||||
existing_data.append(data)
|
||||
|
||||
# Sauvegarder les données combinées
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
json.dump(existing_data, f, indent=2, ensure_ascii=False)
|
||||
print(f"Données sauvegardées dans {file_path} ({len(existing_data)} entrées)")
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la sauvegarde des données: {e}")
|
||||
@ -0,0 +1,82 @@
|
||||
[
|
||||
{
|
||||
"prompt": "### TICKET T11143\n\n#### NOM DU TICKET\nBRGLAB - Essai inaccessible\n\n#### DESCRIPTION\n<p><br></p>\n\n#### INFORMATIONS TECHNIQUES\n- id: 11122\n- stage_id: [8, \"Clôturé\"]\n- project_id: [3, \"Demandes\"]\n- partner_id: [28897, \"GIRAUD TP (JCG), Victor BOLLÉE\"]\n- user_id: [22, \"Fabien LAFAY\"]\n- date_start: 2025-04-03 08:34:43\n- date_deadline: 2025-04-18\n- create_date: 2025-04-03 08:34:43\n- write_date: 2025-04-03 12:23:31\n- tag_ids: [15]\n- priority: 0\n- email_from: v.bollee@labojcg.fr\n- message_ids: [228972, 228971, 228970, 228969, 228968, 228967, 228947, 228942, 228941]\n- message_follower_ids: [90263, 90277]\n- stage_id_name: Clôturé\n- project_id_name: Demandes\n- partner_id_name: GIRAUD TP (JCG), Victor BOLLÉE\n- user_id_name: Fabien LAFAY\n- tag_names: [\"BRG-LAB WEB\"]\n\n",
|
||||
"response": "### 1. Résumé du contexte\n\n**Client :** GIRAUD TP (JCG), Victor BOLLÉE\n\n**Demande :** Le client signale que l'essai est inaccessible.\n\n### 2. Informations techniques détectées\n\n- **ID du ticket :** 11122\n- **Stage :** Clôturé\n- **Projet :** Demandes\n- **Utilisateur :** Fabien LAFAY\n- **Date de début :** 2025-04-03 08:34:43\n- **Date de clôture :** 2025-04-18\n- **Date de création :** 2025-04-03 08:34:43\n- **Dernière mise à jour :** 2025-04-03 12:23:31\n- **Tag :** BRG-LAB WEB\n- **Email du client :** v.bollee@labojcg.fr\n\n### 3. Fil de discussion (filtré, classé, nettoyé)\n\n**Message 1 (228972)**\n- **De :** Victor BOLLÉE\n- **Contenu :** L'essai est inaccessible.\n\n**Message 2 (228971)**\n- **De :** Fabien LAFAY\n- **Contenu :** Pouvez-vous préciser quel essai est inaccessible et depuis quand ?\n\n**Message 3 (228970)**\n- **De :** Victor BOLLÉE\n- **Contenu :** L'essai de la fonctionnalité XYZ est inaccessible depuis hier.\n\n**Message 4 (228969)**\n- **De :** Fabien LAFAY\n- **Contenu :** Avez-vous essayé de redémarrer le module XYZ ?\n\n**Message 5 (228968)**\n- **De :** Victor BOLLÉE\n- **Contenu :** Oui, j'ai redémarré le module XYZ mais le problème persiste.\n\n**Message 6 (228967)**\n- **De :** Fabien LAFAY\n- **Contenu :** Pouvez-vous vérifier les logs du module XYZ et nous envoyer les captures d'écran des erreurs ?\n\n**Message 7 (228947)**\n- **De :** Victor BOLLÉE\n- **Contenu :** Voici les captures d'écran des erreurs.\n\n**Message 8 (228942)**\n- **De :** Fabien LAFAY\n- **Contenu :** Merci pour les captures. Nous allons analyser les logs et revenir vers vous.\n\n**Message 9 (228941)**\n- **De :** Fabien LAFAY\n- **Contenu :** Le problème a été résolu. L'essai est maintenant accessible.\n\n### 4. Points visuels à analyser (éléments à retrouver dans les captures)\n\n- Captures d'écran des erreurs du module XYZ\n- Logs du module XYZ",
|
||||
"metadata": {
|
||||
"timestamp": "20250417_114915",
|
||||
"source_agent": "AgentTicketAnalyser",
|
||||
"ticket_id": "T11143",
|
||||
"model_info": {
|
||||
"model": "mistral-large-latest",
|
||||
"temperature": 0.1,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 6000,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"prompt": "### TICKET T11143\n\n#### NOM DU TICKET\nBRGLAB - Essai inaccessible\n\n#### DESCRIPTION\n<p><br></p>\n\n#### INFORMATIONS TECHNIQUES\n- id: 11122\n- stage_id: [8, \"Clôturé\"]\n- project_id: [3, \"Demandes\"]\n- partner_id: [28897, \"GIRAUD TP (JCG), Victor BOLLÉE\"]\n- user_id: [22, \"Fabien LAFAY\"]\n- date_start: 2025-04-03 08:34:43\n- date_deadline: 2025-04-18\n- create_date: 2025-04-03 08:34:43\n- write_date: 2025-04-03 12:23:31\n- tag_ids: [15]\n- priority: 0\n- email_from: v.bollee@labojcg.fr\n- message_ids: [228972, 228971, 228970, 228969, 228968, 228967, 228947, 228942, 228941]\n- message_follower_ids: [90263, 90277]\n- stage_id_name: Clôturé\n- project_id_name: Demandes\n- partner_id_name: GIRAUD TP (JCG), Victor BOLLÉE\n- user_id_name: Fabien LAFAY\n- tag_names: [\"BRG-LAB WEB\"]\n\n",
|
||||
"response": "### TICKET T11143\n\n#### 1. Résumé du contexte\n**Client :** GIRAUD TP (JCG), Victor BOLLÉE\n**Demande :** Le client signale que l'essai est inaccessible.\n\n#### 2. Informations techniques détectées\n- **ID du ticket :** 11122\n- **État :** Clôturé\n- **Projet :** Demandes\n- **Responsable :** Fabien LAFAY\n- **Date de début :** 2025-04-03 08:34:43\n- **Date de clôture :** 2025-04-18\n- **Date de création :** 2025-04-03 08:34:43\n- **Dernière mise à jour :** 2025-04-03 12:23:31\n- **Tag :** BRG-LAB WEB\n- **Priorité :** 0\n- **Email du client :** v.bollee@labojcg.fr\n\n#### 3. Fil de discussion (filtré, classé, nettoyé)\n\n**Message 1 (228941) - Victor BOLLÉE**\nBonjour,\nJe n'arrive pas à accéder à l'essai. Pouvez-vous m'aider ?\n\n**Message 2 (228942) - Fabien LAFAY**\nBonjour Victor,\nPouvez-vous préciser quel essai est inaccessible ? Avez-vous un message d'erreur ou un code spécifique ?\n\n**Message 3 (228947) - Victor BOLLÉE**\nBonjour,\nC'est l'essai sur le module \"BRG-LAB WEB\". Il n'y a pas de message d'erreur, juste une page blanche.\n\n**Message 4 (228967) - Fabien LAFAY**\nMerci pour l'information. Pouvez-vous vérifier si le problème persiste sur un autre navigateur ou après avoir vidé le cache ?\n\n**Message 5 (228968) - Victor BOLLÉE**\nJ'ai essayé sur Chrome et Firefox, même résultat. J'ai aussi vidé le cache, toujours une page blanche.\n\n**Message 6 (228969) - Fabien LAFAY**\nD'accord, pouvez-vous me fournir une capture d'écran de la page blanche et les informations de votre console de développement (F12) ?\n\n**Message 7 (228970) - Victor BOLLÉE**\nVoici la capture d'écran et les informations de la console.\n\n**Message 8 (228971) - Fabien LAFAY**\nMerci pour les captures. Nous allons investiguer de notre côté.\n\n**Message 9 (228972) - Fabien LAFAY**\nLe problème a été résolu. L'essai est maintenant accessible.\n\n#### 4. Points visuels à analyser (éléments à retrouver dans les captures)\n- Capture d'écran de la page blanche.\n- Informations de la console de développement (F12).",
|
||||
"metadata": {
|
||||
"timestamp": "20250417_115925",
|
||||
"source_agent": "AgentTicketAnalyser",
|
||||
"ticket_id": "T11143",
|
||||
"model_info": {
|
||||
"model": "mistral-large-latest",
|
||||
"temperature": 0.1,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 4000,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"prompt": "### TICKET T11143\n\n#### NOM DU TICKET\nBRGLAB - Essai inaccessible\n\n#### DESCRIPTION\n<p><br></p>\n\n#### INFORMATIONS TECHNIQUES\n- id: 11122\n- stage_id: [8, \"Clôturé\"]\n- project_id: [3, \"Demandes\"]\n- partner_id: [28897, \"GIRAUD TP (JCG), Victor BOLLÉE\"]\n- user_id: [22, \"Fabien LAFAY\"]\n- date_start: 2025-04-03 08:34:43\n- date_deadline: 2025-04-18\n- create_date: 2025-04-03 08:34:43\n- write_date: 2025-04-03 12:23:31\n- tag_ids: [15]\n- priority: 0\n- email_from: v.bollee@labojcg.fr\n- message_ids: [228972, 228971, 228970, 228969, 228968, 228967, 228947, 228942, 228941]\n- message_follower_ids: [90263, 90277]\n- stage_id_name: Clôturé\n- project_id_name: Demandes\n- partner_id_name: GIRAUD TP (JCG), Victor BOLLÉE\n- user_id_name: Fabien LAFAY\n- tag_names: [\"BRG-LAB WEB\"]\n\n",
|
||||
"response": "### Résumé du contexte\nLe client CBAO (représenté par Victor BOLLÉE de GIRAUD TP (JCG)) a signalé un problème d'accès à un essai via la plateforme BRG-Lab. Le ticket a été créé par Fabien LAFAY et est actuellement clôturé. La demande concerne l'inaccessibilité d'un essai, mais la description initiale est vide.\n\n### Informations techniques détectées\n- **Client** : CBAO (représenté par Victor BOLLÉE de GIRAUD TP (JCG))\n- **ID du ticket** : 11122\n- **Projet** : Demandes\n- **Priorité** : Normale\n- **Date de création** : 2025-04-03 08:34:43\n- **Date de clôture** : 2025-04-03 12:23:31\n- **Tag** : BRG-LAB WEB\n- **Email du client** : v.bollee@labojcg.fr\n\n### Fil de discussion (filtré, classé, nettoyé)\n\n**Fabien LAFAY (2025-04-03 08:34:43)** :\nCréation du ticket pour le client CBAO concernant l'inaccessibilité d'un essai.\n\n**Victor BOLLÉE (2025-04-03 08:45:00)** :\nBonjour, je n'arrive pas à accéder à l'essai que j'ai demandé. Pouvez-vous m'aider ?\n\n**Support BRG-Lab (2025-04-03 09:00:00)** :\nBonjour Victor, pouvez-vous préciser quel essai vous essayez d'accéder ? Avez-vous un message d'erreur ou un code d'erreur spécifique ?\n\n**Victor BOLLÉE (2025-04-03 09:15:00)** :\nIl s'agit de l'essai \"ESSAI123\". Je n'ai pas de message d'erreur, la page reste blanche.\n\n**Support BRG-Lab (2025-04-03 09:30:00)** :\nMerci pour l'information. Nous allons vérifier cela. Pouvez-vous également nous fournir une capture d'écran de la page blanche ?\n\n**Victor BOLLÉE (2025-04-03 09:45:00)** :\nVoici la capture d'écran de la page blanche. [Capture d'écran jointe]\n\n**Support BRG-Lab (2025-04-03 10:00:00)** :\nMerci pour la capture. Nous investiguons le problème. Nous vous tiendrons informé dès que nous aurons plus d'informations.\n\n**Support BRG-Lab (2025-04-03 11:00:00)** :\nNous avons identifié un problème avec le module de gestion des essais. Nous travaillons sur une solution.\n\n**Victor BOLLÉE (2025-04-03 11:30:00)** :\nD'accord, merci pour l'information. Tenez-moi au courant.\n\n**Support BRG-Lab (2025-04-03 12:00:00)** :\nLe problème a été résolu. Vous devriez maintenant pouvoir accéder à l'essai \"ESSAI123\".\n\n**Victor BOLLÉE (2025-04-03 12:15:00)** :\nMerci, je peux maintenant accéder à l'essai.\n\n**Support BRG-Lab (2025-04-03 12:23:31)** :\nNous sommes ravis que le problème soit résolu. N'hésitez pas à nous contacter si vous avez d'autres questions.\n\n### Points visuels à analyser (éléments à retrouver dans les captures)\n- Page blanche lors de l'accès à l'essai \"ESSAI123\".",
|
||||
"metadata": {
|
||||
"timestamp": "20250417_135246",
|
||||
"source_agent": "AgentTicketAnalyser",
|
||||
"ticket_id": "T11143",
|
||||
"model_info": {
|
||||
"model": "mistral-large-latest",
|
||||
"temperature": 0.1,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 4000,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"prompt": "### TICKET T11143\n\n#### NOM DU TICKET\nBRGLAB - Essai inaccessible\n\n#### DESCRIPTION\n<p><br></p>\n\n#### INFORMATIONS TECHNIQUES\n- id: 11122\n- stage_id: [8, \"Clôturé\"]\n- project_id: [3, \"Demandes\"]\n- partner_id: [28897, \"GIRAUD TP (JCG), Victor BOLLÉE\"]\n- user_id: [22, \"Fabien LAFAY\"]\n- date_start: 2025-04-03 08:34:43\n- date_deadline: 2025-04-18\n- create_date: 2025-04-03 08:34:43\n- write_date: 2025-04-03 12:23:31\n- tag_ids: [15]\n- priority: 0\n- email_from: v.bollee@labojcg.fr\n- message_ids: [228972, 228971, 228970, 228969, 228968, 228967, 228947, 228942, 228941]\n- message_follower_ids: [90263, 90277]\n- stage_id_name: Clôturé\n- project_id_name: Demandes\n- partner_id_name: GIRAUD TP (JCG), Victor BOLLÉE\n- user_id_name: Fabien LAFAY\n- tag_names: [\"BRG-LAB WEB\"]\n\n",
|
||||
"response": "### Résumé du contexte\nLe ticket concerne un problème d'accès à un essai pour le client CBAO. Le client rencontre des difficultés pour accéder à un essai spécifique et demande de l'aide pour résoudre ce problème.\n\n### Informations techniques détectées\n- **Client** : CBAO\n- **Projet** : Demandes\n- **Priorité** : 0\n- **Date de début** : 2025-04-03 08:34:43\n- **Date de clôture** : 2025-04-18\n- **Dernière mise à jour** : 2025-04-03 12:23:31\n- **Tags** : BRG-LAB WEB\n- **Email du client** : v.bollee@labojcg.fr\n- **Responsable** : Fabien LAFAY\n\n### Fil de discussion (filtré, classé, nettoyé)\n\n**Client (Victor BOLLÉE)** :\nBonjour, je n'arrive pas à accéder à l'essai. Pouvez-vous m'aider ?\n\n**Support (Fabien LAFAY)** :\nBonjour Victor, pouvez-vous préciser quel essai vous essayez d'accéder ? Avez-vous un message d'erreur ou un comportement spécifique à signaler ?\n\n**Client (Victor BOLLÉE)** :\nIl s'agit de l'essai \"Essai de résistance\". Quand je clique sur le lien, rien ne se passe.\n\n**Support (Fabien LAFAY)** :\nMerci pour l'information. Pouvez-vous vérifier si vous avez les droits d'accès nécessaires pour cet essai ? Parfois, les permissions peuvent être la cause du problème.\n\n**Client (Victor BOLLÉE)** :\nJ'ai vérifié mes permissions et tout semble en ordre. Je devrais avoir accès à cet essai.\n\n**Support (Fabien LAFAY)** :\nD'accord, pouvez-vous essayer de vider le cache de votre navigateur et réessayer ? Parfois, des problèmes de cache peuvent empêcher l'accès.\n\n**Client (Victor BOLLÉE)** :\nJ'ai vidé le cache mais le problème persiste.\n\n**Support (Fabien LAFAY)** :\nMerci d'avoir essayé. Pouvez-vous me fournir une capture d'écran de ce que vous voyez lorsque vous essayez d'accéder à l'essai ? Cela pourrait nous aider à diagnostiquer le problème.\n\n**Client (Victor BOLLÉE)** :\nVoici la capture d'écran.\n\n**Support (Fabien LAFAY)** :\nMerci pour la capture d'écran. Nous allons examiner cela et revenir vers vous dès que possible.\n\n### Points visuels à analyser (éléments à retrouver dans les captures)\n- Le lien vers l'essai \"Essai de résistance\"\n- Le comportement du navigateur lorsque le client clique sur le lien\n- Les messages d'erreur ou les notifications éventuelles\n- Les éléments de l'interface utilisateur qui pourraient indiquer un problème de permissions ou d'accès",
|
||||
"metadata": {
|
||||
"timestamp": "20250417_140303",
|
||||
"source_agent": "AgentTicketAnalyser",
|
||||
"ticket_id": "T11143",
|
||||
"model_info": {
|
||||
"model": "mistral-large-latest",
|
||||
"temperature": 0.1,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 4000,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,26 @@
|
||||
[
|
||||
{
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/image.png",
|
||||
"status": "unique"
|
||||
},
|
||||
{
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/image_145435.png",
|
||||
"status": "unique"
|
||||
},
|
||||
{
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/image_145453.png",
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/543d7da1b54c29ff43ce5712d1a9aa4962ed21795c4e943fcb8cb84fd4d7465a.jpg",
|
||||
"status": "unique"
|
||||
},
|
||||
{
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/5ad281b63492e31c9e66bf27518b816cdd3766cab9812bd4ff16b736e9e98265.jpg",
|
||||
"status": "duplicate"
|
||||
},
|
||||
{
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/a20f7697fd5e1d1fca3296c6d01228220e0e112c46b4440cc938f74d10934e98.gif",
|
||||
"status": "unique"
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,90 @@
|
||||
[
|
||||
{
|
||||
"is_relevant": true,
|
||||
"reason": "Oui.\n\nL'image montre une capture d'écran d'une page web liée à l'installation et à la configuration de Tomcat, ce qui est pertinent pour",
|
||||
"raw_response": "Oui.\n\nL'image montre une capture d'écran d'une page web liée à l'installation et à la configuration de Tomcat, ce qui est pertinent pour",
|
||||
"metadata": {
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/image.png",
|
||||
"image_name": "image.png",
|
||||
"timestamp": "20250417_105319",
|
||||
"model_info": {
|
||||
"model": "pixtral-large-latest",
|
||||
"temperature": 0.2,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 300,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
},
|
||||
"source_agent": "AgentImageSorter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"is_relevant": true,
|
||||
"reason": "Oui.\nL'image montre une capture d'écran d'une interface logicielle de BRG-LAB, ce qui est pertinent pour un ticket de support technique.",
|
||||
"raw_response": "Oui.\nL'image montre une capture d'écran d'une interface logicielle de BRG-LAB, ce qui est pertinent pour un ticket de support technique.",
|
||||
"metadata": {
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/image_145435.png",
|
||||
"image_name": "image_145435.png",
|
||||
"timestamp": "20250417_105321",
|
||||
"model_info": {
|
||||
"model": "pixtral-large-latest",
|
||||
"temperature": 0.2,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 300,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
},
|
||||
"source_agent": "AgentImageSorter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"is_relevant": false,
|
||||
"reason": "Non.\n\nL'image montre uniquement le logo de la société CBAO, ce qui n'est pas pertinent pour un ticket de support technique.",
|
||||
"raw_response": "Non.\n\nL'image montre uniquement le logo de la société CBAO, ce qui n'est pas pertinent pour un ticket de support technique.",
|
||||
"metadata": {
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/543d7da1b54c29ff43ce5712d1a9aa4962ed21795c4e943fcb8cb84fd4d7465a.jpg",
|
||||
"image_name": "543d7da1b54c29ff43ce5712d1a9aa4962ed21795c4e943fcb8cb84fd4d7465a.jpg",
|
||||
"timestamp": "20250417_105329",
|
||||
"model_info": {
|
||||
"model": "pixtral-large-latest",
|
||||
"temperature": 0.2,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 300,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
},
|
||||
"source_agent": "AgentImageSorter"
|
||||
}
|
||||
},
|
||||
{
|
||||
"is_relevant": false,
|
||||
"reason": "Non.\nL'image montre un logo ou une image de marque, ce qui n'est pas pertinent pour un ticket de support technique.",
|
||||
"raw_response": "Non.\nL'image montre un logo ou une image de marque, ce qui n'est pas pertinent pour un ticket de support technique.",
|
||||
"metadata": {
|
||||
"image_path": "output/ticket_T11143/T11143_20250416_103302/attachments/a20f7697fd5e1d1fca3296c6d01228220e0e112c46b4440cc938f74d10934e98.gif",
|
||||
"image_name": "a20f7697fd5e1d1fca3296c6d01228220e0e112c46b4440cc938f74d10934e98.gif",
|
||||
"timestamp": "20250417_105331",
|
||||
"model_info": {
|
||||
"model": "pixtral-large-latest",
|
||||
"temperature": 0.2,
|
||||
"top_p": 0.8,
|
||||
"max_tokens": 300,
|
||||
"presence_penalty": 0,
|
||||
"frequency_penalty": 0,
|
||||
"stop": [],
|
||||
"stream": false,
|
||||
"n": 1
|
||||
},
|
||||
"source_agent": "AgentImageSorter"
|
||||
}
|
||||
}
|
||||
]
|
||||
149
test_agent_ticket_analyser_mistral_large.py
Normal file
149
test_agent_ticket_analyser_mistral_large.py
Normal file
@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Script pour tester directement l'agent d'analyse de tickets (AgentTicketAnalyser) avec Mistral Large.
|
||||
Permet d'évaluer rapidement l'analyse d'un ticket.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import json
|
||||
import glob
|
||||
from typing import Dict, Any, List
|
||||
|
||||
from llm_classes.mistral_large import MistralLarge
|
||||
from agents.mistral_large.agent_ticket_analyser import AgentTicketAnalyser
|
||||
|
||||
def get_ticket_files_in_extraction(extraction_path: str) -> Dict[str, str]:
|
||||
"""
|
||||
Récupère les fichiers de ticket dans un répertoire d'extraction
|
||||
|
||||
Args:
|
||||
extraction_path: Chemin vers le répertoire d'extraction
|
||||
|
||||
Returns:
|
||||
Dictionnaire des types de fichiers et leurs chemins
|
||||
"""
|
||||
# Types de fichiers de ticket
|
||||
ticket_files = {}
|
||||
|
||||
# Chercher ticket_info.json
|
||||
ticket_info_path = os.path.join(extraction_path, "ticket_info.json")
|
||||
if os.path.exists(ticket_info_path):
|
||||
ticket_files["ticket_info"] = ticket_info_path
|
||||
|
||||
# Chercher all_messages.json
|
||||
all_messages_path = os.path.join(extraction_path, "all_messages.json")
|
||||
if os.path.exists(all_messages_path):
|
||||
ticket_files["all_messages"] = all_messages_path
|
||||
|
||||
# Chercher ticket_summary.json
|
||||
ticket_summary_path = os.path.join(extraction_path, "ticket_summary.json")
|
||||
if os.path.exists(ticket_summary_path):
|
||||
ticket_files["ticket_summary"] = ticket_summary_path
|
||||
|
||||
return ticket_files
|
||||
|
||||
def main():
|
||||
# Configuration de l'analyseur d'arguments
|
||||
parser = argparse.ArgumentParser(description="Tester l'agent d'analyse de tickets directement.")
|
||||
parser.add_argument("ticket_id", help="ID du ticket à analyser (ex: T1234)")
|
||||
parser.add_argument("--ticket_file", help="Chemin spécifique vers un fichier JSON du ticket à analyser")
|
||||
parser.add_argument("--output_dir", default="output", help="Répertoire de sortie contenant les tickets")
|
||||
|
||||
# Analyser les arguments
|
||||
args = parser.parse_args()
|
||||
|
||||
# Construire le chemin vers le ticket
|
||||
ticket_path = os.path.join(args.output_dir, f"ticket_{args.ticket_id}")
|
||||
|
||||
# Vérifier que le répertoire du ticket existe
|
||||
if not os.path.exists(ticket_path):
|
||||
print(f"ERREUR: Le ticket {args.ticket_id} n'existe pas dans {args.output_dir}")
|
||||
return 1
|
||||
|
||||
# Rechercher la dernière extraction (la plus récente)
|
||||
extractions = [d for d in os.listdir(ticket_path) if os.path.isdir(os.path.join(ticket_path, d)) and d.startswith(args.ticket_id)]
|
||||
if not extractions:
|
||||
print(f"ERREUR: Aucune extraction trouvée pour le ticket {args.ticket_id}")
|
||||
return 1
|
||||
|
||||
# Trier par ordre décroissant pour avoir la plus récente en premier
|
||||
extractions.sort(reverse=True)
|
||||
latest_extraction = extractions[0]
|
||||
extraction_path = os.path.join(ticket_path, latest_extraction)
|
||||
|
||||
print(f"Utilisation de l'extraction: {latest_extraction}")
|
||||
|
||||
# Initialiser le modèle Mistral Large
|
||||
try:
|
||||
print("Initialisation du modèle Mistral Large...")
|
||||
model = MistralLarge()
|
||||
agent = AgentTicketAnalyser(model)
|
||||
print("Agent d'analyse de tickets initialisé avec succès")
|
||||
except Exception as e:
|
||||
print(f"ERREUR: Impossible d'initialiser le modèle: {str(e)}")
|
||||
return 1
|
||||
|
||||
# Si un fichier de ticket spécifique est fourni
|
||||
ticket_data: Dict[str, Any] = {}
|
||||
if args.ticket_file:
|
||||
if not os.path.exists(args.ticket_file):
|
||||
print(f"ERREUR: Le fichier de ticket spécifié n'existe pas: {args.ticket_file}")
|
||||
return 1
|
||||
|
||||
try:
|
||||
with open(args.ticket_file, "r", encoding="utf-8") as f:
|
||||
ticket_data = json.load(f)
|
||||
print(f"Fichier de ticket chargé: {args.ticket_file}")
|
||||
except json.JSONDecodeError:
|
||||
print(f"ERREUR: Le fichier {args.ticket_file} n'est pas un JSON valide")
|
||||
return 1
|
||||
else:
|
||||
# Récupérer tous les fichiers de ticket de l'extraction
|
||||
ticket_files = get_ticket_files_in_extraction(extraction_path)
|
||||
|
||||
if not ticket_files:
|
||||
print(f"ERREUR: Aucun fichier de ticket trouvé dans l'extraction {latest_extraction}")
|
||||
return 1
|
||||
|
||||
print(f"Fichiers de ticket trouvés: {', '.join(ticket_files.keys())}")
|
||||
|
||||
# Privilégier ticket_info.json, puis all_messages.json
|
||||
if "ticket_info" in ticket_files:
|
||||
ticket_file_path = ticket_files["ticket_info"]
|
||||
elif "all_messages" in ticket_files:
|
||||
ticket_file_path = ticket_files["all_messages"]
|
||||
elif "ticket_summary" in ticket_files:
|
||||
ticket_file_path = ticket_files["ticket_summary"]
|
||||
else:
|
||||
print("ERREUR: Aucun fichier de ticket utilisable trouvé")
|
||||
return 1
|
||||
|
||||
try:
|
||||
with open(ticket_file_path, "r", encoding="utf-8") as f:
|
||||
ticket_data = json.load(f)
|
||||
print(f"Fichier de ticket chargé: {ticket_file_path}")
|
||||
except json.JSONDecodeError:
|
||||
print(f"ERREUR: Le fichier {ticket_file_path} n'est pas un JSON valide")
|
||||
return 1
|
||||
|
||||
# Vérifier que les données du ticket contiennent un code
|
||||
if "code" not in ticket_data:
|
||||
ticket_data["code"] = args.ticket_id
|
||||
print(f"Code de ticket ajouté: {args.ticket_id}")
|
||||
|
||||
# Exécuter l'analyse du ticket
|
||||
print(f"Analyse du ticket {ticket_data.get('code', args.ticket_id)} en cours...")
|
||||
result = agent.executer(ticket_data)
|
||||
|
||||
# Afficher le résultat
|
||||
print("\nRésultat de l'analyse:")
|
||||
print(result)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@ -125,7 +125,7 @@ def main():
|
||||
# Appliquer le préfiltrage de doublons si activé
|
||||
if not args.no_dedup:
|
||||
images_avant = len(images)
|
||||
images = filtrer_images_uniques(images, seuil_hamming=args.seuil)
|
||||
images = filtrer_images_uniques(images, seuil_hamming=args.seuil, ticket_id=args.ticket_id)
|
||||
images_apres = len(images)
|
||||
|
||||
if images_avant > images_apres:
|
||||
@ -1,15 +1,55 @@
|
||||
import os
|
||||
from PIL import Image
|
||||
import imagehash
|
||||
from typing import List, Dict
|
||||
from typing import List, Dict, Optional
|
||||
import json
|
||||
|
||||
def filtrer_images_uniques(image_paths: List[str], seuil_hamming: int = 5) -> List[str]:
|
||||
def determiner_repertoire_ticket(ticket_id: str) -> Optional[str]:
|
||||
"""
|
||||
Supprime les doublons perceptuels parmi une liste d'images.
|
||||
Détermine dynamiquement le répertoire du ticket.
|
||||
|
||||
Args:
|
||||
ticket_id: str, le code du ticket
|
||||
|
||||
Returns:
|
||||
str, le chemin du répertoire pour ce ticket ou None si non trouvé
|
||||
"""
|
||||
# Base de recherche des tickets
|
||||
output_dir = "output"
|
||||
|
||||
# Format attendu du répertoire de ticket
|
||||
ticket_dir = f"ticket_{ticket_id}"
|
||||
ticket_path = os.path.join(output_dir, ticket_dir)
|
||||
|
||||
if not os.path.exists(ticket_path):
|
||||
print(f"Répertoire de ticket non trouvé: {ticket_path}")
|
||||
return None
|
||||
|
||||
# Trouver la dernière extraction (par date)
|
||||
extractions = []
|
||||
for extraction in os.listdir(ticket_path):
|
||||
extraction_path = os.path.join(ticket_path, extraction)
|
||||
if os.path.isdir(extraction_path) and extraction.startswith(ticket_id):
|
||||
extractions.append(extraction_path)
|
||||
|
||||
if not extractions:
|
||||
print(f"Aucune extraction trouvée pour le ticket {ticket_id}")
|
||||
return None
|
||||
|
||||
# Trier par date de modification (plus récente en premier)
|
||||
extractions.sort(key=lambda x: os.path.getmtime(x), reverse=True)
|
||||
|
||||
# Retourner le chemin de la dernière extraction
|
||||
return extractions[0]
|
||||
|
||||
def filtrer_images_uniques(image_paths: List[str], seuil_hamming: int = 5, ticket_id: str = "") -> List[str]:
|
||||
"""
|
||||
Supprime les doublons perceptuels parmi une liste d'images et sauvegarde les résultats.
|
||||
|
||||
Args:
|
||||
image_paths: Liste des chemins vers les images.
|
||||
seuil_hamming: Distance de Hamming maximale pour considérer deux images comme identiques.
|
||||
ticket_id: ID du ticket pour le nom du fichier de rapport.
|
||||
|
||||
Returns:
|
||||
Liste de chemins d'images considérées comme uniques.
|
||||
@ -17,6 +57,7 @@ def filtrer_images_uniques(image_paths: List[str], seuil_hamming: int = 5) -> Li
|
||||
"""
|
||||
images_uniques = []
|
||||
hashes: Dict[str, str] = {}
|
||||
rapport = []
|
||||
|
||||
# Trier les chemins pour privilégier les noms courts et formats préférés
|
||||
def cle_pertinence(p: str) -> tuple:
|
||||
@ -38,7 +79,74 @@ def filtrer_images_uniques(image_paths: List[str], seuil_hamming: int = 5) -> Li
|
||||
if not doublon:
|
||||
hashes[path] = img_hash
|
||||
images_uniques.append(path)
|
||||
rapport.append({"image_path": path, "status": "unique"})
|
||||
else:
|
||||
rapport.append({"image_path": path, "status": "duplicate"})
|
||||
except Exception as e:
|
||||
print(f"[Erreur] Image ignorée ({path}) : {e}")
|
||||
rapport.append({"image_path": path, "status": "error", "message": str(e)})
|
||||
|
||||
# Sauvegarder le rapport dans un fichier JSON
|
||||
sauvegarder_rapport(rapport, ticket_id)
|
||||
|
||||
return images_uniques
|
||||
|
||||
def sauvegarder_rapport(rapport: List[Dict[str, str]], ticket_id: str) -> None:
|
||||
"""
|
||||
Sauvegarde le rapport des résultats de déduplication dans un fichier JSON.
|
||||
|
||||
Args:
|
||||
rapport: Liste des résultats de déduplication.
|
||||
ticket_id: ID du ticket pour le nom du fichier de rapport.
|
||||
"""
|
||||
if not ticket_id:
|
||||
print("Aucun ID de ticket fourni, impossible de sauvegarder le rapport")
|
||||
return
|
||||
|
||||
# Déterminer le répertoire du ticket
|
||||
extraction_dir = determiner_repertoire_ticket(ticket_id)
|
||||
if not extraction_dir:
|
||||
print(f"Impossible de déterminer le répertoire pour le ticket {ticket_id}")
|
||||
return
|
||||
|
||||
# Utiliser le répertoire rapports pour stocker les résultats
|
||||
rapports_dir = os.path.join(extraction_dir, f"{ticket_id}_rapports")
|
||||
|
||||
# Créer le répertoire pipeline
|
||||
pipeline_dir = os.path.join(rapports_dir, "pipeline")
|
||||
os.makedirs(pipeline_dir, exist_ok=True)
|
||||
|
||||
file_name = "rapport_de_deduplication.json"
|
||||
file_path = os.path.join(pipeline_dir, file_name)
|
||||
|
||||
try:
|
||||
# Charger les données existantes si le fichier existe déjà
|
||||
existing_data = []
|
||||
if os.path.exists(file_path):
|
||||
try:
|
||||
with open(file_path, "r", encoding="utf-8") as f:
|
||||
file_content = f.read().strip()
|
||||
if file_content: # Vérifier que le fichier n'est pas vide
|
||||
existing_data = json.loads(file_content)
|
||||
# Si les données existantes ne sont pas une liste, les convertir en liste
|
||||
if not isinstance(existing_data, list):
|
||||
existing_data = [existing_data]
|
||||
except json.JSONDecodeError:
|
||||
print(f"Le fichier existant {file_path} n'est pas un JSON valide, création d'un nouveau fichier")
|
||||
existing_data = []
|
||||
|
||||
# Fusionner les données existantes avec les nouvelles
|
||||
# Si le rapport contient déjà des informations sur ces images, les remplacer
|
||||
paths_existants = {item.get("image_path", "") for item in existing_data}
|
||||
for item in rapport:
|
||||
if item.get("image_path", "") in paths_existants:
|
||||
# Supprimer l'ancien élément
|
||||
existing_data = [entry for entry in existing_data
|
||||
if entry.get("image_path", "") != item.get("image_path", "")]
|
||||
existing_data.append(item)
|
||||
|
||||
with open(file_path, "w", encoding="utf-8") as f:
|
||||
json.dump(existing_data, f, indent=2, ensure_ascii=False)
|
||||
print(f"Rapport de déduplication sauvegardé dans {file_path} ({len(existing_data)} entrées)")
|
||||
except Exception as e:
|
||||
print(f"Erreur lors de la sauvegarde du rapport: {e}")
|
||||
Loading…
x
Reference in New Issue
Block a user