"""Source schemas.""" from __future__ import annotations from datetime import datetime from typing import Annotated from pydantic import BaseModel, ConfigDict, Field from app.models.source import SourceKind class SourceOut(BaseModel): model_config = ConfigDict(from_attributes=True) id: int name: str slug: str kind: SourceKind url: str enabled: bool region: str | None = None language_src: str | None = None priority: int fetch_interval_min: int translate_to: str last_fetched_at: datetime | None = None last_status: str | None = None consecutive_failures: int = 0 # 源级屏蔽分类标签;与 llm_settings.blocklist_tags 合并后注入 classify prompt blocklist_tags: list[str] = [] # url 字段:正常源要 HttpUrl(校验合法 URL),但 api_push 源是合成占位(类似 api-push://...) # 用 Annotated Union 区分:rss/html_list/tg_channel → HttpUrl;api_push → str # 但 SourceIn.kind 未知时(前端一次提交),无法静态区分。最简单的兼容:统一接受 str, # 入库前在 admin.create_source 里按 kind 分支校验。 # 这里改成 str(最长 2048),保留手工校验的责任。 SourceUrlStr = Annotated[str, Field(min_length=1, max_length=2048)] class SourceIn(BaseModel): name: str = Field(min_length=1, max_length=128) slug: str = Field(min_length=1, max_length=128, pattern=r"^[a-z0-9-]+$") kind: SourceKind = SourceKind.RSS # url:不再强制 HttpUrl,允许 api_push 源的合成 url(api-push://...); # rss/html_list/tg_channel 由 admin.create_source 在入库前手工校验 url: str = Field(min_length=1, max_length=2048) region: str | None = None language_src: str | None = None priority: int = Field(default=50, ge=1, le=100) fetch_interval_min: int = Field(default=60, ge=5, le=1440) translate_to: str = "zh" enabled: bool = True detail_selector: dict | None = None headers_json: dict | None = None blocklist_tags: list[str] = [] class SourceUpdate(BaseModel): name: str | None = None enabled: bool | None = None priority: int | None = Field(default=None, ge=1, le=100) fetch_interval_min: int | None = Field(default=None, ge=5, le=1440) region: str | None = None translate_to: str | None = None blocklist_tags: list[str] | None = None