from __future__ import annotations from datetime import datetime from typing import Literal, Optional from pydantic import BaseModel, Field class SearchTopic(BaseModel): # 主题是模型每次运行时使用的长期情报目标。 name: str description: str class SignalItem(BaseModel): # 模型产出的结构化情报会通过这个契约进入数据库和日报。 source_type: Literal["news", "github"] topic: str title: str summary: str source_url: str source_name: str published_at: Optional[datetime] = None importance: int = Field(ge=1, le=5) entities: list[str] = Field(default_factory=list) class AgentResult(BaseModel): # Agent结果同时承载机器可读信号和人可读日报。 title: str signals: list[SignalItem] report_markdown: str raw_response: dict = Field(default_factory=dict) class RunResponse(BaseModel): run_id: int status: str report_path: Optional[str] = None class RunRead(BaseModel): id: int status: str started_at: datetime finished_at: Optional[datetime] error: Optional[str] model_config = {"from_attributes": True} class SignalRead(BaseModel): id: int run_id: int source_type: Literal["news", "github"] topic: str title: str summary: str source_url: str source_name: str published_at: Optional[datetime] importance: int entities: list[str] created_at: datetime model_config = {"from_attributes": True} class ReportRead(BaseModel): id: int run_id: int title: str content_md: str file_path: Optional[str] created_at: datetime model_config = {"from_attributes": True} class DashboardRead(BaseModel): runs: list[RunRead] news_signals: list[SignalRead] github_signals: list[SignalRead] latest_report: Optional[ReportRead] topics: list["TopicRead"] class TopicCreate(BaseModel): name: str = Field(min_length=2, max_length=120) description: str = Field(min_length=5) enabled: bool = True class TopicRead(BaseModel): id: int name: str description: str enabled: bool model_config = {"from_attributes": True}