llm_ticket3/agents/pixtral12b/agent_image_sorter.py.backup
2025-04-14 15:57:31 +02:00

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