| | """
|
| | Application configuration using Pydantic BaseSettings.
|
| | Supports environment-based configuration with validation.
|
| | """
|
| |
|
| | import os
|
| | from typing import Optional, List, Union
|
| | from pydantic import Field, field_validator
|
| | from pydantic_settings import BaseSettings
|
| |
|
| |
|
| | class Settings(BaseSettings):
|
| | """Application settings with environment variable support."""
|
| |
|
| |
|
| | app_name: str = Field(default="FastAPI Video Backend", env="APP_NAME")
|
| | app_version: str = Field(default="0.1.0", env="APP_VERSION")
|
| | debug: bool = Field(default=False, env="DEBUG")
|
| | environment: str = Field(default="development", env="ENVIRONMENT")
|
| |
|
| |
|
| | host: str = Field(default="0.0.0.0", env="HOST")
|
| | port: int = Field(default=8000, env="PORT")
|
| | reload: bool = Field(default=True, env="RELOAD")
|
| |
|
| |
|
| | api_v1_prefix: str = Field(default="/api/v1", env="API_V1_PREFIX")
|
| | docs_url: str = Field(default="/docs", env="DOCS_URL")
|
| | redoc_url: str = Field(default="/redoc", env="REDOC_URL")
|
| | openapi_url: str = Field(default="/openapi.json", env="OPENAPI_URL")
|
| |
|
| |
|
| | allowed_origins: str = Field(
|
| | default="http://localhost:3000,http://localhost:8080",
|
| | env="ALLOWED_ORIGINS"
|
| | )
|
| | allowed_methods: str = Field(
|
| | default="GET,POST,PUT,DELETE,OPTIONS",
|
| | env="ALLOWED_METHODS"
|
| | )
|
| | allowed_headers: str = Field(
|
| | default="*",
|
| | env="ALLOWED_HEADERS"
|
| | )
|
| |
|
| |
|
| | redis_url: str = Field(default="redis://localhost:6379/0", env="REDIS_URL")
|
| | redis_host: str = Field(default="localhost", env="REDIS_HOST")
|
| | redis_port: int = Field(default=6379, env="REDIS_PORT")
|
| | redis_db: int = Field(default=0, env="REDIS_DB")
|
| | redis_password: Optional[str] = Field(default=None, env="REDIS_PASSWORD")
|
| | redis_max_connections: int = Field(default=20, env="REDIS_MAX_CONNECTIONS")
|
| | redis_socket_timeout: int = Field(default=5, env="REDIS_SOCKET_TIMEOUT")
|
| | redis_socket_connect_timeout: int = Field(default=5, env="REDIS_SOCKET_CONNECT_TIMEOUT")
|
| |
|
| |
|
| | clerk_secret_key: str = Field(default="", env="CLERK_SECRET_KEY")
|
| | clerk_publishable_key: str = Field(default="", env="CLERK_PUBLISHABLE_KEY")
|
| | clerk_webhook_secret: Optional[str] = Field(default=None, env="CLERK_WEBHOOK_SECRET")
|
| | clerk_jwt_verification: bool = Field(default=True, env="CLERK_JWT_VERIFICATION")
|
| |
|
| |
|
| | job_queue_name: str = Field(default="video_generation_queue", env="JOB_QUEUE_NAME")
|
| | job_queue_max_size: int = Field(default=1000, env="JOB_QUEUE_MAX_SIZE")
|
| | job_default_timeout: int = Field(default=3600, env="JOB_DEFAULT_TIMEOUT")
|
| | job_retry_attempts: int = Field(default=3, env="JOB_RETRY_ATTEMPTS")
|
| |
|
| |
|
| | upload_dir: str = Field(default="./uploads", env="UPLOAD_DIR")
|
| | file_storage_path: str = Field(default="./storage", env="FILE_STORAGE_PATH")
|
| | max_file_size: int = Field(default=100 * 1024 * 1024, env="MAX_FILE_SIZE")
|
| | allowed_file_types: List[str] = Field(
|
| | default=["image/jpeg", "image/png", "image/gif", "video/mp4", "text/plain"],
|
| | env="ALLOWED_FILE_TYPES"
|
| | )
|
| |
|
| |
|
| | rate_limit_requests: int = Field(default=100, env="RATE_LIMIT_REQUESTS")
|
| | rate_limit_window: int = Field(default=60, env="RATE_LIMIT_WINDOW")
|
| | rate_limit_per_user: int = Field(default=50, env="RATE_LIMIT_PER_USER")
|
| |
|
| |
|
| | log_level: str = Field(default="INFO", env="LOG_LEVEL")
|
| | log_format: str = Field(default="json", env="LOG_FORMAT")
|
| | log_file: Optional[str] = Field(default=None, env="LOG_FILE")
|
| | log_rotation: str = Field(default="1 day", env="LOG_ROTATION")
|
| | log_retention: str = Field(default="30 days", env="LOG_RETENTION")
|
| |
|
| |
|
| | secret_key: str = Field(default="dev-secret-key-change-in-production", env="SECRET_KEY")
|
| | access_token_expire_minutes: int = Field(default=30, env="ACCESS_TOKEN_EXPIRE_MINUTES")
|
| | refresh_token_expire_days: int = Field(default=7, env="REFRESH_TOKEN_EXPIRE_DAYS")
|
| |
|
| |
|
| | video_output_dir: str = Field(default="./videos", env="VIDEO_OUTPUT_DIR")
|
| | video_quality_default: str = Field(default="medium", env="VIDEO_QUALITY_DEFAULT")
|
| | video_max_duration: int = Field(default=600, env="VIDEO_MAX_DURATION")
|
| |
|
| |
|
| | health_check_interval: int = Field(default=30, env="HEALTH_CHECK_INTERVAL")
|
| | health_check_timeout: int = Field(default=5, env="HEALTH_CHECK_TIMEOUT")
|
| |
|
| | def get_allowed_origins(self) -> List[str]:
|
| | """Parse CORS origins from string."""
|
| | return [origin.strip() for origin in self.allowed_origins.split(",")]
|
| |
|
| | def get_allowed_methods(self) -> List[str]:
|
| | """Parse CORS methods from string."""
|
| | return [method.strip() for method in self.allowed_methods.split(",")]
|
| |
|
| | def get_allowed_headers(self) -> List[str]:
|
| | """Parse CORS headers from string."""
|
| | return [header.strip() for header in self.allowed_headers.split(",")]
|
| |
|
| | def get_allowed_file_types(self) -> List[str]:
|
| | """Get allowed file types list."""
|
| | return self.allowed_file_types
|
| |
|
| | @field_validator("allowed_file_types", mode="before")
|
| | @classmethod
|
| | def parse_file_types(cls, v):
|
| | """Parse allowed file types from string or list."""
|
| | if isinstance(v, str) and not v.startswith('['):
|
| |
|
| | return [file_type.strip() for file_type in v.split(",")]
|
| | return v
|
| |
|
| | @field_validator("log_level")
|
| | @classmethod
|
| | def validate_log_level(cls, v):
|
| | """Validate log level."""
|
| | valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
| | if v.upper() not in valid_levels:
|
| | raise ValueError(f"Log level must be one of: {valid_levels}")
|
| | return v.upper()
|
| |
|
| | @field_validator("log_format")
|
| | @classmethod
|
| | def validate_log_format(cls, v):
|
| | """Validate log format."""
|
| | valid_formats = ["json", "text"]
|
| | if v.lower() not in valid_formats:
|
| | raise ValueError(f"Log format must be one of: {valid_formats}")
|
| | return v.lower()
|
| |
|
| | @field_validator("environment")
|
| | @classmethod
|
| | def validate_environment(cls, v):
|
| | """Validate environment."""
|
| | valid_environments = ["development", "staging", "production", "testing"]
|
| | if v.lower() not in valid_environments:
|
| | raise ValueError(f"Environment must be one of: {valid_environments}")
|
| | return v.lower()
|
| |
|
| | @field_validator("video_quality_default")
|
| | @classmethod
|
| | def validate_video_quality(cls, v):
|
| | """Validate video quality."""
|
| | valid_qualities = ["low", "medium", "high", "ultra"]
|
| | if v.lower() not in valid_qualities:
|
| | raise ValueError(f"Video quality must be one of: {valid_qualities}")
|
| | return v.lower()
|
| |
|
| | @property
|
| | def is_development(self) -> bool:
|
| | """Check if running in development mode."""
|
| | return self.environment == "development"
|
| |
|
| | @property
|
| | def is_production(self) -> bool:
|
| | """Check if running in production mode."""
|
| | return self.environment == "production"
|
| |
|
| | @property
|
| | def is_testing(self) -> bool:
|
| | """Check if running in testing mode."""
|
| | return self.environment == "testing"
|
| |
|
| | def get_redis_url(self) -> str:
|
| | """Get Redis URL with proper formatting."""
|
| | if self.redis_url:
|
| | return self.redis_url
|
| |
|
| | auth_part = f":{self.redis_password}@" if self.redis_password else ""
|
| | return f"redis://{auth_part}{self.redis_host}:{self.redis_port}/{self.redis_db}"
|
| |
|
| | model_config = {
|
| | "env_file": ".env",
|
| | "env_file_encoding": "utf-8",
|
| | "case_sensitive": False,
|
| | "extra": "ignore",
|
| | }
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| | def get_settings() -> Settings:
|
| | """Get application settings instance."""
|
| | return Settings() |