"""Article schemas.""" from __future__ import annotations from datetime import datetime from pydantic import BaseModel, ConfigDict, Field class SourceBrief(BaseModel): model_config = ConfigDict(from_attributes=True) id: int name: str slug: str region: str | None = None class ArticleListItem(BaseModel): """列表项:精简字段(首页只露钩子,详细阅读进详情页)。""" model_config = ConfigDict(from_attributes=True) id: int source: SourceBrief title: str title_zh: str | None = None summary_zh: str | None = None lang_src: str | None = None translation_status: str category: str | None = None published_at: datetime | None = None fetched_at: datetime image_url: str | None = None # === 列表预览钩子:点击进详情前的"诱导点" === commentary: str | None = None # LLM 点评(列表里截断显示) commentary_status: str | None = None # ok/failed/pending/n/a image_ai_url: str | None = None # AI 插图(列表里缩略图) is_starred: bool = False class ArticleDetail(BaseModel): model_config = ConfigDict(from_attributes=True) id: int source: SourceBrief url: str title: str body_html: str | None = None body_text: str title_zh: str | None = None body_zh_html: str | None = None body_zh_text: str | None = None body_zh_formatted: str | None = None # LLM 排版后 summary_zh: str | None = None lang_src: str | None = None author: str | None = None image_url: str | None = None image_ai_url: str | None = None # LLM 生成的插图 translation_status: str translation_engine: str | None = None translated_at: datetime | None = None # === LLM 增强状态 + 内容 === category: str | None = None format_status: str | None = None # pending/ok/failed/n/a classify_status: str | None = None image_ai_status: str | None = None commentary_status: str | None = None commentary: str | None = None entities: dict | None = None sentiment: float | None = None duplicate_of: int | None = None published_at: datetime | None = None fetched_at: datetime is_starred: bool = False class ArticleListResponse(BaseModel): items: list[ArticleListItem] next_cursor: str | None = None total: int | None = None class ArticleQuery(BaseModel): """用作 ?query= 解析参考(实际 FastAPI 直接用 Query)。""" since: datetime | None = None until: datetime | None = None source: str | None = None # 逗号分隔 slug category: str | None = None q: str | None = None lang: str = Field(default="both", pattern=r"^(src|zh|both)$") limit: int = Field(default=50, ge=1, le=200) cursor: str | None = None starred_only: bool = False