from pydantic import BaseModel, Field class DocumentInfo(BaseModel): document_id: str name: str chunks_count: int file_type: str created_at: str metadata: dict = Field(default_factory=dict) class ChunkPreview(BaseModel): index: int section: str = "" page_number: int = 0 text_preview: str = "" char_length: int = 0 class DocumentUploadResponse(BaseModel): document_id: str name: str chunks_count: int status: str = "indexed" created_at: str chunks_preview: list[ChunkPreview] = Field(default_factory=list) class DocumentListResponse(BaseModel): documents: list[DocumentInfo] total: int class ChunkDetail(BaseModel): index: int section: str = "" page_number: int = 0 text: str = "" char_length: int = 0 embedding: list[float] = Field(default_factory=list) embedding_dim: int = 0 class DocumentChunksResponse(BaseModel): document_id: str name: str file_type: str chunks_count: int chunks: list[ChunkDetail] = Field(default_factory=list) class DocumentDeleteResponse(BaseModel): ok: bool = True deleted_chunks: int class SourceInfo(BaseModel): document_id: str document_name: str chunk_text: str section: str = "" page: int = 0 relevance_score: float = 0.0 class QueryResponse(BaseModel): answer: str sources: list[SourceInfo] model_used: str assembled_prompt: str = "" class HealthResponse(BaseModel): status: str = "ok" chromadb: str embedding_model: str documents_count: int chunks_count: int class MessageInfo(BaseModel): id: int role: str text: str created_at: str sources: list[SourceInfo] = Field(default_factory=list) assembled_prompt: str = "" intent_code: str = "" intent_name: str = "" class ThreadInfo(BaseModel): id: int name: str created_at: str updated_at: str messages_count: int first_message_preview: str = "" class ThreadListResponse(BaseModel): threads: list[ThreadInfo] total: int class ThreadStateInfo(BaseModel): current_intent_code: str | None = None current_step: int = 0 slots: dict = Field(default_factory=dict) class BounceInfo(BaseModel): from_: str = Field(alias="from") to: str preface: str = "" model_config = {"populate_by_name": True} class ThreadDetailResponse(BaseModel): id: int name: str created_at: str updated_at: str messages: list[MessageInfo] = Field(default_factory=list) thread_state: ThreadStateInfo | None = None class ChatResponse(BaseModel): thread_id: int thread_name: str message_id: int intent_code: str = "" intent_name: str = "" router_intent_code: str = "" config_version: int = 0 router_version: int | None = None answer: str sources: list[SourceInfo] model_used: str assembled_prompt: str = "" thread_state: ThreadStateInfo = Field(default_factory=ThreadStateInfo) bounces: list[BounceInfo] = Field(default_factory=list) class ThreadDeleteResponse(BaseModel): ok: bool = True deleted_messages: int class AgentConfigInfo(BaseModel): id: int intent_id: int | None = None intent_code: str = "" intent_name: str = "" version: int name: str | None = None system_prompt: str rules_text: str = "" is_active: bool created_at: str class AgentConfigListResponse(BaseModel): configs: list[AgentConfigInfo] total: int class AgentConfigDeleteResponse(BaseModel): ok: bool = True class IntentInfo(BaseModel): id: int code: str name: str description: str = "" is_enabled: bool order_index: int active_config_id: int | None = None active_config_version: int | None = None class IntentListResponse(BaseModel): intents: list[IntentInfo] total: int