mirror of
https://github.com/Ladebeze66/llm_ticket3.git
synced 2025-12-16 00:06:53 +01:00
193 lines
8.4 KiB
Plaintext
193 lines
8.4 KiB
Plaintext
from agents.utils.base_agent import BaseAgent
|
|
import logging
|
|
import os
|
|
from typing import List, Dict, Any, Optional
|
|
import json
|
|
|
|
logger = logging.getLogger("AgentImageSorter")
|
|
|
|
class AgentImageSorter(BaseAgent):
|
|
"""
|
|
Agent pour trier les images et identifier celles qui sont pertinentes pour l'analyse.
|
|
"""
|
|
def __init__(self, llm):
|
|
super().__init__(llm)
|
|
|
|
# Configuration locale de l'agent
|
|
self.system_prompt = """Tu es un agent spécialisé dans l'analyse et le tri d'images pour le support technique.
|
|
Ta mission est d'identifier les images pertinentes pour comprendre un problème technique, en distinguant
|
|
celles qui contiennent des informations utiles (captures d'écran, photos de produits défectueux, etc.)
|
|
de celles qui sont décoratives ou non informatives.
|
|
|
|
Suis ces directives pour évaluer chaque image:
|
|
1. Identifie le contenu principal de l'image (capture d'écran, photo, schéma, etc.)
|
|
2. Évalue si l'image contient des informations utiles pour comprendre le problème technique
|
|
3. Détermine si l'image montre un problème, une erreur, ou une situation anormale
|
|
4. Examine si l'image contient du texte ou des messages d'erreur importants
|
|
|
|
Pour chaque image, tu dois fournir:
|
|
- Une description concise du contenu (1-2 phrases)
|
|
- Un niveau de pertinence (Élevé/Moyen/Faible)
|
|
- Une justification de ton évaluation"""
|
|
|
|
self.image_batch_size = 3 # Nombre d'images à analyser par lot
|
|
|
|
def executer(self, attachments_dir: str, contexte: Optional[Dict] = None) -> Dict[str, Dict[str, Any]]:
|
|
"""
|
|
Trie les images dans un répertoire de pièces jointes et identifie celles qui sont pertinentes.
|
|
|
|
Args:
|
|
attachments_dir: Chemin vers le répertoire des pièces jointes
|
|
contexte: Contexte optionnel sur le ticket pour aider à l'analyse
|
|
|
|
Returns:
|
|
Dictionnaire avec les chemins des images comme clés et les résultats d'analyse comme valeurs
|
|
"""
|
|
logger.info(f"Tri des images dans: {attachments_dir}")
|
|
|
|
# Vérifier si attachments_dir est un fichier ou un dossier
|
|
if os.path.isfile(attachments_dir):
|
|
logger.info(f"Le chemin fourni est un fichier et non un dossier: {attachments_dir}")
|
|
# Si c'est un fichier image, on le traite directement
|
|
if attachments_dir.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.tiff')):
|
|
images = [attachments_dir]
|
|
# Le vrai dossier est le répertoire parent
|
|
attachments_dir = os.path.dirname(attachments_dir)
|
|
else:
|
|
logger.error(f"Le fichier n'est pas une image: {attachments_dir}")
|
|
return {}
|
|
# Vérifier que le répertoire existe
|
|
elif not os.path.exists(attachments_dir):
|
|
logger.error(f"Le répertoire {attachments_dir} n'existe pas")
|
|
return {}
|
|
else:
|
|
# Lister les images du répertoire
|
|
images = [os.path.join(attachments_dir, f) for f in os.listdir(attachments_dir)
|
|
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif', '.tiff'))]
|
|
|
|
if not images:
|
|
logger.info(f"Aucune image trouvée dans {attachments_dir}")
|
|
return {}
|
|
|
|
logger.info(f"Nombre d'images trouvées: {len(images)}")
|
|
|
|
# Analyser les images individuellement ou par lots selon la configuration
|
|
resultats = {}
|
|
|
|
# Préparer un contexte spécifique pour l'analyse des images
|
|
contexte_analyse = "Aucun contexte disponible."
|
|
if contexte:
|
|
# Extraire des informations pertinentes du contexte
|
|
sujet = contexte.get("sujet", "")
|
|
description = contexte.get("description", "")
|
|
if sujet and description:
|
|
contexte_analyse = f"Sujet du ticket: {sujet}\nDescription du problème: {description}"
|
|
elif sujet:
|
|
contexte_analyse = f"Sujet du ticket: {sujet}"
|
|
elif description:
|
|
contexte_analyse = f"Description du problème: {description}"
|
|
|
|
# Traitement image par image
|
|
for image_path in images:
|
|
image_name = os.path.basename(image_path)
|
|
logger.info(f"Analyse de l'image: {image_name}")
|
|
|
|
prompt = f"""Analyse cette image dans le contexte suivant:
|
|
{contexte_analyse}
|
|
|
|
Réponds au format JSON avec la structure suivante:
|
|
{{
|
|
"description": "Description concise du contenu",
|
|
"pertinence": "Élevé/Moyen/Faible",
|
|
"justification": "Pourquoi cette image est pertinente ou non",
|
|
"contenu_technique": true/false
|
|
}}"""
|
|
|
|
# Analyser l'image
|
|
try:
|
|
resultat_brut = self.llm.interroger_avec_image(image_path, prompt)
|
|
|
|
# Extraire le JSON de la réponse
|
|
json_str = self._extraire_json(resultat_brut)
|
|
if json_str:
|
|
try:
|
|
# Charger le JSON
|
|
analyse = json.loads(json_str)
|
|
# Ajouter le chemin complet pour référence
|
|
analyse["image_path"] = image_path
|
|
resultats[image_path] = analyse
|
|
|
|
pertinence = analyse.get("pertinence", "").lower()
|
|
logger.info(f"Image {image_name} - Pertinence: {pertinence}")
|
|
except json.JSONDecodeError:
|
|
logger.error(f"Erreur de décodage JSON pour {image_name}")
|
|
resultats[image_path] = {
|
|
"description": "Erreur d'analyse",
|
|
"pertinence": "Inconnue",
|
|
"justification": "Erreur de traitement de la réponse",
|
|
"contenu_technique": False,
|
|
"image_path": image_path
|
|
}
|
|
else:
|
|
logger.error(f"Format de réponse incorrect pour {image_name}")
|
|
# Créer une entrée avec les informations disponibles
|
|
resultats[image_path] = {
|
|
"description": "Analyse non disponible",
|
|
"pertinence": "Inconnue",
|
|
"justification": "Format de réponse incorrect",
|
|
"contenu_technique": False,
|
|
"image_path": image_path
|
|
}
|
|
except Exception as e:
|
|
logger.error(f"Erreur lors de l'analyse de l'image {image_name}: {str(e)}")
|
|
resultats[image_path] = {
|
|
"description": "Erreur d'analyse",
|
|
"pertinence": "Inconnue",
|
|
"justification": f"Exception: {str(e)}",
|
|
"contenu_technique": False,
|
|
"image_path": image_path
|
|
}
|
|
|
|
return resultats
|
|
|
|
def _extraire_json(self, texte: str) -> Optional[str]:
|
|
"""
|
|
Extrait le contenu JSON d'une chaîne de texte.
|
|
|
|
Args:
|
|
texte: Texte contenant potentiellement du JSON
|
|
|
|
Returns:
|
|
Chaîne JSON extraite ou None si aucun JSON n'est trouvé
|
|
"""
|
|
# Chercher des accolades ouvrantes et fermantes
|
|
debut = texte.find('{')
|
|
fin = texte.rfind('}')
|
|
|
|
if debut != -1 and fin != -1 and fin > debut:
|
|
return texte[debut:fin+1]
|
|
|
|
return None
|
|
|
|
def filtrer_images_pertinentes(self, resultats: Dict[str, Dict[str, Any]]) -> List[str]:
|
|
"""
|
|
Filtre les images pour ne conserver que celles qui sont pertinentes.
|
|
|
|
Args:
|
|
resultats: Dictionnaire avec les résultats d'analyse des images
|
|
|
|
Returns:
|
|
Liste des chemins des images pertinentes
|
|
"""
|
|
pertinentes = []
|
|
|
|
for image_path, analyse in resultats.items():
|
|
pertinence = analyse.get("pertinence", "").lower()
|
|
contenu_technique = analyse.get("contenu_technique", False)
|
|
|
|
# Considérer comme pertinentes les images avec pertinence élevée ou moyenne
|
|
# ou celles marquées comme ayant un contenu technique
|
|
if pertinence in ["élevé", "moyen", "eleve", "elevé", "medium", "high", "moyenne"] or contenu_technique:
|
|
pertinentes.append(image_path)
|
|
|
|
return pertinentes |