""" Voice Service Configuration Environment-based configuration with Pydantic Settings DSGVO-konform: Keine Audio-Persistenz, nur transiente Verarbeitung """ from functools import lru_cache from typing import Optional, List from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): """Application settings loaded from environment variables.""" model_config = SettingsConfigDict( env_file=".env", env_file_encoding="utf-8", case_sensitive=False, extra="ignore", # Ignore unknown environment variables from docker-compose ) # Service Config port: int = 8091 environment: str = "development" debug: bool = False # JWT Authentication (load from Vault or environment, test default for CI) jwt_secret: str = "test-secret-for-ci-only-do-not-use-in-production" jwt_algorithm: str = "HS256" jwt_expiration_hours: int = 24 # PostgreSQL (load from Vault or environment, test default for CI) database_url: str = "postgresql://test:test@localhost:5432/test" # Valkey (Redis-fork) Session Cache valkey_url: str = "redis://valkey:6379/2" session_ttl_hours: int = 24 task_ttl_hours: int = 168 # 7 days for pending tasks # PersonaPlex Configuration (Production GPU) personaplex_enabled: bool = False personaplex_ws_url: str = "ws://host.docker.internal:8998" personaplex_model: str = "personaplex-7b" personaplex_timeout: int = 30 # Task Orchestrator orchestrator_enabled: bool = True orchestrator_max_concurrent_tasks: int = 10 # Fallback LLM (Ollama for Development) fallback_llm_provider: str = "ollama" # "ollama" or "none" ollama_base_url: str = "http://host.docker.internal:11434" ollama_voice_model: str = "qwen2.5:32b" ollama_timeout: int = 120 # Klausur Service Integration klausur_service_url: str = "http://klausur-service:8086" # Audio Configuration audio_sample_rate: int = 24000 # 24kHz for Mimi codec audio_frame_size_ms: int = 80 # 80ms frames audio_persistence: bool = False # NEVER persist audio # Encryption Configuration encryption_enabled: bool = True namespace_key_algorithm: str = "AES-256-GCM" # TTL Configuration (DSGVO Data Minimization) transcript_ttl_days: int = 7 task_state_ttl_days: int = 30 audit_log_ttl_days: int = 90 # Rate Limiting max_sessions_per_user: int = 5 max_requests_per_minute: int = 60 # CORS (for frontend access) cors_origins: List[str] = [ "http://localhost:3000", "http://localhost:3001", "http://localhost:8091", "http://macmini:3000", "http://macmini:3001", "https://localhost", "https://localhost:3000", "https://localhost:3001", "https://localhost:8091", "https://macmini", "https://macmini:3000", "https://macmini:3001", "https://macmini:8091", ] @property def is_development(self) -> bool: """Check if running in development mode.""" return self.environment == "development" @property def audio_frame_samples(self) -> int: """Calculate samples per frame.""" return int(self.audio_sample_rate * self.audio_frame_size_ms / 1000) @property def use_personaplex(self) -> bool: """Check if PersonaPlex should be used (production only).""" return self.personaplex_enabled and not self.is_development @lru_cache def get_settings() -> Settings: """Get cached settings instance.""" return Settings() # Export settings instance for convenience settings = get_settings()