#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Utilitaire pour enregistrer le flux de traitement entre les agents LLM """ import os import time import uuid import json from typing import Dict, Any, Optional, List class WorkflowLogger: """ Enregistreur de flux de travail pour suivre le traitement entre les agents """ def __init__(self, session_id: Optional[str] = None): """ Initialise l'enregistreur de flux de travail Args: session_id (str, optional): Identifiant de session (généré si non fourni) """ # Utiliser l'ID fourni ou en générer un nouveau self.session_id = session_id or str(uuid.uuid4())[:8] self.timestamp = time.strftime("%Y%m%d-%H%M%S") # Répertoire pour les journaux self.log_dir = os.path.join("data", "workflows") os.makedirs(self.log_dir, exist_ok=True) # Fichier principal pour ce flux de travail self.workflow_file = os.path.join(self.log_dir, f"{self.timestamp}_{self.session_id}_workflow.md") # Initialiser le fichier avec un en-tête with open(self.workflow_file, "w", encoding="utf-8") as f: f.write(f"# Flux de traitement - Session {self.session_id}\n\n") f.write(f"Date et heure: {time.strftime('%d/%m/%Y %H:%M:%S')}\n\n") f.write("## Étapes du traitement\n\n") def log_step(self, agent_name: str, input_data: Dict[str, Any], output_data: Any, metadata: Optional[Dict[str, Any]] = None) -> None: """ Enregistre une étape du flux de traitement Args: agent_name (str): Nom de l'agent utilisé input_data (Dict): Données d'entrée de l'agent output_data (Any): Données de sortie de l'agent metadata (Dict, optional): Métadonnées supplémentaires """ step_time = time.strftime("%H:%M:%S") with open(self.workflow_file, "a", encoding="utf-8") as f: # En-tête de l'étape f.write(f"### Étape: {agent_name} ({step_time})\n\n") # Métadonnées si fournies if metadata: f.write("#### Métadonnées\n\n") for key, value in metadata.items(): f.write(f"- **{key}**: {value}\n") f.write("\n") # Entrées f.write("#### Entrées\n\n") for key, value in input_data.items(): if key == "images" and value: f.write(f"- **{key}**: {len(value)} image(s) fournie(s)\n") else: # Limiter la taille des entrées affichées if isinstance(value, str) and len(value) > 500: preview = value[:497] + "..." f.write(f"- **{key}**:\n```\n{preview}\n```\n") else: f.write(f"- **{key}**:\n```\n{value}\n```\n") # Sorties f.write("#### Sorties\n\n") if isinstance(output_data, str) and len(output_data) > 1000: preview = output_data[:997] + "..." f.write(f"```\n{preview}\n```\n") else: f.write(f"```\n{output_data}\n```\n") # Séparateur f.write("\n---\n\n") def log_error(self, agent_name: str, error_message: str, input_data: Optional[Dict[str, Any]] = None) -> None: """ Enregistre une erreur dans le flux de traitement Args: agent_name (str): Nom de l'agent qui a généré l'erreur error_message (str): Message d'erreur input_data (Dict, optional): Données d'entrée qui ont causé l'erreur """ step_time = time.strftime("%H:%M:%S") with open(self.workflow_file, "a", encoding="utf-8") as f: # En-tête de l'erreur f.write(f"### ERREUR dans {agent_name} ({step_time})\n\n") # Message d'erreur f.write("#### Message d'erreur\n\n") f.write(f"```\n{error_message}\n```\n\n") # Entrées si fournies if input_data: f.write("#### Entrées ayant causé l'erreur\n\n") for key, value in input_data.items(): if key == "images" and value: f.write(f"- **{key}**: {len(value)} image(s) fournie(s)\n") else: # Limiter la taille des entrées affichées if isinstance(value, str) and len(value) > 500: preview = value[:497] + "..." f.write(f"- **{key}**:\n```\n{preview}\n```\n") else: f.write(f"- **{key}**:\n```\n{value}\n```\n") # Séparateur f.write("\n---\n\n") def log_summary(self, summary_text: str) -> None: """ Ajoute un résumé final au flux de traitement Args: summary_text (str): Texte du résumé """ with open(self.workflow_file, "a", encoding="utf-8") as f: f.write("## Résumé du traitement\n\n") f.write(f"{summary_text}\n\n") f.write(f"*Fin du flux de traitement - {time.strftime('%d/%m/%Y %H:%M:%S')}*\n") def get_workflow_path(self) -> str: """ Renvoie le chemin du fichier de flux de travail Returns: str: Chemin du fichier """ return self.workflow_file