Spaces:
Running
Running
| """ | |
| DataVision β Centralized Configuration Module | |
| Uses Pydantic Settings v2 for type-safe, environment-driven configuration. | |
| All settings are loaded from environment variables or .env files. | |
| Required variables will raise validation errors on startup if missing. | |
| """ | |
| import os | |
| from typing import Optional, Literal | |
| from pydantic_settings import BaseSettings, SettingsConfigDict | |
| from pydantic import Field | |
| class Settings(BaseSettings): | |
| """Application configuration loaded from environment variables.""" | |
| model_config = SettingsConfigDict( | |
| env_file=(".env", "../.env"), | |
| env_file_encoding="utf-8", | |
| case_sensitive=True, | |
| extra="ignore", | |
| ) | |
| # ββ Environment βββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ENVIRONMENT: Literal["development", "testing", "production"] = "development" | |
| DEBUG: bool = False | |
| APP_NAME: str = "DataVision AI" | |
| APP_VERSION: str = "1.0.0" | |
| # ββ Database ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| DATABASE_URL: str = Field( | |
| default="postgresql+asyncpg://datavision:datavision_dev@localhost:5433/datavision", | |
| description="PostgreSQL async connection URL (postgresql+asyncpg://...)" | |
| ) | |
| DB_POOL_SIZE: int = 5 | |
| DB_MAX_OVERFLOW: int = 10 | |
| DB_POOL_PRE_PING: bool = True | |
| DB_POOL_RECYCLE: int = 3600 | |
| DB_ECHO: bool = False | |
| # ββ JWT Auth ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| JWT_SECRET: str = Field( | |
| default=os.environ.get("JWT_SECRET") or os.environ.get("JWT_SECRET_KEY") or "datavision-production-jwt-secret-key-32bytes-long!", | |
| description="Secret key for signing JWT tokens. Must be kept secret." | |
| ) | |
| JWT_ALGORITHM: str = "HS256" | |
| ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 | |
| REFRESH_TOKEN_EXPIRE_DAYS: int = 7 | |
| # ββ Security ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| CORS_ORIGINS: str = "*" | |
| ALLOWED_HOSTS: str = "*" | |
| BCRYPT_ROUNDS: int = 12 | |
| # ββ Redis (Optional) ββββββββββββββββββββββββββββββββββββββββββββ | |
| REDIS_URL: Optional[str] = None | |
| # ββ LLM Providers βββββββββββββββββββββββββββββββββββββββββββββββ | |
| GROQ_API_KEY: Optional[str] = None | |
| GROQ_KEY_1: Optional[str] = None | |
| GROQ_KEY_2: Optional[str] = None | |
| GROQ_KEY_3: Optional[str] = None | |
| OPENAI_API_KEY: Optional[str] = None | |
| GOOGLE_API_KEY: Optional[str] = None | |
| ANTHROPIC_API_KEY: Optional[str] = None | |
| OPENROUTER_API_KEY: Optional[str] = None | |
| # ββ Email βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| RESEND_API_KEY: Optional[str] = None | |
| FROM_EMAIL: str = "noreply@datavision.ai" | |
| # ββ OAuth βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| GOOGLE_CLIENT_ID: Optional[str] = None | |
| GOOGLE_CLIENT_SECRET: Optional[str] = None | |
| GITHUB_CLIENT_ID: Optional[str] = None | |
| GITHUB_CLIENT_SECRET: Optional[str] = None | |
| def cors_origins_list(self) -> list[str]: | |
| """Parse CORS_ORIGINS from comma-separated string to list.""" | |
| if self.CORS_ORIGINS == "*": | |
| return ["*"] | |
| return [origin.strip() for origin in self.CORS_ORIGINS.split(",") if origin.strip()] | |
| def is_production(self) -> bool: | |
| return self.ENVIRONMENT == "production" | |
| def is_development(self) -> bool: | |
| return self.ENVIRONMENT == "development" | |
| # Singleton settings instance | |
| _settings: Optional[Settings] = None | |
| def get_settings() -> Settings: | |
| """Get or create the global Settings singleton.""" | |
| global _settings | |
| if _settings is None: | |
| _settings = Settings() | |
| return _settings | |