mirror of
https://github.com/Ladebeze66/llm_ticket3.git
synced 2025-12-16 03:47:49 +01:00
169 lines
7.1 KiB
Python
169 lines
7.1 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
Agent pour filtrer les images non pertinentes dans un contexte de support technique.
|
|
"""
|
|
|
|
import os
|
|
import json
|
|
import re
|
|
from typing import Dict, Any, Optional
|
|
|
|
from .agent_base import Agent
|
|
from llm import Pixtral
|
|
|
|
class AgentFiltreImages(Agent):
|
|
"""
|
|
Agent qui détermine si une image est pertinente dans un contexte de support technique.
|
|
Filtre les logos, signatures, icônes, etc.
|
|
"""
|
|
def __init__(self, api_key: Optional[str] = None):
|
|
"""
|
|
Initialise l'agent de filtrage d'images.
|
|
|
|
Args:
|
|
api_key: Clé API pour le LLM
|
|
"""
|
|
super().__init__("AgentFiltreImages")
|
|
self.llm = Pixtral(api_key=api_key)
|
|
|
|
# Configuration par défaut du LLM
|
|
default_system_prompt = """
|
|
Vous êtes un expert en analyse d'images techniques. Votre mission est de déterminer
|
|
si une image est pertinente dans un contexte de support technique ou non.
|
|
|
|
Images PERTINENTES:
|
|
- Captures d'écran montrant des problèmes, erreurs, bugs
|
|
- Photos d'équipements avec problèmes visibles
|
|
- Schémas techniques ou diagrammes
|
|
- Graphiques de données techniques
|
|
|
|
Images NON PERTINENTES:
|
|
- Logos d'entreprise
|
|
- Signatures ou avatars
|
|
- Icônes ou boutons isolés
|
|
- Bannières décoratives, séparateurs
|
|
- Images génériques sans information technique
|
|
"""
|
|
self.configurer_llm(
|
|
system_prompt=default_system_prompt,
|
|
temperature=0.2, # Basse température pour des réponses précises
|
|
max_tokens=500 # Réponses courtes pour le filtrage
|
|
)
|
|
|
|
def executer(self, image_path: str) -> Dict[str, Any]:
|
|
"""
|
|
Détermine si une image est pertinente pour l'analyse technique.
|
|
|
|
Args:
|
|
image_path: Chemin vers l'image à analyser
|
|
|
|
Returns:
|
|
Dictionnaire contenant le résultat du filtrage avec au minimum
|
|
{'pertinente': True/False}
|
|
"""
|
|
# Vérifier que l'image existe
|
|
if not os.path.exists(image_path):
|
|
erreur = f"L'image {image_path} n'existe pas"
|
|
self.ajouter_historique("filtre_image_erreur", image_path, erreur)
|
|
return {"pertinente": False, "error": erreur}
|
|
|
|
# Construire le prompt pour la classification
|
|
prompt = """
|
|
Analysez cette image et déterminez si elle est PERTINENTE ou NON PERTINENTE dans un contexte de support technique.
|
|
|
|
Répondez au format JSON suivant:
|
|
{
|
|
"pertinente": true/false,
|
|
"type_image": "capture_ecran|photo_equipement|schema|graphique|logo|icone|decorative|autre",
|
|
"description": "Brève description du contenu",
|
|
"confiance": "valeur de 0 à 100",
|
|
"justification": "Explication de votre décision"
|
|
}
|
|
"""
|
|
|
|
# Enregistrer l'action dans l'historique
|
|
self.ajouter_historique("filtre_image", image_path, "Filtrage en cours...")
|
|
|
|
# Appel au LLM
|
|
try:
|
|
# Pour les cas complexes, augmenter légèrement la température
|
|
if "complexe" in image_path or os.path.getsize(image_path) > 500000:
|
|
self.configurer_llm(temperature=0.4)
|
|
self.ajouter_historique("ajustement_temperature", "Augmentation pour image complexe", "temperature=0.4")
|
|
|
|
resultat_brut = self.llm.analyze_image(image_path, prompt)
|
|
|
|
# Essayer d'extraire le JSON de la réponse
|
|
try:
|
|
content = resultat_brut.get("content", "")
|
|
|
|
# Si le contenu est déjà au format JSON correctement formaté
|
|
if content.strip().startswith("{") and content.strip().endswith("}"):
|
|
try:
|
|
resultat_json = json.loads(content)
|
|
except json.JSONDecodeError:
|
|
# Si le contenu a la structure JSON mais ne peut pas être décodé
|
|
# nettoyer et réessayer
|
|
content_cleaned = content.replace("```json", "").replace("```", "").strip()
|
|
resultat_json = json.loads(content_cleaned)
|
|
else:
|
|
# Chercher un bloc JSON dans la réponse
|
|
json_match = re.search(r'```json\s*(.*?)\s*```', content, re.DOTALL)
|
|
if json_match:
|
|
json_str = json_match.group(1).strip()
|
|
else:
|
|
# Essayer d'extraire un objet JSON sans les blocs de code
|
|
json_match = re.search(r'(\{.*?\})', content, re.DOTALL)
|
|
if json_match:
|
|
json_str = json_match.group(1).strip()
|
|
else:
|
|
# Sinon, prendre tout le contenu comme JSON potentiel
|
|
json_str = content.strip()
|
|
|
|
# Parser le JSON
|
|
resultat_json = json.loads(json_str)
|
|
|
|
# S'assurer que le champ 'pertinente' existe
|
|
if "pertinente" not in resultat_json:
|
|
resultat_json["pertinente"] = False
|
|
resultat_json["error"] = "Format de réponse incorrect"
|
|
|
|
# Ajouter les paramètres LLM utilisés
|
|
resultat_json["parametres_llm"] = self.generer_rapport_parametres()
|
|
|
|
self.ajouter_historique("filtre_image_resultat", "Filtrage terminé",
|
|
f"Pertinente: {resultat_json.get('pertinente', False)}")
|
|
return resultat_json
|
|
|
|
except Exception as e:
|
|
# Pour les modules en mode simulation, utiliser directement la réponse
|
|
if "pertinente" in resultat_brut.get("content", ""):
|
|
try:
|
|
resultat_json = json.loads(resultat_brut.get("content", ""))
|
|
resultat_json["parametres_llm"] = self.generer_rapport_parametres()
|
|
self.ajouter_historique("filtre_image_resultat", "Filtrage terminé",
|
|
f"Pertinente: {resultat_json.get('pertinente', False)}")
|
|
return resultat_json
|
|
except:
|
|
pass
|
|
|
|
# En cas d'erreur de parsing, retourner un résultat par défaut
|
|
resultat = {
|
|
"pertinente": False,
|
|
"error": f"Erreur de parsing JSON: {str(e)}",
|
|
"response_raw": resultat_brut.get("content", "")[:200],
|
|
"parametres_llm": self.generer_rapport_parametres()
|
|
}
|
|
self.ajouter_historique("filtre_image_parsing_erreur", "Erreur de parsing", str(e))
|
|
return resultat
|
|
|
|
except Exception as e:
|
|
erreur = f"Erreur lors du filtrage: {str(e)}"
|
|
self.ajouter_historique("filtre_image_erreur", image_path, erreur)
|
|
return {
|
|
"pertinente": False,
|
|
"error": erreur,
|
|
"parametres_llm": self.generer_rapport_parametres()
|
|
} |