llm_ticket3/agents/pixtral12b/agent_image_analyser.py
2025-04-14 14:10:19 +02:00

195 lines
7.4 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import json
import time
import logging
import base64
from typing import Dict, Any, List, Optional, Tuple
# 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("AgentImageAnalyser_Pixtral12b")
class AgentImageAnalyser(BaseAgent):
"""
Agent spécialisé pour analyser des images et en extraire les informations pertinentes.
Version optimisée pour Pixtral 12B.
"""
def __init__(self, llm: Any):
"""
Initialise l'agent d'analyse d'images avec un modèle LLM.
Args:
llm: Instance du modèle de langage à utiliser
"""
super().__init__(llm)
self.temperature = 0.1 # Température basse pour des analyses factuelles
self.top_p = 0.9
self.max_tokens = 3000
# System prompt spécifique pour l'analyse d'images
self.system_prompt = """Tu es un expert en analyse d'images de captures d'écran d'applications métier.
Tu vas analyser des images techniques pour en extraire des informations pertinentes.
Pour chaque image, tu dois :
1. Identifier le type d'interface visible (formulaire, tableau, menu, etc.)
2. Extraire tous les éléments visuels importants (champs, boutons, menus, messages)
3. Repérer les anomalies ou problèmes visibles (erreurs, incohérences, éléments manquants)
4. Identifier le contexte fonctionnel de l'image (à quelle fonctionnalité elle correspond)
Ta réponse suivra ce format structuré :
```
## Analyse de l'image: [Titre basé sur le contenu]
### Description générale
- Type d'interface: [type d'interface identifié]
- Éléments principaux: [liste des éléments UI dominants]
- Contexte fonctionnel: [fonctionnalité ou module apparent]
### Éléments détaillés
- [Liste détaillée des éléments visibles importants]
- [Valeurs de champs, options sélectionnées, etc.]
- [Messages système ou d'erreur si présents]
### Anomalies détectées
- [Description précise des problèmes visibles]
- [Éléments manquants ou incohérents]
- [Messages d'erreur et leur contexte]
### Interprétation technique
- [Explication technique de ce qui est affiché]
- [Relation avec le problème décrit dans le ticket]
- [Indications sur la source probable du problème]
```
Reste factuel et précis. Ne spécule pas au-delà de ce qui est clairement visible.
Concentre-toi sur les détails techniques plutôt que sur l'esthétique de l'interface."""
def executer(self, images: List[Dict[str, Any]], ticket_analyse: Optional[str] = None) -> List[Dict[str, Any]]:
"""
Analyse une liste d'images pour en extraire les informations pertinentes.
Args:
images: Liste de dictionnaires contenant les informations sur les images
- 'path': Chemin de l'image
- 'type': Type de l'image
- 'nom': Nom de l'image
ticket_analyse: Analyse du ticket (contexte pour l'analyse des images)
Returns:
Liste de dictionnaires contenant les analyses d'images
"""
results = []
if not images:
logger.warning("Aucune image à analyser")
return results
logger.info(f"Analyse de {len(images)} images")
print(f" Analyse de {len(images)} images")
# Analyser chaque image
for i, image_info in enumerate(images, 1):
image_path = image_info.get('path', '')
image_name = image_info.get('nom', os.path.basename(image_path))
if not os.path.exists(image_path):
logger.warning(f"Image non trouvée: {image_path}")
results.append({
"image": image_info,
"analyse": f"ERREUR: Image non trouvée: {image_path}",
"pertinent": False
})
continue
logger.info(f"Analyse de l'image {i}/{len(images)}: {image_name}")
print(f" Analyse de l'image {i}/{len(images)}: {image_name}")
start_time = time.time()
try:
# Encoder l'image en base64
image_base64 = self._encoder_image_base64(image_path)
# Construire le prompt pour l'analyse
prompt = self._construire_prompt_image(image_name, ticket_analyse)
# Analyser l'image avec le LLM
analyse = self.llm.generate_vision(
system_prompt=self.system_prompt,
prompt=prompt,
image_base64=image_base64,
temperature=self.temperature,
top_p=self.top_p,
max_tokens=self.max_tokens
)
# Calculer le temps d'analyse
analysis_time = time.time() - start_time
# Log de l'analyse complétée
logger.info(f"Analyse de l'image {image_name} complétée en {analysis_time:.2f} secondes")
print(f" Analyse complétée en {analysis_time:.2f} secondes")
# Ajouter le résultat à la liste
results.append({
"image": image_info,
"analyse": analyse,
"pertinent": True,
"analysis_time": analysis_time
})
except Exception as e:
error_message = f"Erreur lors de l'analyse de l'image {image_name}: {str(e)}"
logger.error(error_message)
print(f" ERREUR: {error_message}")
results.append({
"image": image_info,
"analyse": f"ERREUR: {error_message}",
"pertinent": False
})
return results
def _encoder_image_base64(self, image_path: str) -> str:
"""
Encode une image en base64.
Args:
image_path: Chemin de l'image à encoder
Returns:
Chaîne encodée en base64
"""
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
def _construire_prompt_image(self, image_name: str, ticket_analyse: Optional[str] = None) -> str:
"""
Construit un prompt pour l'analyse d'une image.
Args:
image_name: Nom de l'image à analyser
ticket_analyse: Analyse du ticket (contexte pour l'analyse de l'image)
Returns:
Prompt pour l'analyse de l'image
"""
prompt = f"Analyse cette capture d'écran: {image_name}\n\n"
if ticket_analyse:
prompt += "### Contexte du ticket\n"
prompt += f"{ticket_analyse[:1000]}...\n\n" if len(ticket_analyse) > 1000 else f"{ticket_analyse}\n\n"
prompt += "Examine attentivement tous les éléments visuels, repère les anomalies, et identifie les informations techniques pertinentes. "
prompt += "Fournis une analyse complète et structurée de cette image selon le format demandé."
return prompt