mirror of
https://github.com/Ladebeze66/llm_ticket3.git
synced 2025-12-13 10:46:51 +01:00
196 lines
7.6 KiB
Python
196 lines
7.6 KiB
Python
from ..base_agent import BaseAgent
|
|
from typing import Dict, Any
|
|
import logging
|
|
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")
|
|
|
|
class AgentTicketAnalyser(BaseAgent):
|
|
def __init__(self, llm):
|
|
super().__init__("AgentTicketAnalyser", llm)
|
|
|
|
self.params = {
|
|
"temperature": 0.1,
|
|
"top_p": 0.5,
|
|
"max_tokens": 4000
|
|
}
|
|
|
|
self.system_prompt = """Tu es un expert en analyse de tickets pour le support informatique de BRG-Lab pour la société CBAO.
|
|
Tu interviens avant l'analyse des captures d'écran pour contextualiser le ticket, identifier les questions posées, et structurer les échanges de manière claire.
|
|
|
|
Ta mission principale :
|
|
|
|
1. Identifier le client et le contexte du ticket (demande "name" et "description")
|
|
- Récupère le nom de l'auteur si présent
|
|
- Indique si un `user_id` est disponible
|
|
- Conserve uniquement les informations d'identification utiles (pas d'adresse ou signature de mail inutile)
|
|
|
|
2. Mettre en perspective le `name` du ticket
|
|
- Il peut contenir une ou plusieurs questions implicites
|
|
- Reformule ces questions de façon explicite
|
|
|
|
3. Analyser la `description`
|
|
- Elle fournit souvent le vrai point d'entrée technique
|
|
- Repère les formulations interrogatives ou les demandes spécifiques
|
|
- Identifie si cette partie complète ou précise les questions du nom
|
|
|
|
4. Structurer le fil de discussion
|
|
- Conserve uniquement les échanges pertinents
|
|
-Conserve les questions soulevés par "name" ou "description"
|
|
- CONSERVE ABSOLUMENT les références documentation, FAQ, liens utiles et manuels
|
|
- Identifie clairement chaque intervenant (client / support)
|
|
- Classe les informations par ordre chronologique avec date et rôle
|
|
|
|
5. Préparer la transmission à l'agent suivant
|
|
- Préserve tous les éléments utiles à l'analyse d'image : modules cités, options évoquées, comportements décrits
|
|
- Mentionne si des images sont attachées au ticket
|
|
|
|
Structure ta réponse :
|
|
|
|
1. Résumé du contexte
|
|
- Client (nom, email si disponible)
|
|
- Sujet du ticket reformulé en une ou plusieurs questions
|
|
- Description technique synthétique
|
|
|
|
2. Informations techniques détectées
|
|
- Logiciels/modules mentionnés
|
|
- Paramètres évoqués
|
|
- Fonctionnalités impactées
|
|
- Conditions spécifiques (multi-laboratoire, utilisateur non valide, etc.)
|
|
|
|
3. Fil de discussion (filtrée, nettoyée, classée)
|
|
- Intervenant (Client/Support)
|
|
- Date et contenu de chaque échange
|
|
- Résumés techniques
|
|
- INCLURE TOUS les liens documentaires (manuel, FAQ, documentation technique)
|
|
|
|
4. Éléments liés à l'analyse visuelle
|
|
- Nombre d'images attachées
|
|
- Références aux interfaces ou options à visualiser
|
|
- Points à vérifier dans les captures (listes incomplètes, cases à cocher, utilisateurs grisés, etc.)
|
|
|
|
IMPORTANT :
|
|
- Ne propose aucune solution ni interprétation
|
|
- Ne génère pas de tableau
|
|
- Reste strictement factuel en te basant uniquement sur les informations fournies
|
|
- Ne reformule pas les messages, conserve les formulations exactes sauf nettoyage de forme"""
|
|
|
|
self.ticket_loader = TicketDataLoader()
|
|
self._appliquer_config_locale()
|
|
logger.info("AgentTicketAnalyser initialisé")
|
|
|
|
def _appliquer_config_locale(self) -> None:
|
|
if hasattr(self.llm, "prompt_system"):
|
|
self.llm.prompt_system = self.system_prompt
|
|
if hasattr(self.llm, "configurer"):
|
|
self.llm.configurer(**self.params)
|
|
def executer(self, ticket_data: Dict[str, Any]) -> str:
|
|
if isinstance(ticket_data, str) and os.path.exists(ticket_data):
|
|
ticket_data = self.ticket_loader.charger(ticket_data)
|
|
|
|
if not isinstance(ticket_data, dict):
|
|
logger.error("Les données du ticket ne sont pas valides")
|
|
return "ERREUR: Format de ticket invalide"
|
|
|
|
ticket_code = ticket_data.get("code", "Inconnu")
|
|
logger.info(f"Analyse du ticket {ticket_code}")
|
|
print(f"AgentTicketAnalyser: analyse du ticket {ticket_code}")
|
|
|
|
prompt = self._generer_prompt(ticket_data)
|
|
|
|
try:
|
|
response = self.llm.interroger(prompt)
|
|
logger.info("Analyse du ticket terminée avec succès")
|
|
print(f" Analyse terminée: {len(response)} caractères")
|
|
|
|
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", {})
|
|
},
|
|
"source_agent": self.nom
|
|
}
|
|
}
|
|
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)}"
|
|
|
|
self.ajouter_historique("analyse_ticket", {
|
|
"ticket_id": ticket_code,
|
|
"prompt": prompt,
|
|
"timestamp": self._get_timestamp()
|
|
}, response)
|
|
|
|
return response
|
|
|
|
def _generer_prompt(self, ticket_data: Dict[str, Any]) -> str:
|
|
ticket_code = ticket_data.get("code", "Inconnu")
|
|
name = ticket_data.get("name", "").strip()
|
|
description = ticket_data.get("description", "").strip()
|
|
create_date = ticket_data.get("create_date", "")
|
|
auteur_initial = ticket_data.get("partner_id_email_from", "Client")
|
|
|
|
texte = f"### TICKET {ticket_code}\n\n"
|
|
|
|
if name:
|
|
texte += f"--- MESSAGE INITIAL DU CLIENT ---\n"
|
|
texte += f"Auteur : {auteur_initial}\n"
|
|
texte += f"Date : {self._formater_date(create_date)}\n"
|
|
texte += f"Contenu :\n{name}\n"
|
|
if description and description != "<p><br></p>":
|
|
texte += f"{description}\n\n"
|
|
|
|
messages = ticket_data.get("messages", [])
|
|
for i, msg in enumerate(messages):
|
|
if not isinstance(msg, dict):
|
|
continue
|
|
auteur = msg.get("author_id", "inconnu")
|
|
date = self._formater_date(msg.get("date", "inconnue"))
|
|
sujet = msg.get("subject", "").strip()
|
|
message_type = msg.get("message_type", "").strip()
|
|
contenu = msg.get("content", "").strip()
|
|
|
|
texte += f"--- MESSAGE {i+1} ---\n"
|
|
texte += f"Auteur : {auteur}\n"
|
|
texte += f"Date : {date}\n"
|
|
texte += f"Type : {message_type}\n"
|
|
if sujet:
|
|
texte += f"Sujet : {sujet}\n"
|
|
texte += f"Contenu :\n{contenu}\n\n"
|
|
|
|
return texte
|
|
|
|
def _formater_date(self, date_str: str) -> str:
|
|
if not date_str:
|
|
return "date inconnue"
|
|
try:
|
|
formats = [
|
|
"%Y-%m-%dT%H:%M:%S.%fZ", "%Y-%m-%dT%H:%M:%SZ",
|
|
"%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S",
|
|
"%d/%m/%Y %H:%M:%S", "%d/%m/%Y"
|
|
]
|
|
for fmt in formats:
|
|
try:
|
|
dt = datetime.strptime(date_str, fmt)
|
|
return dt.strftime("%d/%m/%Y %H:%M")
|
|
except ValueError:
|
|
continue
|
|
return date_str
|
|
except Exception:
|
|
return date_str
|
|
|
|
def _get_timestamp(self) -> str:
|
|
return datetime.now().strftime("%Y%m%d_%H%M%S")
|