from pydantic_settings import BaseSettings, SettingsConfigDict class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") APP_NAME: str = "VideoGen API" APP_VERSION: str = "1.0.0" DEBUG: bool = False SECRET_KEY: str = "change-me" DATABASE_URL: str = "sqlite+aiosqlite:///./videogen.db" REDIS_URL: str = "" # Leave empty to disable Redis (rate limiting, captcha) JWT_ALGORITHM: str = "HS256" JWT_EXPIRE_MINUTES: int = 1440 JWT_EXPIRE_REMEMBER_MINUTES: int = 10080 SEEDANCE_API_KEY: str = "" SEEDANCE_API_BASE: str = "https://ark.cn-beijing.volces.com/api/v3" SEEDANCE_CALLBACK_URL: str = "" LLM_API_BASE: str = "https://api.openai.com/v1" LLM_API_KEY: str = "" LLM_MODEL: str = "gpt-4o" LLM_MOCK: bool = True ENCRYPTION_KEY: str = "changeme-32bytes-base64-key-here!!" # SMS settings # 兼容旧字段:SMS_API_URL/SMS_API_KEY/SMS_SIGN_NAME/SMS_TEMPLATE_CODE 保留, # 新接入默认使用火山引擎短信 SDK。 SMS_API_URL: str = "" SMS_API_KEY: str = "" SMS_SIGN_NAME: str = "VideoGen" SMS_TEMPLATE_CODE: str = "SMS_001" SMS_MOCK: bool = True # 火山引擎短信配置。 # SmsAccount=消息组ID,TemplateID=模板ID,Sign=短信签名内容。 VOLC_SMS_ACCESS_KEY_ID: str = "" VOLC_SMS_SECRET_ACCESS_KEY: str = "" VOLC_SMS_ACCOUNT: str = "" VOLC_SMS_TEMPLATE_ID: str = "" VOLC_SMS_SIGN: str = "" SMS_CODE_LENGTH: int = 4 SMS_CODE_TTL_SECONDS: int = 300 SMS_SEND_INTERVAL_SECONDS: int = 60 SMS_DAILY_LIMIT: int = 20 # Payment settings WECHAT_MCH_ID: str = "" WECHAT_API_KEY: str = "" WECHAT_CERT_PATH: str = "" ALIPAY_APP_ID: str = "" ALIPAY_PRIVATE_KEY: str = "" ALIPAY_PUBLIC_KEY: str = "" PAYMENT_MOCK: bool = True STORAGE_TYPE: str = "local" STORAGE_LOCAL_PATH: str = "./storage/generate/videos" STORAGE_IMAGE_LOCAL_PATH: str = "./storage/generate/images" STORAGE_VIDEO_COVER_LOCAL_PATH: str = "./storage/generate/covers" UPLOAD_LOCAL_PATH: str = "./storage/uploads" # 本地视频封面截帧配置。 # 说明: # - FFMPEG_BIN 为空时自动从系统 PATH 查找 ffmpeg / ffmpeg.exe。 # - VIDEO_COVER_TIMEOUT_SECONDS 必须较短,避免 ffmpeg 异常卡住下载 worker。 FFMPEG_BIN: str = "" VIDEO_COVER_SEEK_TIME: str = "00:00:01" VIDEO_COVER_FALLBACK_SEEK_TIME: str = "00:00:00" VIDEO_COVER_WIDTH: int = 720 VIDEO_COVER_TIMEOUT_SECONDS: int = 15 VIDEO_COVER_FORMAT: str = "jpg" CAPTCHA_ENABLED: bool = True BASE_URL: str = "http://ceshi.apiforeign.minzhong.cn" CORS_ORIGINS: list[str] = ["*"] RATE_LIMIT_ENABLED: bool = True # ChatAPI async generation pipeline settings CELERY_BROKER_URL: str = "" CELERY_RESULT_BACKEND: str = "" CHATAPI_REQUEST_TIMEOUT_SECONDS: int = 120 CHATAPI_VIDEO_FPS: float = 0.5 CHATAPI_ASYNC_MAX_RETRIES: int = 3 CHATAPI_ASYNC_RETRY_BACKOFF_SECONDS: int = 30 CHATAPI_ASYNC_POLL_INTERVAL_SECONDS: int = 30 CHATAPI_ASYNC_IMAGE_DEADLINE_MINUTES: int = 10 CHATAPI_ASYNC_VIDEO_DEADLINE_MINUTES: int = 30 # Distributed provider concurrency limits. 0 means disabled/no-op. ARK_CHAT_PROMPT_MAX_CONCURRENCY: int = 20 ARK_IMAGE_CREATE_MAX_CONCURRENCY: int = 10 ARK_VIDEO_CREATE_MAX_CONCURRENCY: int = 10 ARK_IMAGE_POLL_MAX_CONCURRENCY: int = 50 ARK_VIDEO_POLL_MAX_CONCURRENCY: int = 50 RESULT_DOWNLOAD_MAX_CONCURRENCY: int = 10 PROVIDER_LIMIT_WAIT_TIMEOUT_SECONDS: float = 30.0 PROVIDER_LIMIT_TOKEN_TTL_SECONDS: int = 600 CELERY_DB_POOL_SIZE: int = 1 CELERY_DB_MAX_OVERFLOW: int = 1 CELERY_DB_POOL_TIMEOUT: int = 30 CELERY_DB_POOL_RECYCLE: int = 1800 # Celery 图片/视频下载容灾配置。 # Redis broker 下 priority=0 最高,priority=9 最低。 DOWNLOAD_TASK_PRIORITY_NORMAL: int = 5 DOWNLOAD_TASK_PRIORITY_RECOVER: int = 0 DOWNLOAD_TASK_MAX_ATTEMPTS: int = 3 DOWNLOAD_TASK_RETRY_BACKOFF_SECONDS: int = 30 DOWNLOAD_TASK_LEASE_SECONDS: int = 10 * 60 DOWNLOAD_TASK_QUEUE_TIMEOUT_SECONDS: int = 5 * 60 DOWNLOAD_RECOVERY_BATCH_SIZE: int = 100 DOWNLOAD_RECOVERY_STARTUP_DELAY_SECONDS: int = 3 DOWNLOAD_ACTIVE_REDIS_HASH_KEY: str = "vg:celery:download:active" DOWNLOAD_ACTIVE_REDIS_ZSET_KEY: str = "vg:celery:download:active_index" RESOURCE_SIGN_SECRET: str = "resource-signature-secret-key-for-API-authentication" RESOURCE_SIGN_EXPIRE_SECONDS: int = 60 RESOURCE_SIGN_ARG_EXPIRE: str = "exp" RESOURCE_SIGN_ARG_SIGNATURE: str = "sign" settings = Settings()