"""Application configuration loaded from environment variables""" from pydantic_settings import BaseSettings from pydantic import field_validator from functools import lru_cache from typing import List import logging class Settings(BaseSettings): """Application settings""" # Database DATABASE_URL: str # Security FERNET_KEY: str # AD API AD_API_URL: str AD_API_TIMEOUT_SECONDS: int = 10 # AD API request timeout # Session Settings SESSION_INACTIVITY_DAYS: int = 3 TOKEN_REFRESH_THRESHOLD_MINUTES: int = 5 MAX_REFRESH_ATTEMPTS: int = 3 # Server HOST: str = "0.0.0.0" PORT: int = 8000 DEBUG: bool = False # Default to False for security LOG_LEVEL: str = "INFO" # DEBUG, INFO, WARNING, ERROR # CORS Configuration CORS_ORIGINS: str = "http://localhost:3000" # Comma-separated list of allowed origins # System Admin SYSTEM_ADMIN_EMAIL: str = "" # System administrator email with special permissions # Realtime Messaging Settings MESSAGE_EDIT_TIME_LIMIT_MINUTES: int = 15 # Time limit for editing messages TYPING_TIMEOUT_SECONDS: int = 3 # Typing indicator timeout # File Upload Size Limits (in MB) IMAGE_MAX_SIZE_MB: int = 10 DOCUMENT_MAX_SIZE_MB: int = 20 LOG_MAX_SIZE_MB: int = 5 # MinIO Object Storage MINIO_ENDPOINT: str = "localhost:9000" MINIO_ACCESS_KEY: str = "minioadmin" MINIO_SECRET_KEY: str = "minioadmin" MINIO_BUCKET: str = "task-reporter-files" MINIO_SECURE: bool = False # Use HTTPS # DIFY AI Service DIFY_BASE_URL: str = "https://dify.theaken.com/v1" DIFY_API_KEY: str = "" # Required for report generation DIFY_TIMEOUT_SECONDS: int = 120 # AI generation can take time # Report Generation REPORT_MAX_MESSAGES: int = 200 # Summarize if exceeded REPORT_STORAGE_PATH: str = "reports" # MinIO path prefix for reports @field_validator("LOG_LEVEL") @classmethod def validate_log_level(cls, v: str) -> str: """Validate log level""" valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] v_upper = v.upper() if v_upper not in valid_levels: raise ValueError(f"LOG_LEVEL must be one of {valid_levels}") return v_upper def get_cors_origins(self) -> List[str]: """Parse CORS_ORIGINS into a list""" if not self.CORS_ORIGINS: return [] return [origin.strip() for origin in self.CORS_ORIGINS.split(",") if origin.strip()] def get_image_max_size_bytes(self) -> int: """Get image max size in bytes""" return self.IMAGE_MAX_SIZE_MB * 1024 * 1024 def get_document_max_size_bytes(self) -> int: """Get document max size in bytes""" return self.DOCUMENT_MAX_SIZE_MB * 1024 * 1024 def get_log_max_size_bytes(self) -> int: """Get log file max size in bytes""" return self.LOG_MAX_SIZE_MB * 1024 * 1024 def configure_logging(self) -> None: """Configure application logging based on LOG_LEVEL""" logging.basicConfig( level=getattr(logging, self.LOG_LEVEL), format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" ) class Config: env_file = ".env" case_sensitive = True @lru_cache() def get_settings() -> Settings: """Get cached settings instance""" return Settings()