from pydantic import BaseModel, HttpUrl from datetime import datetime from typing import List, Optional # --- Base Schemas --- class LocationBase(BaseModel): """ Base schema for a single geocoded location. """ entity_name: Optional[str] = None latitude: float longitude: float entity_type: Optional[str] = None geocoder_source: Optional[str] = None class Config: from_attributes = True # Allows Pydantic to read ORM objects class ArticleBase(BaseModel): """ Base schema for an article being processed. """ title: Optional[str] = None link: Optional[str] = None summary: Optional[str] = None published_date: Optional[datetime] = None source_name: Optional[str] = None class Config: from_attributes = True # --- API Response Schemas --- class ArticleInDB(ArticleBase): """ Schema for an article when retrieved from the DB (includes ID). """ id: int is_processed: bool = False processing_error: Optional[str] = None # --- Event Schema (The main output for the map) --- class EventLocation(BaseModel): """ Simplified location schema used in the final Event output. This represents the cluster point on the map. """ latitude: float longitude: float entity_name: Optional[str] = None class Config: from_attributes = True class Event(BaseModel): """ The final representation of a news event to be displayed on the map. This structure is optimized for the front-end (MapView.jsx). NOTE: In the prototype, one Article will map to one Event for simplicity. Later, this will be used for clustered news (many Articles -> one Event). """ id: int title: Optional[str] = None link: Optional[str] = None summary: Optional[str] = None published_date: Optional[datetime] = None source_name: Optional[str] = None priority: Optional[str] = "medium" # low, medium, high, critical # Sentiment Analysis fields sentiment_score: Optional[float] = 0.0 # -1 to 1 sentiment_label: Optional[str] = "neutral" # positive, neutral, negative # The primary location for the event marker location: Optional[EventLocation] = None # (Optional future feature: list of all articles in the cluster) # articles: List[ArticleBase] = [] class Config: from_attributes = True