"""Pydantic 请求/响应模型""" from typing import Optional, List from pydantic import BaseModel, Field # ===== 统一响应壳 ===== class ApiResponse(BaseModel): """统一 API 响应壳""" code: int = 0 message: str = "ok" data: Optional[dict] = None trace_id: Optional[str] = None # ===== 检索 ===== class SearchRequest(BaseModel): """检索请求""" query: str = Field(..., min_length=1, max_length=1000, description="查询文本") category: Optional[str] = Field(None, description="法规类别过滤") province: Optional[str] = Field(None, description="省份过滤(仅地方性法规)") city: Optional[str] = Field(None, description="市级过滤(仅地方性法规)") top_k: int = Field(20, ge=1, le=100, description="返回数量") page: int = Field(1, ge=1, description="页码") page_size: int = Field(20, ge=1, le=100, description="每页数量") class SearchResultItem(BaseModel): """单条检索结果""" law_id: int law_name: str category: str chapter: Optional[str] = None clause_no: Optional[str] = None content: str score: float file_path: str province: Optional[str] = None city: Optional[str] = None publish_date: Optional[str] = None class SearchResponseData(BaseModel): """检索响应数据""" results: List[SearchResultItem] total: int page: int page_size: int # ===== RAG 问答 ===== class RagRequest(BaseModel): """RAG 问答请求""" question: str = Field(..., min_length=1, max_length=1000, description="用户问题") template: str = Field("simple", description="prompt 模板: simple/professional/compare") category: Optional[str] = Field(None, description="法规类别过滤") province: Optional[str] = Field(None, description="省份过滤") system_prompt: Optional[str] = Field(None, description="自定义系统提示词,覆盖默认") template_text: Optional[str] = Field(None, description="自定义模板正文,覆盖预设模板。需含 {context} 和 {question} 占位符") class CitationItem(BaseModel): """RAG 引用条文""" law_id: int law_name: str category: str chapter: Optional[str] = None clause_no: Optional[str] = None content: str score: float file_path: str province: Optional[str] = None # ===== 法规浏览 ===== class LawListItem(BaseModel): """法规列表项""" law_id: int name: str category: str publish_date: Optional[str] = None province: Optional[str] = None city: Optional[str] = None clause_count: int file_path: str class LawDetail(BaseModel): """法规详情""" law_id: int name: str category: str publish_date: Optional[str] = None province: Optional[str] = None city: Optional[str] = None content: str file_path: str clauses: List[dict] = [] # ===== 统计 ===== class StatsResponse(BaseModel): """索引统计""" total_laws: int total_clauses: int category_stats: dict index_built_at: Optional[str] = None faiss_dim: Optional[int] = None