A community based topic aggregation platform built on atproto
at main 1.9 kB view raw
1""" 2Data models for Kagi News RSS aggregator. 3""" 4from dataclasses import dataclass, field 5from datetime import datetime 6from typing import List, Optional 7 8 9@dataclass 10class Source: 11 """A news source citation.""" 12 title: str 13 url: str 14 domain: str 15 16 17@dataclass 18class Perspective: 19 """A perspective from a particular actor/stakeholder.""" 20 actor: str 21 description: str 22 source_url: str 23 source_name: str = "" # Name of the source (e.g., "The Straits Times") 24 25 26@dataclass 27class Quote: 28 """A notable quote from the story.""" 29 text: str 30 attribution: str 31 32 33@dataclass 34class KagiStory: 35 """ 36 Structured representation of a Kagi News story. 37 38 Parsed from RSS feed item with HTML description. 39 """ 40 # RSS metadata 41 title: str 42 link: str # Kagi story permalink 43 guid: str 44 pub_date: datetime 45 categories: List[str] = field(default_factory=list) 46 47 # Parsed from HTML description 48 summary: str = "" 49 highlights: List[str] = field(default_factory=list) 50 perspectives: List[Perspective] = field(default_factory=list) 51 quote: Optional[Quote] = None 52 sources: List[Source] = field(default_factory=list) 53 image_url: Optional[str] = None 54 image_alt: Optional[str] = None 55 56 def __post_init__(self): 57 """Validate required fields.""" 58 if not self.title: 59 raise ValueError("title is required") 60 if not self.link: 61 raise ValueError("link is required") 62 if not self.guid: 63 raise ValueError("guid is required") 64 65 66@dataclass 67class FeedConfig: 68 """Configuration for a single RSS feed.""" 69 name: str 70 url: str 71 community_handle: str 72 enabled: bool = True 73 74 75@dataclass 76class AggregatorConfig: 77 """Full aggregator configuration.""" 78 coves_api_url: str 79 feeds: List[FeedConfig] 80 log_level: str = "info"