""" Configuration settings loaded from environment variables. Never hardcode credentials or secrets. """ import os from typing import Optional class Settings: """ Application settings with sensible defaults. Override via environment variables. """ # Storage settings SUPABASE_URL: str = os.getenv("SUPABASE_URL", "") SUPABASE_KEY: str = os.getenv("SUPABASE_KEY", "") SUPABASE_TABLE: str = os.getenv("SUPABASE_TABLE", "proofs") # Hashing settings HASH_ALGORITHM: str = os.getenv("HASH_ALGORITHM", "sha256") # Validation settings MAX_FILE_SIZE_MB: int = int(os.getenv("MAX_FILE_SIZE_MB", "10")) ALLOWED_CONTENT_TYPES: list = [ "text/plain", "application/pdf", "image/png", "image/jpeg", "application/json", ] # OCR settings OCR_ENABLED: bool = os.getenv("OCR_ENABLED", "true").lower() == "true" OCR_LANGUAGE: str = os.getenv("OCR_LANGUAGE", "eng") # Tesseract language code # AI Sidecar settings (non-authoritative) AI_ENABLED: bool = os.getenv("AI_ENABLED", "false").lower() == "true" GEMINI_API_KEY: str = os.getenv("GEMINI_API_KEY", "") GEMINI_MODEL: str = os.getenv("GEMINI_MODEL", "gemini-1.5-flash") GEMINI_TIMEOUT: int = int(os.getenv("GEMINI_TIMEOUT", "10")) # seconds @classmethod def validate(cls) -> bool: """ Check if required settings are present. Returns True if valid, False otherwise. """ if not cls.SUPABASE_URL or not cls.SUPABASE_KEY: return False return True @classmethod def validate_ai(cls) -> bool: """ Check if AI sidecar is properly configured. Returns True if AI can be enabled, False otherwise. """ if not cls.AI_ENABLED: return False if not cls.GEMINI_API_KEY: return False return True @classmethod def get_max_file_size_bytes(cls) -> int: """Get max file size in bytes.""" return cls.MAX_FILE_SIZE_MB * 1024 * 1024 # Global settings instance settings = Settings()