#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Script principal d'orchestration du processus d'analyse de tickets. Ce script permet d'exécuter toutes les étapes du traitement ou des étapes individuelles. """ import os import sys import json import argparse import subprocess import logging from typing import Dict, List, Any, Optional import shutil # Configuration du logger logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("processus_complet.log"), logging.StreamHandler() ] ) logger = logging.getLogger("processus_complet") def executer_commande(commande: List[str], description: str) -> bool: """ Exécute une commande système et gère les erreurs. Args: commande: Liste des éléments de la commande à exécuter description: Description de la commande pour le journal Returns: True si la commande s'est exécutée avec succès, False sinon """ try: logger.info(f"Exécution: {description}") logger.debug(f"Commande: {' '.join(commande)}") resultat = subprocess.run(commande, check=True, capture_output=True, text=True) logger.info(f"Succès: {description}") logger.debug(f"Sortie: {resultat.stdout}") return True except subprocess.CalledProcessError as e: logger.error(f"Échec: {description}") logger.error(f"Code de sortie: {e.returncode}") logger.error(f"Erreur: {e.stderr}") return False except Exception as e: logger.error(f"Erreur lors de l'exécution de la commande: {str(e)}") return False def etape_extraction(ticket_dir: str, output_dir: str) -> bool: """ Exécute l'étape d'extraction des données du ticket. Args: ticket_dir: Répertoire contenant les données brutes du ticket output_dir: Répertoire où sauvegarder les données extraites Returns: True si l'extraction a réussi, False sinon """ script_path = os.path.join("scripts", "extract_ticket.py") if not os.path.exists(script_path): logger.error(f"Script d'extraction non trouvé: {script_path}") return False commande = [ sys.executable, script_path, ticket_dir, "--output-dir", output_dir, "--verbose" ] return executer_commande(commande, "Extraction des données du ticket") def etape_filtrage_images(ticket_dir: str) -> bool: """ Exécute l'étape de filtrage des images pertinentes. Args: ticket_dir: Répertoire contenant les données du ticket Returns: True si le filtrage a réussi, False sinon """ script_path = os.path.join("scripts", "filter_images.py") if not os.path.exists(script_path): logger.error(f"Script de filtrage d'images non trouvé: {script_path}") return False commande = [ sys.executable, script_path, "--dossier-ticket", ticket_dir, "--output", os.path.join(ticket_dir, "filter_report.json"), "--verbose" ] return executer_commande(commande, "Filtrage des images pertinentes") def etape_analyse_images(ticket_dir: str, rapport_filtrage: str) -> bool: """ Exécute l'étape d'analyse des images pertinentes. Args: ticket_dir: Répertoire contenant les données du ticket rapport_filtrage: Chemin vers le rapport de filtrage d'images Returns: True si l'analyse a réussi, False sinon """ script_path = os.path.join("scripts", "analyze_image_contexte.py") ticket_info_path = os.path.join(ticket_dir, "ticket_info.json") if not os.path.exists(script_path): logger.error(f"Script d'analyse d'images non trouvé: {script_path}") return False # Charger le rapport de filtrage try: with open(rapport_filtrage, 'r', encoding='utf-8') as f: filtre_data = json.load(f) images_pertinentes = filtre_data.get("images_pertinentes", []) if not images_pertinentes: logger.info("Aucune image pertinente à analyser") return True except Exception as e: logger.error(f"Erreur lors du chargement du rapport de filtrage: {str(e)}") return False # Créer le répertoire pour les rapports d'analyse d'images images_analyses_dir = os.path.join(ticket_dir, "images_analyses") os.makedirs(images_analyses_dir, exist_ok=True) # Analyser chaque image pertinente succes = True for image_path in images_pertinentes: image_name = os.path.basename(image_path) output_base = os.path.join(images_analyses_dir, image_name) commande = [ sys.executable, script_path, "--image", image_path, "--ticket-info", ticket_info_path, "--output", output_base + "_analyse", "--verbose" ] if not executer_commande(commande, f"Analyse de l'image {image_name}"): succes = False return succes def etape_analyse_ticket(ticket_dir: str, rapport_filtrage: str) -> bool: """ Exécute l'étape d'analyse du contenu du ticket. Args: ticket_dir: Répertoire contenant les données du ticket rapport_filtrage: Chemin vers le rapport de filtrage d'images Returns: True si l'analyse a réussi, False sinon """ script_path = os.path.join("scripts", "analyze_ticket.py") messages_path = os.path.join(ticket_dir, "messages.json") if not os.path.exists(script_path): logger.error(f"Script d'analyse de ticket non trouvé: {script_path}") return False commande = [ sys.executable, script_path, "--messages", messages_path, "--images-rapport", rapport_filtrage, "--output", ticket_dir, "--verbose" ] return executer_commande(commande, "Analyse du contenu du ticket") def etape_questions_reponses(ticket_dir: str) -> bool: """ Exécute l'étape d'extraction des questions et réponses. Args: ticket_dir: Répertoire contenant les données du ticket Returns: True si l'extraction a réussi, False sinon """ script_path = os.path.join("scripts", "extract_question_reponse.py") messages_path = os.path.join(ticket_dir, "messages.json") output_path = os.path.join(ticket_dir, "questions_reponses.md") if not os.path.exists(script_path): logger.error(f"Script d'extraction des questions-réponses non trouvé: {script_path}") return False commande = [ sys.executable, script_path, "--messages", messages_path, "--output", output_path, "--verbose" ] return executer_commande(commande, "Extraction des questions et réponses") def processus_complet(ticket_code: str, dossier_source: str = None, dossier_sortie: str = None) -> bool: """ Exécute le processus complet d'analyse d'un ticket. Args: ticket_code: Code du ticket à analyser dossier_source: Dossier contenant les tickets bruts (par défaut: output/) dossier_sortie: Dossier où sauvegarder les résultats (par défaut: output_processed/) Returns: True si le processus s'est exécuté avec succès, False sinon """ # Définir les dossiers par défaut si non spécifiés if dossier_source is None: dossier_source = "output" if dossier_sortie is None: dossier_sortie = "output_processed" # Construire les chemins ticket_dir_source = os.path.join(dossier_source, f"ticket_{ticket_code}") ticket_dir_sortie = os.path.join(dossier_sortie, f"ticket_{ticket_code}") # Vérifier que le dossier source existe if not os.path.exists(ticket_dir_source): logger.error(f"Dossier source non trouvé: {ticket_dir_source}") return False # Créer le dossier de sortie s'il n'existe pas os.makedirs(ticket_dir_sortie, exist_ok=True) # 1. Extraction des données if not etape_extraction(ticket_dir_source, ticket_dir_sortie): logger.error("Échec de l'étape d'extraction") return False # 2. Filtrage des images if not etape_filtrage_images(ticket_dir_sortie): logger.error("Échec de l'étape de filtrage des images") return False # 3. Analyse des images pertinentes rapport_filtrage = os.path.join(ticket_dir_sortie, "filter_report.json") if not etape_analyse_images(ticket_dir_sortie, rapport_filtrage): logger.error("Échec de l'étape d'analyse des images") return False # 4. Analyse du contenu du ticket if not etape_analyse_ticket(ticket_dir_sortie, rapport_filtrage): logger.error("Échec de l'étape d'analyse du ticket") return False # 5. Extraction des questions et réponses if not etape_questions_reponses(ticket_dir_sortie): logger.error("Échec de l'étape d'extraction des questions et réponses") return False logger.info(f"Processus complet terminé avec succès pour le ticket {ticket_code}") logger.info(f"Résultats disponibles dans: {ticket_dir_sortie}") return True def main(): """ Point d'entrée du script. """ parser = argparse.ArgumentParser(description="Exécute le processus d'analyse de tickets de support.") parser.add_argument("--ticket", "-t", required=True, help="Code du ticket à analyser (ex: T0167)") parser.add_argument("--source", "-s", help="Dossier source contenant les tickets bruts (par défaut: output/)") parser.add_argument("--output", "-o", help="Dossier de sortie pour les résultats (par défaut: output_processed/)") parser.add_argument("--etapes", "-e", choices=["extraction", "filtrage", "analyse_images", "analyse_ticket", "questions_reponses", "tout"], default="tout", help="Étapes à exécuter") parser.add_argument("--verbose", "-v", action="store_true", help="Afficher plus d'informations") args = parser.parse_args() # Configurer le niveau de log if args.verbose: logging.getLogger().setLevel(logging.DEBUG) # Récupérer le code du ticket ticket_code = args.ticket if ticket_code.startswith("ticket_"): ticket_code = ticket_code[7:] # Définir les dossiers source et sortie dossier_source = args.source or "output" dossier_sortie = args.output or "output_processed" # Construire les chemins ticket_dir_source = os.path.join(dossier_source, f"ticket_{ticket_code}") ticket_dir_sortie = os.path.join(dossier_sortie, f"ticket_{ticket_code}") # Vérifier que le dossier source existe if not os.path.exists(ticket_dir_source): logger.error(f"Dossier source non trouvé: {ticket_dir_source}") sys.exit(1) # Exécuter les étapes demandées if args.etapes == "tout": if processus_complet(ticket_code, dossier_source, dossier_sortie): print(f"Processus complet terminé avec succès pour le ticket {ticket_code}") print(f"Résultats disponibles dans: {ticket_dir_sortie}") else: print(f"Échec du processus pour le ticket {ticket_code}") sys.exit(1) else: # Créer le dossier de sortie s'il n'existe pas os.makedirs(ticket_dir_sortie, exist_ok=True) # Exécuter l'étape spécifique if args.etapes == "extraction": if etape_extraction(ticket_dir_source, ticket_dir_sortie): print("Étape d'extraction terminée avec succès") else: print("Échec de l'étape d'extraction") sys.exit(1) elif args.etapes == "filtrage": if etape_filtrage_images(ticket_dir_sortie): print("Étape de filtrage des images terminée avec succès") else: print("Échec de l'étape de filtrage des images") sys.exit(1) elif args.etapes == "analyse_images": rapport_filtrage = os.path.join(ticket_dir_sortie, "filter_report.json") if not os.path.exists(rapport_filtrage): logger.error(f"Rapport de filtrage non trouvé: {rapport_filtrage}") print("Veuillez d'abord exécuter l'étape de filtrage des images") sys.exit(1) if etape_analyse_images(ticket_dir_sortie, rapport_filtrage): print("Étape d'analyse des images terminée avec succès") else: print("Échec de l'étape d'analyse des images") sys.exit(1) elif args.etapes == "analyse_ticket": rapport_filtrage = os.path.join(ticket_dir_sortie, "filter_report.json") if not os.path.exists(rapport_filtrage): logger.error(f"Rapport de filtrage non trouvé: {rapport_filtrage}") print("Veuillez d'abord exécuter l'étape de filtrage des images") sys.exit(1) if etape_analyse_ticket(ticket_dir_sortie, rapport_filtrage): print("Étape d'analyse du ticket terminée avec succès") else: print("Échec de l'étape d'analyse du ticket") sys.exit(1) elif args.etapes == "questions_reponses": if etape_questions_reponses(ticket_dir_sortie): print("Étape d'extraction des questions et réponses terminée avec succès") else: print("Échec de l'étape d'extraction des questions et réponses") sys.exit(1) if __name__ == "__main__": main()