""" 知识库分段 Schema """ from typing import Optional, List, Dict, Any from datetime import datetime from pydantic import BaseModel, Field, ConfigDict from app.base_schema import CSTDatetime class SegmentResponse(BaseModel): """分段输出""" id: str knowledge_base_id: str document_id: str document_name: str = "" position: int = 0 content: str answer: Optional[str] = None token_count: int = 0 char_count: int = 0 word_count: int = 0 page_number: Optional[int] = None keywords: Optional[List[str]] = None metadata: Optional[Dict[str, Any]] = None embedding_status: str = "pending" enabled: bool = True hit_count: int = 0 sys_create_datetime: Optional[CSTDatetime] = None model_config = ConfigDict(from_attributes=True) class SegmentListResponse(BaseModel): """分段列表输出""" id: str document_id: str document_name: str = "" position: int = 0 content: str answer: Optional[str] = None token_count: int = 0 char_count: int = 0 word_count: int = 0 page_number: Optional[int] = None keywords: Optional[List[str]] = None extra_metadata: Optional[Dict[str, Any]] = None enabled: bool = True hit_count: int = 0 embedding_status: str = "pending" sys_create_datetime: Optional[CSTDatetime] = None model_config = ConfigDict(from_attributes=True) class SegmentUpdateInput(BaseModel): """更新分段""" content: Optional[str] = Field(None, description="分段内容") keywords: Optional[List[str]] = Field(None, description="关键词") enabled: Optional[bool] = Field(None, description="是否启用") extra_metadata: Optional[Dict[str, Any]] = Field(None, description="元数据") class SegmentCreateInput(BaseModel): """手动创建分段""" content: str = Field(..., min_length=1, description="分段内容") answer: Optional[str] = Field(None, description="Q&A 模式的答案") keywords: Optional[List[str]] = Field(None, description="关键词") class ChunkPreviewInput(BaseModel): """分块预览输入""" file_id: str = Field(..., description="文件ID") chunk_strategy: str = Field(default="recursive", description="分块策略") chunk_size: int = Field(default=500, ge=100, le=4000, description="分块大小") chunk_overlap: int = Field(default=50, ge=0, le=500, description="分块重叠") separator: Optional[str] = Field(None, description="自定义分隔符") process_rules: Optional[Dict[str, Any]] = Field(None, description="预处理规则") class ChunkPreviewItem(BaseModel): """分块预览结果项""" position: int = 0 content: str = "" char_count: int = 0 token_count: int = 0 word_count: int = 0 answer: Optional[str] = None metadata: Optional[Dict[str, Any]] = None class ChunkPreviewResponse(BaseModel): """分块预览响应""" chunks: List[ChunkPreviewItem] = Field(default_factory=list) total: int = 0 strategy: str = "" chunk_size: int = 0 chunk_overlap: int = 0 class RetrievalInput(BaseModel): """检索输入""" model_config = ConfigDict(protected_namespaces=()) query: str = Field(..., min_length=1, description="查询文本") knowledge_base_ids: List[str] = Field(..., min_length=1, description="知识库ID列表") top_k: int = Field(default=5, ge=1, le=20, description="返回数量") score_threshold: float = Field(default=0.5, ge=0, le=1, description="相似度阈值") retrieval_mode: Optional[str] = Field(None, description="检索模式(不传则使用知识库配置)") rerank_enabled: Optional[bool] = Field(None, description="是否启用重排序(不传则使用知识库配置)") rerank_model_id: Optional[str] = Field(None, description="重排序模型ID(不传则使用知识库配置)") metadata_filter: Optional[Dict[str, Any]] = Field(None, description="元数据过滤条件") class RetrievalResult(BaseModel): """检索结果""" segment_id: str document_id: str document_name: str = "" knowledge_base_id: str knowledge_base_name: str = "" content: str score: float = 0.0 token_count: int = 0 page_number: Optional[int] = None metadata: Optional[Dict[str, Any]] = None keywords: Optional[List[str]] = None match_source: Optional[str] = Field(None, description="命中来源: vector/fulltext/annotation") parent_content: Optional[str] = Field(None, description="父分段内容(Small-to-Big 模式)") class RetrievalResponse(BaseModel): """检索响应""" results: List[RetrievalResult] = Field(default_factory=list) total: int = 0 query: str = "" elapsed_time: int = 0 retrieval_mode: str = "" rerank_applied: bool = False