"""Chat models: ChatWorkflow, ChatMessage, ChatLog, ChatStat, ChatDocument.""" from typing import List, Dict, Any, Optional from pydantic import BaseModel, Field from modules.shared.attributeUtils import register_model_labels, ModelMixin from modules.shared.timezoneUtils import get_utc_timestamp import uuid class ChatStat(BaseModel, ModelMixin): id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") workflowId: Optional[str] = Field(None, description="Foreign key to workflow (for workflow stats)") messageId: Optional[str] = Field(None, description="Foreign key to message (for message stats)") processingTime: Optional[float] = Field(None, description="Processing time in seconds") tokenCount: Optional[int] = Field(None, description="Number of tokens processed") bytesSent: Optional[int] = Field(None, description="Number of bytes sent") bytesReceived: Optional[int] = Field(None, description="Number of bytes received") successRate: Optional[float] = Field(None, description="Success rate of operations") errorCount: Optional[int] = Field(None, description="Number of errors encountered") register_model_labels( "ChatStat", {"en": "Chat Statistics", "fr": "Statistiques de chat"}, { "id": {"en": "ID", "fr": "ID"}, "workflowId": {"en": "Workflow ID", "fr": "ID du workflow"}, "messageId": {"en": "Message ID", "fr": "ID du message"}, "processingTime": {"en": "Processing Time", "fr": "Temps de traitement"}, "tokenCount": {"en": "Token Count", "fr": "Nombre de tokens"}, "bytesSent": {"en": "Bytes Sent", "fr": "Octets envoyés"}, "bytesReceived": {"en": "Bytes Received", "fr": "Octets reçus"}, "successRate": {"en": "Success Rate", "fr": "Taux de succès"}, "errorCount": {"en": "Error Count", "fr": "Nombre d'erreurs"}, }, ) class ChatLog(BaseModel, ModelMixin): id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") workflowId: str = Field(description="Foreign key to workflow") message: str = Field(description="Log message") type: str = Field(description="Log type (info, warning, error, etc.)") timestamp: float = Field(default_factory=get_utc_timestamp, description="When the log entry was created (UTC timestamp in seconds)") status: Optional[str] = Field(None, description="Status of the log entry") progress: Optional[float] = Field(None, description="Progress indicator (0.0 to 1.0)") performance: Optional[Dict[str, Any]] = Field(None, description="Performance metrics") register_model_labels( "ChatLog", {"en": "Chat Log", "fr": "Journal de chat"}, { "id": {"en": "ID", "fr": "ID"}, "workflowId": {"en": "Workflow ID", "fr": "ID du flux de travail"}, "message": {"en": "Message", "fr": "Message"}, "type": {"en": "Type", "fr": "Type"}, "timestamp": {"en": "Timestamp", "fr": "Horodatage"}, "status": {"en": "Status", "fr": "Statut"}, "progress": {"en": "Progress", "fr": "Progression"}, "performance": {"en": "Performance", "fr": "Performance"}, }, ) class ChatDocument(BaseModel, ModelMixin): id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") messageId: str = Field(description="Foreign key to message") fileId: str = Field(description="Foreign key to file") fileName: str = Field(description="Name of the file") fileSize: int = Field(description="Size of the file") mimeType: str = Field(description="MIME type of the file") roundNumber: Optional[int] = Field(None, description="Round number in workflow") taskNumber: Optional[int] = Field(None, description="Task number within round") actionNumber: Optional[int] = Field(None, description="Action number within task") actionId: Optional[str] = Field(None, description="ID of the action that created this document") register_model_labels( "ChatDocument", {"en": "Chat Document", "fr": "Document de chat"}, { "id": {"en": "ID", "fr": "ID"}, "messageId": {"en": "Message ID", "fr": "ID du message"}, "fileId": {"en": "File ID", "fr": "ID du fichier"}, "fileName": {"en": "File Name", "fr": "Nom du fichier"}, "fileSize": {"en": "File Size", "fr": "Taille du fichier"}, "mimeType": {"en": "MIME Type", "fr": "Type MIME"}, "roundNumber": {"en": "Round Number", "fr": "Numéro de tour"}, "taskNumber": {"en": "Task Number", "fr": "Numéro de tâche"}, "actionNumber": {"en": "Action Number", "fr": "Numéro d'action"}, "actionId": {"en": "Action ID", "fr": "ID de l'action"}, }, ) class ContentMetadata(BaseModel, ModelMixin): size: int = Field(description="Content size in bytes") pages: Optional[int] = Field(None, description="Number of pages for multi-page content") error: Optional[str] = Field(None, description="Processing error if any") width: Optional[int] = Field(None, description="Width in pixels for images/videos") height: Optional[int] = Field(None, description="Height in pixels for images/videos") colorMode: Optional[str] = Field(None, description="Color mode") fps: Optional[float] = Field(None, description="Frames per second for videos") durationSec: Optional[float] = Field(None, description="Duration in seconds for media") mimeType: str = Field(description="MIME type of the content") base64Encoded: bool = Field(description="Whether the data is base64 encoded") register_model_labels( "ContentMetadata", {"en": "Content Metadata", "fr": "Métadonnées du contenu"}, { "size": {"en": "Size", "fr": "Taille"}, "pages": {"en": "Pages", "fr": "Pages"}, "error": {"en": "Error", "fr": "Erreur"}, "width": {"en": "Width", "fr": "Largeur"}, "height": {"en": "Height", "fr": "Hauteur"}, "colorMode": {"en": "Color Mode", "fr": "Mode de couleur"}, "fps": {"en": "FPS", "fr": "IPS"}, "durationSec": {"en": "Duration", "fr": "Durée"}, "mimeType": {"en": "MIME Type", "fr": "Type MIME"}, "base64Encoded": {"en": "Base64 Encoded", "fr": "Encodé en Base64"}, }, ) class ContentItem(BaseModel, ModelMixin): label: str = Field(description="Content label") data: str = Field(description="Extracted text content") metadata: ContentMetadata = Field(description="Content metadata") register_model_labels( "ContentItem", {"en": "Content Item", "fr": "Élément de contenu"}, { "label": {"en": "Label", "fr": "Étiquette"}, "data": {"en": "Data", "fr": "Données"}, "metadata": {"en": "Metadata", "fr": "Métadonnées"}, }, ) class ExtractedContent(BaseModel, ModelMixin): id: str = Field(description="Reference to source ChatDocument") contents: List[ContentItem] = Field(default_factory=list, description="List of content items") register_model_labels( "ExtractedContent", {"en": "Extracted Content", "fr": "Contenu extrait"}, { "id": {"en": "Object ID", "fr": "ID de l'objet"}, "contents": {"en": "Contents", "fr": "Contenus"}, }, ) class ChatMessage(BaseModel, ModelMixin): id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") workflowId: str = Field(description="Foreign key to workflow") parentMessageId: Optional[str] = Field(None, description="Parent message ID for threading") documents: List[ChatDocument] = Field(default_factory=list, description="Associated documents") documentsLabel: Optional[str] = Field(None, description="Label for the set of documents") message: Optional[str] = Field(None, description="Message content") role: str = Field(description="Role of the message sender") status: str = Field(description="Status of the message (first, step, last)") sequenceNr: int = Field(description="Sequence number of the message (set automatically)") publishedAt: float = Field(default_factory=get_utc_timestamp, description="When the message was published (UTC timestamp in seconds)") stats: Optional[ChatStat] = Field(None, description="Statistics for this message") success: Optional[bool] = Field(None, description="Whether the message processing was successful") actionId: Optional[str] = Field(None, description="ID of the action that produced this message") actionMethod: Optional[str] = Field(None, description="Method of the action that produced this message") actionName: Optional[str] = Field(None, description="Name of the action that produced this message") roundNumber: Optional[int] = Field(None, description="Round number in workflow") taskNumber: Optional[int] = Field(None, description="Task number within round") actionNumber: Optional[int] = Field(None, description="Action number within task") taskProgress: Optional[str] = Field(None, description="Task progress status: pending, running, success, fail, retry") actionProgress: Optional[str] = Field(None, description="Action progress status: pending, running, success, fail") register_model_labels( "ChatMessage", {"en": "Chat Message", "fr": "Message de chat"}, { "id": {"en": "ID", "fr": "ID"}, "workflowId": {"en": "Workflow ID", "fr": "ID du flux de travail"}, "parentMessageId": {"en": "Parent Message ID", "fr": "ID du message parent"}, "documents": {"en": "Documents", "fr": "Documents"}, "documentsLabel": {"en": "Documents Label", "fr": "Label des documents"}, "message": {"en": "Message", "fr": "Message"}, "role": {"en": "Role", "fr": "Rôle"}, "status": {"en": "Status", "fr": "Statut"}, "sequenceNr": {"en": "Sequence Number", "fr": "Numéro de séquence"}, "publishedAt": {"en": "Published At", "fr": "Publié le"}, "stats": {"en": "Statistics", "fr": "Statistiques"}, "success": {"en": "Success", "fr": "Succès"}, "actionId": {"en": "Action ID", "fr": "ID de l'action"}, "actionMethod": {"en": "Action Method", "fr": "Méthode de l'action"}, "actionName": {"en": "Action Name", "fr": "Nom de l'action"}, "roundNumber": {"en": "Round Number", "fr": "Numéro de tour"}, "taskNumber": {"en": "Task Number", "fr": "Numéro de tâche"}, "actionNumber": {"en": "Action Number", "fr": "Numéro d'action"}, "taskProgress": {"en": "Task Progress", "fr": "Progression de la tâche"}, "actionProgress": {"en": "Action Progress", "fr": "Progression de l'action"}, }, ) class ChatWorkflow(BaseModel, ModelMixin): id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key", frontend_type="text", frontend_readonly=True, frontend_required=False) mandateId: str = Field(description="ID of the mandate this workflow belongs to", frontend_type="text", frontend_readonly=True, frontend_required=False) status: str = Field(description="Current status of the workflow", frontend_type="select", frontend_readonly=False, frontend_required=False, frontend_options=[ {"value": "running", "label": {"en": "Running", "fr": "En cours"}}, {"value": "completed", "label": {"en": "Completed", "fr": "Terminé"}}, {"value": "stopped", "label": {"en": "Stopped", "fr": "Arrêté"}}, {"value": "error", "label": {"en": "Error", "fr": "Erreur"}}, ]) name: Optional[str] = Field(None, description="Name of the workflow", frontend_type="text", frontend_readonly=False, frontend_required=True) currentRound: int = Field(description="Current round number", frontend_type="integer", frontend_readonly=True, frontend_required=False) currentTask: int = Field(default=0, description="Current task number", frontend_type="integer", frontend_readonly=True, frontend_required=False) currentAction: int = Field(default=0, description="Current action number", frontend_type="integer", frontend_readonly=True, frontend_required=False) totalTasks: int = Field(default=0, description="Total number of tasks in the workflow", frontend_type="integer", frontend_readonly=True, frontend_required=False) totalActions: int = Field(default=0, description="Total number of actions in the workflow", frontend_type="integer", frontend_readonly=True, frontend_required=False) lastActivity: float = Field(default_factory=get_utc_timestamp, description="Timestamp of last activity (UTC timestamp in seconds)", frontend_type="timestamp", frontend_readonly=True, frontend_required=False) startedAt: float = Field(default_factory=get_utc_timestamp, description="When the workflow started (UTC timestamp in seconds)", frontend_type="timestamp", frontend_readonly=True, frontend_required=False) logs: List[ChatLog] = Field(default_factory=list, description="Workflow logs", frontend_type="text", frontend_readonly=True, frontend_required=False) messages: List[ChatMessage] = Field(default_factory=list, description="Messages in the workflow", frontend_type="text", frontend_readonly=True, frontend_required=False) stats: Optional[ChatStat] = Field(None, description="Workflow statistics", frontend_type="text", frontend_readonly=True, frontend_required=False) tasks: list = Field(default_factory=list, description="List of tasks in the workflow", frontend_type="text", frontend_readonly=True, frontend_required=False) workflowMode: str = Field(default="Actionplan", description="Workflow mode selector", frontend_type="select", frontend_readonly=False, frontend_required=False, frontend_options=[ {"value": "Actionplan", "label": {"en": "Action Plan", "fr": "Plan d'actions"}}, {"value": "React", "label": {"en": "React", "fr": "Réactif"}}, ]) maxSteps: int = Field(default=5, description="Maximum number of iterations in react mode", frontend_type="integer", frontend_readonly=False, frontend_required=False) register_model_labels( "ChatWorkflow", {"en": "Chat Workflow", "fr": "Flux de travail de chat"}, { "id": {"en": "ID", "fr": "ID"}, "mandateId": {"en": "Mandate ID", "fr": "ID du mandat"}, "status": {"en": "Status", "fr": "Statut"}, "name": {"en": "Name", "fr": "Nom"}, "currentRound": {"en": "Current Round", "fr": "Tour actuel"}, "currentTask": {"en": "Current Task", "fr": "Tâche actuelle"}, "currentAction": {"en": "Current Action", "fr": "Action actuelle"}, "totalTasks": {"en": "Total Tasks", "fr": "Total des tâches"}, "totalActions": {"en": "Total Actions", "fr": "Total des actions"}, "lastActivity": {"en": "Last Activity", "fr": "Dernière activité"}, "startedAt": {"en": "Started At", "fr": "Démarré le"}, "logs": {"en": "Logs", "fr": "Journaux"}, "messages": {"en": "Messages", "fr": "Messages"}, "stats": {"en": "Statistics", "fr": "Statistiques"}, "tasks": {"en": "Tasks", "fr": "Tâches"}, "workflowMode": {"en": "Workflow Mode", "fr": "Mode de workflow"}, "maxSteps": {"en": "Max Steps", "fr": "Étapes max"}, }, ) class WorkflowResult(BaseModel, ModelMixin): status: str completed_tasks: int total_tasks: int execution_time: float final_results_count: int error: Optional[str] = None phase: Optional[str] = None register_model_labels( "WorkflowResult", {"en": "Workflow Result", "fr": "Résultat du workflow"}, { "status": {"en": "Status", "fr": "Statut"}, "completed_tasks": {"en": "Completed Tasks", "fr": "Tâches terminées"}, "total_tasks": {"en": "Total Tasks", "fr": "Total des tâches"}, "execution_time": {"en": "Execution Time", "fr": "Temps d'exécution"}, "final_results_count": {"en": "Final Results Count", "fr": "Nombre de résultats finaux"}, "error": {"en": "Error", "fr": "Erreur"}, "phase": {"en": "Phase", "fr": "Phase"}, }, ) class UserInputRequest(BaseModel, ModelMixin): prompt: str = Field(description="Prompt for the user") listFileId: List[str] = Field(default_factory=list, description="List of file IDs") userLanguage: str = Field(default="en", description="User's preferred language") register_model_labels( "UserInputRequest", {"en": "User Input Request", "fr": "Demande de saisie utilisateur"}, { "prompt": {"en": "Prompt", "fr": "Invite"}, "listFileId": {"en": "File IDs", "fr": "IDs des fichiers"}, "userLanguage": {"en": "User Language", "fr": "Langue de l'utilisateur"}, }, )