Files
diary-news/backend/app/schemas/article.py

91 lines
2.4 KiB
Python

"""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
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