# Copyright (c) 2025 Patrick Motsch # All rights reserved. """ Pydantic models for Chatbot V2 feature. Stores context per chat: uploaded files, extracted content, and conversation history. """ import uuid from typing import Optional, List, Dict, Any from pydantic import BaseModel, Field from modules.shared.timeUtils import getUtcTimestamp class ChatbotV2ContextFile(BaseModel): """Uploaded file metadata for context extraction.""" id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") conversationId: str = Field(description="Foreign key to conversation") fileId: str = Field(description="Foreign key to file in central Files table") fileName: str = Field(description="Original file name") mimeType: str = Field(default="application/octet-stream", description="MIME type") fileSize: int = Field(default=0, description="File size in bytes") uploadOrder: int = Field(default=0, description="Order of upload (0-based)") class ChatbotV2ExtractedContext(BaseModel): """Extracted content per conversation - text blocks and summaries for chat context.""" id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") conversationId: str = Field(description="Foreign key to conversation") textBlocks: List[Dict[str, Any]] = Field(default_factory=list, description="Extracted text blocks per file (page, text, block_id)") summaries: List[Dict[str, Any]] = Field(default_factory=list, description="Optional per-document or per-section summaries") extractionStatus: str = Field(default="pending", description="pending|running|completed|failed") errors: List[str] = Field(default_factory=list, description="Extraction errors if any") createdAt: float = Field(default_factory=getUtcTimestamp, description="When extraction completed") class ChatbotV2Document(BaseModel): """Documents attached to chatbot V2 messages.""" 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(default=0, description="Size of the file") mimeType: str = Field(default="application/octet-stream", description="MIME type") class ChatbotV2Message(BaseModel): """Messages in Chatbot V2 conversations.""" id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") conversationId: str = Field(description="Foreign key to conversation") parentMessageId: Optional[str] = Field(None, description="Parent message ID for threading") message: Optional[str] = Field(None, description="Message content") role: str = Field(description="Role: user or assistant") status: str = Field(default="step", description="Status: first, step, last") sequenceNr: int = Field(default=0, description="Sequence number of the message") publishedAt: Optional[float] = Field(default=None, description="When the message was published (UTC timestamp)") roundNumber: int = Field(default=1, description="Round number in conversation") class ChatbotV2Log(BaseModel): """Log entries for Chatbot V2 conversations.""" id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") conversationId: str = Field(description="Foreign key to conversation") message: str = Field(description="Log message") type: str = Field(default="info", description="Log type: info, warning, error") timestamp: float = Field(default_factory=getUtcTimestamp, description="When the log entry was created") status: Optional[str] = Field(None, description="Status of the log entry") progress: Optional[float] = Field(None, description="Progress indicator (0.0 to 1.0)") class ChatbotV2Conversation(BaseModel): """Chatbot V2 conversation - stores context information per chat.""" id: str = Field(default_factory=lambda: str(uuid.uuid4()), description="Primary key") featureInstanceId: str = Field(description="Feature instance ID for per-instance isolation") mandateId: Optional[str] = Field(None, description="Mandate ID for RBAC") name: Optional[str] = Field(None, description="Name of the conversation") status: str = Field(default="extracting", description="extracting|ready|running|stopped") currentRound: int = Field(default=0, description="Current round number") lastActivity: float = Field(default_factory=getUtcTimestamp, description="Timestamp of last activity") startedAt: float = Field(default_factory=getUtcTimestamp, description="When the conversation started") extractedContextId: Optional[str] = Field(None, description="FK to ChatbotV2ExtractedContext when ready") maxSteps: int = Field(default=10, description="Maximum number of chat rounds") # Hydrated from child tables (not stored in DB as columns) contextFiles: List[ChatbotV2ContextFile] = Field(default_factory=list, description="Uploaded context files") messages: List[ChatbotV2Message] = Field(default_factory=list, description="Conversation messages")