""" Pydantic v2 schemas for the Attention subsystem API. """ from datetime import date, datetime from typing import Any, Dict, List, Optional from pydantic import BaseModel, Field class EntityInfo(BaseModel): ticker: str canonical_name: str = Field(description="Normalized company name with legal suffixes stripped (e.g. 'Apple')") wiki_title: Optional[str] = Field(default=None, description="Matched Wikipedia article title; null if unresolved") gdelt_query: Optional[str] = Field(default=None, description="GDELT DOC API query string (quoted OR phrases)") aliases: List[str] = Field(default_factory=list, description="Intermediate forms used during name normalization") resolver_confidence: float = Field(default=0.0, description="Wikipedia match confidence [0, 1]") is_manual_override: bool = Field(default=False, description="If true, automated re-resolution is skipped") class WikiFeatures(BaseModel): views: Optional[int] = Field(default=None, description="Wikipedia pageviews on the event date") baseline_10d: Optional[float] = Field(default=None, description="Median pageviews over the prior 10 days") spike_10d: Optional[float] = Field(default=None, description="views / baseline_10d; >1 means above-average attention") zscore_20d: Optional[float] = Field(default=None, description="Z-score vs prior 20-day mean/stdev; null if stdev=0") class NewsFeatures(BaseModel): article_count_1d: int = Field(default=0, description="GDELT articles published on the event date") article_count_3d: int = Field(default=0, description="GDELT articles in the event_date ± 1 day window") unique_domains_3d: int = Field(default=0, description="Distinct publisher domains in the 3-day window") us_article_count_3d: int = Field(default=0, description="US-sourced articles in the 3-day window") gdelt_status: str = Field( default="not_collected", description=( "GDELT data availability for this event date. " "'collected' — scheduler has run; counts are accurate (0 means genuinely no articles). " "'not_collected' — scheduler has not run yet; POST /admin/collect/gdelt/{ticker}?event_date=... to populate. " "'not_available' — event date is before GDELT V2 coverage start (2017-01-01)." ), ) class EventAttentionResponse(BaseModel): ticker: str event_date: date entity: EntityInfo wiki: WikiFeatures news: NewsFeatures metadata: Dict[str, Any] = Field(default_factory=dict) class EntityResolveResponse(BaseModel): ticker: str entity: EntityInfo status: str # "resolved", "already_exists", "failed", "manual_override_skipped" message: str class CollectionStatusResponse(BaseModel): ticker: str source: str # "wiki" or "gdelt" records_collected: int date_range: Dict[str, Any] = Field(default_factory=dict) status: str