mirror of
https://github.com/Ladebeze66/llm_ticket3.git
synced 2025-12-16 21:37:49 +01:00
196 lines
8.1 KiB
Python
196 lines
8.1 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
import json
|
|
import time
|
|
import logging
|
|
from typing import Dict, Any, Optional
|
|
|
|
# Importer BaseAgent depuis le répertoire utils
|
|
from agents.utils.base_agent import BaseAgent
|
|
|
|
# Configuration du logging
|
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
logger = logging.getLogger("AgentTicketAnalyser_DeepSeek")
|
|
|
|
class AgentTicketAnalyser(BaseAgent):
|
|
"""
|
|
Agent spécialisé pour analyser un ticket et en extraire les informations clés.
|
|
Version optimisée pour DeepSeek.
|
|
"""
|
|
|
|
def __init__(self, llm: Any):
|
|
"""
|
|
Initialise l'agent d'analyse de ticket avec un modèle LLM.
|
|
|
|
Args:
|
|
llm: Instance du modèle de langage à utiliser
|
|
"""
|
|
super().__init__(llm)
|
|
self.temperature = 0.1 # Température très basse pour une analyse factuelle
|
|
self.top_p = 0.9
|
|
self.max_tokens = 4000
|
|
|
|
# System prompt spécifique pour l'analyse de tickets avec DeepSeek
|
|
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"""
|
|
|
|
def executer(self, ticket_data: Dict[str, Any]) -> str:
|
|
"""
|
|
Analyse un ticket à partir des données fournies.
|
|
|
|
Args:
|
|
ticket_data: Dictionnaire contenant les données du ticket
|
|
- 'ticket_summary': Résumé du ticket
|
|
- 'messages': Liste des messages du ticket
|
|
|
|
Returns:
|
|
str: Analyse structurée du ticket
|
|
"""
|
|
start_time = time.time()
|
|
|
|
try:
|
|
# Extraire le résumé du ticket
|
|
ticket_summary = ticket_data.get('ticket_summary', {})
|
|
ticket_code = ticket_summary.get('code', 'INCONNU')
|
|
ticket_sujet = ticket_summary.get('sujet', 'Sans sujet')
|
|
|
|
# Log des informations de base du ticket
|
|
logger.info(f"Analyse du ticket {ticket_code}: {ticket_sujet}")
|
|
print(f" Analyse du ticket {ticket_code}: {ticket_sujet[:80]}{'...' if len(ticket_sujet) > 80 else ''}")
|
|
|
|
# Construire le contexte à partir des messages
|
|
messages = ticket_data.get('messages', [])
|
|
|
|
# Construire un prompt pour analyser le ticket
|
|
ticket_prompt = self._construire_prompt_ticket(ticket_summary, messages)
|
|
|
|
# Analyser le ticket avec le LLM
|
|
analyse = self.llm.generate(
|
|
system_prompt=self.system_prompt,
|
|
prompt=ticket_prompt,
|
|
temperature=self.temperature,
|
|
top_p=self.top_p,
|
|
max_tokens=self.max_tokens
|
|
)
|
|
|
|
# Calcul du temps de génération
|
|
generation_time = time.time() - start_time
|
|
|
|
# Log de l'analyse complétée
|
|
logger.info(f"Analyse complétée en {generation_time:.2f} secondes")
|
|
print(f" Analyse complétée en {generation_time:.2f} secondes")
|
|
|
|
return analyse
|
|
|
|
except Exception as e:
|
|
logger.error(f"Erreur lors de l'analyse du ticket: {str(e)}")
|
|
return f"ERREUR: Impossible d'analyser le ticket: {str(e)}"
|
|
|
|
def _construire_prompt_ticket(self, ticket_summary: Dict[str, Any], messages: list) -> str:
|
|
"""
|
|
Construit un prompt détaillé à partir des données du ticket.
|
|
|
|
Args:
|
|
ticket_summary: Résumé du ticket
|
|
messages: Liste des messages du ticket
|
|
|
|
Returns:
|
|
str: Prompt détaillé pour l'analyse
|
|
"""
|
|
# Construire l'en-tête avec les informations du ticket
|
|
prompt = f"# TICKET: {ticket_summary.get('code', 'INCONNU')}\n"
|
|
prompt += f"Sujet: {ticket_summary.get('sujet', 'Sans sujet')}\n"
|
|
prompt += f"Statut: {ticket_summary.get('statut', 'Inconnu')}\n"
|
|
prompt += f"Priorité: {ticket_summary.get('priorité', 'Non définie')}\n"
|
|
prompt += f"Date de création: {ticket_summary.get('date_création', 'Inconnue')}\n\n"
|
|
|
|
# Ajouter la section des messages
|
|
prompt += "## MESSAGES DU TICKET\n\n"
|
|
|
|
for i, message in enumerate(messages, 1):
|
|
# Extraire les informations du message
|
|
date = message.get('date', 'Date inconnue')
|
|
auteur = message.get('auteur', 'Auteur inconnu')
|
|
role = message.get('role', 'Rôle inconnu')
|
|
contenu = message.get('contenu', '')
|
|
|
|
# Ajouter l'en-tête du message
|
|
prompt += f"### Message {i} - {date}\n"
|
|
prompt += f"De: {auteur} ({role})\n\n"
|
|
|
|
# Ajouter le contenu du message
|
|
prompt += f"{contenu}\n\n"
|
|
|
|
# Ajouter les informations sur les pièces jointes si disponibles
|
|
attachments = message.get('attachments', [])
|
|
if attachments:
|
|
prompt += f"Pièces jointes ({len(attachments)}):\n"
|
|
for attachment in attachments:
|
|
prompt += f"- {attachment.get('nom', 'Sans nom')} ({attachment.get('type', 'Type inconnu')})\n"
|
|
prompt += "\n"
|
|
|
|
# Ajouter les instructions d'analyse
|
|
prompt += "\n## INSTRUCTIONS\n"
|
|
prompt += "Analyse ce ticket selon les instructions dans ton system prompt. "
|
|
prompt += "Fournis une analyse structurée et complète qui servira de base à l'analyse des images."
|
|
|
|
return prompt |