116 lines
3.6 KiB
Python
116 lines
3.6 KiB
Python
"""Configuration management with validation."""
|
|
|
|
import os
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
# Load environment variables from .env file
|
|
load_dotenv()
|
|
|
|
|
|
class ConfigurationError(Exception):
|
|
"""Raised when configuration is invalid."""
|
|
|
|
pass
|
|
|
|
|
|
@dataclass
|
|
class Settings:
|
|
"""Application settings loaded from environment variables."""
|
|
|
|
# LLM Configuration
|
|
deepseek_api_key: str = field(
|
|
default_factory=lambda: os.getenv("DEEPSEEK_API_KEY", "")
|
|
)
|
|
deepseek_base_url: str = field(
|
|
default_factory=lambda: os.getenv(
|
|
"DEEPSEEK_BASE_URL", "https://api.deepseek.com"
|
|
)
|
|
)
|
|
model: str = field(
|
|
default_factory=lambda: os.getenv("DEEPSEEK_MODEL", "deepseek-chat")
|
|
)
|
|
temperature: float = field(
|
|
default_factory=lambda: float(os.getenv("TEMPERATURE", "0.2"))
|
|
)
|
|
|
|
# TMDB Configuration
|
|
tmdb_api_key: str = field(default_factory=lambda: os.getenv("TMDB_API_KEY", ""))
|
|
tmdb_base_url: str = field(
|
|
default_factory=lambda: os.getenv(
|
|
"TMDB_BASE_URL", "https://api.themoviedb.org/3"
|
|
)
|
|
)
|
|
|
|
# Storage Configuration
|
|
memory_file: str = field(
|
|
default_factory=lambda: os.getenv("MEMORY_FILE", "memory.json")
|
|
)
|
|
|
|
# Security Configuration
|
|
max_tool_iterations: int = field(
|
|
default_factory=lambda: int(os.getenv("MAX_TOOL_ITERATIONS", "5"))
|
|
)
|
|
request_timeout: int = field(
|
|
default_factory=lambda: int(os.getenv("REQUEST_TIMEOUT", "30"))
|
|
)
|
|
|
|
# Memory Configuration
|
|
max_history_messages: int = field(
|
|
default_factory=lambda: int(os.getenv("MAX_HISTORY_MESSAGES", "10"))
|
|
)
|
|
|
|
def __post_init__(self):
|
|
"""Validate settings after initialization."""
|
|
self._validate()
|
|
|
|
def _validate(self) -> None:
|
|
"""Validate configuration values."""
|
|
# Validate temperature
|
|
if not 0.0 <= self.temperature <= 2.0:
|
|
raise ConfigurationError(
|
|
f"Temperature must be between 0.0 and 2.0, got {self.temperature}"
|
|
)
|
|
|
|
# Validate max_tool_iterations
|
|
if self.max_tool_iterations < 1 or self.max_tool_iterations > 20:
|
|
raise ConfigurationError(
|
|
f"max_tool_iterations must be between 1 and 20, got {self.max_tool_iterations}"
|
|
)
|
|
|
|
# Validate request_timeout
|
|
if self.request_timeout < 1 or self.request_timeout > 300:
|
|
raise ConfigurationError(
|
|
f"request_timeout must be between 1 and 300 seconds, got {self.request_timeout}"
|
|
)
|
|
|
|
# Validate URLs
|
|
if not self.deepseek_base_url.startswith(("http://", "https://")):
|
|
raise ConfigurationError(
|
|
f"Invalid deepseek_base_url: {self.deepseek_base_url}"
|
|
)
|
|
|
|
if not self.tmdb_base_url.startswith(("http://", "https://")):
|
|
raise ConfigurationError(f"Invalid tmdb_base_url: {self.tmdb_base_url}")
|
|
|
|
# Validate memory file path
|
|
memory_path = Path(self.memory_file)
|
|
if memory_path.exists() and not memory_path.is_file():
|
|
raise ConfigurationError(
|
|
f"memory_file exists but is not a file: {self.memory_file}"
|
|
)
|
|
|
|
def is_deepseek_configured(self) -> bool:
|
|
"""Check if DeepSeek API is properly configured."""
|
|
return bool(self.deepseek_api_key and self.deepseek_base_url)
|
|
|
|
def is_tmdb_configured(self) -> bool:
|
|
"""Check if TMDB API is properly configured."""
|
|
return bool(self.tmdb_api_key and self.tmdb_base_url)
|
|
|
|
|
|
# Global settings instance
|
|
settings = Settings()
|