llm_ticket3/scripts/processus_complet.py
2025-04-02 11:43:26 +02:00

383 lines
14 KiB
Python

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