157 lines
3.9 KiB
Python
157 lines
3.9 KiB
Python
"""Configuration management for News Agent"""
|
|
|
|
import yaml
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from pydantic import BaseModel, Field, HttpUrl
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class RSSSource(BaseModel):
|
|
"""RSS feed source configuration"""
|
|
|
|
name: str
|
|
url: HttpUrl
|
|
category: str
|
|
|
|
|
|
class AIFilteringConfig(BaseModel):
|
|
"""AI filtering configuration"""
|
|
|
|
enabled: bool = True
|
|
min_score: float = Field(ge=0, le=10, default=6.5)
|
|
max_articles: int = Field(ge=1, default=15)
|
|
|
|
|
|
class AIConfig(BaseModel):
|
|
"""AI processing configuration"""
|
|
|
|
provider: str = "openrouter"
|
|
base_url: str = "https://openrouter.ai/api/v1"
|
|
model: str = "google/gemini-flash-1.5"
|
|
filtering: AIFilteringConfig
|
|
interests: list[str]
|
|
|
|
|
|
class SMTPConfig(BaseModel):
|
|
"""SMTP server configuration"""
|
|
|
|
host: str = "localhost"
|
|
port: int = 25
|
|
use_tls: bool = False
|
|
use_ssl: bool = False
|
|
username: str | None = None
|
|
password: str | None = None
|
|
|
|
|
|
class EmailConfig(BaseModel):
|
|
"""Email configuration"""
|
|
|
|
to: str
|
|
from_: str = Field(alias="from")
|
|
from_name: str = "Daily Tech News Agent"
|
|
subject_template: str = "Tech News Digest - {date}"
|
|
smtp: SMTPConfig
|
|
|
|
|
|
class ScheduleConfig(BaseModel):
|
|
"""Schedule configuration"""
|
|
|
|
time: str = "07:00"
|
|
timezone: str = "Europe/Oslo"
|
|
|
|
|
|
class DatabaseConfig(BaseModel):
|
|
"""Database configuration"""
|
|
|
|
path: str = "data/articles.db"
|
|
retention_days: int = 30
|
|
|
|
|
|
class LoggingConfig(BaseModel):
|
|
"""Logging configuration"""
|
|
|
|
level: str = "INFO"
|
|
file: str = "data/logs/news-agent.log"
|
|
max_bytes: int = 10485760
|
|
backup_count: int = 5
|
|
|
|
|
|
class EnvSettings(BaseSettings):
|
|
"""Environment variable settings"""
|
|
|
|
model_config = SettingsConfigDict(env_file=".env", case_sensitive=False, extra="ignore")
|
|
|
|
openrouter_api_key: str
|
|
openrouter_site_url: str | None = None
|
|
openrouter_site_name: str | None = None
|
|
smtp_username: str | None = None
|
|
smtp_password: str | None = None
|
|
error_notification_email: str | None = None
|
|
|
|
|
|
class Config:
|
|
"""Main configuration manager"""
|
|
|
|
def __init__(self, config_path: str | Path = "config.yaml"):
|
|
"""Load configuration from YAML file and environment variables"""
|
|
self.config_path = Path(config_path)
|
|
|
|
# Load YAML configuration
|
|
with open(self.config_path) as f:
|
|
self._config: dict[str, Any] = yaml.safe_load(f)
|
|
|
|
# Load environment variables
|
|
self.env = EnvSettings()
|
|
|
|
@property
|
|
def rss_sources(self) -> list[RSSSource]:
|
|
"""Get all RSS sources"""
|
|
return [RSSSource(**src) for src in self._config["sources"]["rss"]]
|
|
|
|
@property
|
|
def ai(self) -> AIConfig:
|
|
"""Get AI configuration"""
|
|
return AIConfig(**self._config["ai"])
|
|
|
|
@property
|
|
def email(self) -> EmailConfig:
|
|
"""Get email configuration"""
|
|
email_config = self._config["email"].copy()
|
|
|
|
# Merge SMTP credentials from environment variables
|
|
if self.env.smtp_username:
|
|
email_config["smtp"]["username"] = self.env.smtp_username
|
|
if self.env.smtp_password:
|
|
email_config["smtp"]["password"] = self.env.smtp_password
|
|
|
|
return EmailConfig(**email_config)
|
|
|
|
@property
|
|
def schedule(self) -> ScheduleConfig:
|
|
"""Get schedule configuration"""
|
|
return ScheduleConfig(**self._config["schedule"])
|
|
|
|
@property
|
|
def database(self) -> DatabaseConfig:
|
|
"""Get database configuration"""
|
|
return DatabaseConfig(**self._config["database"])
|
|
|
|
@property
|
|
def logging(self) -> LoggingConfig:
|
|
"""Get logging configuration"""
|
|
return LoggingConfig(**self._config["logging"])
|
|
|
|
|
|
# Global config instance (lazy loaded)
|
|
_config: Config | None = None
|
|
|
|
|
|
def get_config() -> Config:
|
|
"""Get or create global config instance"""
|
|
global _config
|
|
if _config is None:
|
|
_config = Config()
|
|
return _config
|