import os from typing import List, ClassVar from pydantic_settings import BaseSettings from pydantic import AnyHttpUrl, field_validator class Settings(BaseSettings): # Project settings PROJECT_NAME: str = "SEREACT - Secure Image Management API" API_V1_STR: str = "/api/v1" # Environment ENVIRONMENT: str = "development" # CORS settings CORS_ORIGINS: List[str] = ["*"] CORS_METHODS: List[str] = ["GET", "POST", "PUT", "DELETE", "OPTIONS"] CORS_HEADERS: List[str] = ["Content-Type", "Authorization", "X-Requested-With"] CORS_EXPOSE_HEADERS: List[str] = ["Content-Length", "Content-Range"] CORS_MAX_AGE: int = 3600 @field_validator("CORS_ORIGINS", mode="before") def assemble_cors_origins(cls, v): # Read from environment variable first env_origins = os.getenv("CORS_ORIGINS") if env_origins: if env_origins.startswith("[") and env_origins.endswith("]"): # Handle list format like "['*']" import ast try: return ast.literal_eval(env_origins) except: pass # Handle comma-separated format return [i.strip().strip("'\"") for i in env_origins.split(",")] # Fallback to default if no env var if isinstance(v, str) and not v.startswith("["): return [i.strip() for i in v.split(",")] elif not v: # If empty list, use defaults return ["http://localhost:3000", "http://localhost:8000", "http://127.0.0.1:8000", "http://127.0.0.1:3000", "https://localhost:3000", "https://localhost:8000"] return v @field_validator("CORS_METHODS", mode="before") def assemble_cors_methods(cls, v): env_methods = os.getenv("CORS_METHODS") if env_methods: return [i.strip() for i in env_methods.split(",")] return v or ["GET", "POST", "PUT", "DELETE", "OPTIONS"] @field_validator("CORS_HEADERS", mode="before") def assemble_cors_headers(cls, v): env_headers = os.getenv("CORS_HEADERS") if env_headers: return [i.strip() for i in env_headers.split(",")] return v or ["Content-Type", "Authorization", "X-Requested-With"] @field_validator("CORS_EXPOSE_HEADERS", mode="before") def assemble_cors_expose_headers(cls, v): env_expose = os.getenv("CORS_EXPOSE_HEADERS") if env_expose: return [i.strip() for i in env_expose.split(",")] return v or ["Content-Length", "Content-Range"] @field_validator("CORS_MAX_AGE", mode="before") def assemble_cors_max_age(cls, v): env_max_age = os.getenv("CORS_MAX_AGE") if env_max_age: return int(env_max_age) return v or 3600 # Firestore settings FIRESTORE_PROJECT_ID: str = os.getenv("FIRESTORE_PROJECT_ID", "") FIRESTORE_DATABASE_NAME: str = os.getenv("FIRESTORE_DATABASE_NAME", "sereact-db") FIRESTORE_CREDENTIALS_FILE: str = os.getenv("FIRESTORE_CREDENTIALS_FILE", "firestore-credentials.json") # Google Cloud Storage settings GCS_BUCKET_NAME: str = os.getenv("GCS_BUCKET_NAME", "image-mgmt-bucket") GCS_CREDENTIALS_FILE: str = os.getenv("GCS_CREDENTIALS_FILE", "credentials.json") # Google Pub/Sub settings PUBSUB_TOPIC: str = os.getenv("PUBSUB_TOPIC", "image-processing-topic") PUBSUB_SUBSCRIPTION: str = os.getenv("PUBSUB_SUBSCRIPTION", "image-processing-subscription") # Google Cloud Vision API VISION_API_ENABLED: bool = os.getenv("VISION_API_ENABLED", "true").lower() == "true" # Security settings API_KEY_SECRET: str = os.getenv("API_KEY_SECRET", "super-secret-key-for-development-only") API_KEY_EXPIRY_DAYS: int = int(os.getenv("API_KEY_EXPIRY_DAYS", "365")) # Vector Database settings (for image embeddings) VECTOR_DB_API_KEY: str = os.getenv("VECTOR_DB_API_KEY", "") VECTOR_DB_ENVIRONMENT: str = os.getenv("VECTOR_DB_ENVIRONMENT", "") VECTOR_DB_INDEX_NAME: str = os.getenv("VECTOR_DB_INDEX_NAME", "image-embeddings") # Rate limiting RATE_LIMIT_PER_MINUTE: int = int(os.getenv("RATE_LIMIT_PER_MINUTE", "100")) # Qdrant settings QDRANT_HOST: str = os.getenv("QDRANT_HOST", "localhost") QDRANT_PORT: int = int(os.getenv("QDRANT_PORT", "6333")) QDRANT_API_KEY: str = os.getenv("QDRANT_API_KEY", "") QDRANT_COLLECTION: str = os.getenv("QDRANT_COLLECTION", "image_vectors") QDRANT_HTTPS: bool = os.getenv("QDRANT_HTTPS", "").lower() in ("true", "1", "yes") QDRANT_PREFER_GRPC: bool = os.getenv("QDRANT_PREFER_GRPC", "false").lower() in ("true", "1", "yes") # Logging LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO") model_config: ClassVar[dict] = { "case_sensitive": True, "env_file": ".env" } settings = Settings()