#!/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() }