first commit
This commit is contained in:
156
src/config.py
Normal file
156
src/config.py
Normal file
@@ -0,0 +1,156 @@
|
||||
"""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
|
||||
Reference in New Issue
Block a user