"""Shared data models for DenseFeed pipeline.""" from __future__ import annotations from typing import Literal from pydantic import BaseModel class Item(BaseModel): """Uniform output from all fetchers.""" source: str title: str url: str summary: str = "" published_ts: float = 0.0 score: float | None = None reason: str | None = None class Article(BaseModel): """Extracted article content.""" url: str title: str body: str author: str = "" published: str = "" class ScriptLine(BaseModel): """A single line of podcast dialogue.""" speaker: Literal["A", "B"] text: str emotion: str = "neutral" class Script(BaseModel): """Full podcast script.""" date: str title: str lines: list[ScriptLine] class StageResult(BaseModel): """Metadata for a completed pipeline stage.""" stage: int name: str success: bool duration_s: float = 0.0 output_path: str = "" error: str | None = None items_in: int = 0 items_out: int = 0 class PipelineRun(BaseModel): """Full pipeline run state.""" date: str register_dir: str = "" run_id: str = "" # e.g. "2026-06-06_001" user_id: str = "" # HF username (empty for CLI) stages: list[StageResult] = [] started_at: str = "" finished_at: str = "" config_json: dict = {} # snapshot of effective config for reproducibility class UserPreferences(BaseModel): """Per-user preferences stored in DuckDB. This model is the single source of truth for preference defaults and schema. DuckDBBackend.DEFAULT_PREFS is derived from this model's defaults. """ user_id: str = "" topics: list[str] = [] excluded_sources: list[str] = [] speaker_a_voice: str = "en-US-AndrewMultilingualNeural" speaker_b_voice: str = "en-US-AvaMultilingualNeural" speaker_a_rate: str = "+10%" speaker_b_rate: str = "+10%" cross_speaker_pause_ms: int = 550 same_speaker_pause_ms: int = 250 min_relevance: int = 6 top_n_items: int = 12 hf_dataset_repo: str = "" hf_audio_repo: str = ""