Files
video-gen/video-gen-api/app/config.py
T

206 lines
8.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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=消息组IDTemplateID=模板IDSign=短信签名内容。
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 = ""
ALIPAY_NOTIFY_URL: str = ""
PAYMENT_MOCK: bool = False # Default off; use admin panel to enable for testing
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 = ""
# Celery async 兼容配置。
# single_loop:每个 Celery 子进程一个专用 event loop,推荐线上/本地统一使用。
# direct:旧版线程本地 loop 降级模式,建议配合 CELERY_DB_USE_NULLPOOL=true。
CELERY_ASYNC_RUNNER_MODE: str = "single_loop"
CELERY_DB_USE_NULLPOOL: bool = False
CELERY_STARTUP_RECOVERY_ENABLED: bool = True
CHATAPI_REQUEST_TIMEOUT_SECONDS: int = 180
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"
# Celery 生成链路 / provider poll 容灾配置。
# 说明:
# - 不新增 Celery worker;恢复任务仍投递到 gen_result_download。
# - worker_ready 每个 worker 都会尝试抢启动恢复锁,只有抢到锁的 worker 投递恢复任务。
# - poll active 使用独立 Redis key,避免影响稳定的下载 active 注册表。
GENERATION_RECOVERY_BATCH_SIZE: int = 100
GENERATION_RECOVERY_MAX_ROUNDS: int = 5
POLL_RECOVERY_BATCH_SIZE: int = 100
POLL_TASK_LEASE_SECONDS: int = 5 * 60
POLL_TASK_QUEUE_TIMEOUT_SECONDS: int = 2 * 60
POLL_ACTIVE_REDIS_HASH_KEY: str = "vg:celery:poll:active"
POLL_ACTIVE_REDIS_ZSET_KEY: str = "vg:celery:poll:active_index"
CELERY_STARTUP_RECOVERY_LOCK_KEY: str = "vg:celery:startup_recovery_lock"
CELERY_STARTUP_RECOVERY_LOCK_TTL_SECONDS: int = 120
# 模块异步任务容灾配置。
# 覆盖 ModuleGenerationStep 提词任务、shot 原视频/片段分析、shot ffmpeg 切割 active 注册。
# 不新增 worker 队列:恢复扫描仍走 gen_result_download,真实业务任务回到原始队列。
MODULE_ASYNC_RECOVERY_BATCH_SIZE: int = 100
MODULE_ASYNC_QUEUE_TIMEOUT_SECONDS: int = 5 * 60
MODULE_ASYNC_LEASE_SECONDS: int = 10 * 60
MODULE_ASYNC_LOCK_TTL_SECONDS: int = 10 * 60
MODULE_ASYNC_REQUEUE_DELAY_SECONDS: int = 10
MODULE_ASYNC_ACTIVE_REDIS_HASH_KEY: str = "vg:celery:module_async:active"
MODULE_ASYNC_ACTIVE_REDIS_ZSET_KEY: str = "vg:celery:module_async:active_index"
MODULE_ASYNC_LOCK_KEY_PREFIX: str = "vg:celery:module_async:lock"
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"
# 爆款开头复刻默认配置。素材校验由前端完成,后端只接收已有上传接口返回的链接。
HOT_OPENING_DEFAULT_VIDEO_DURATION: int = 4
HOT_OPENING_DEFAULT_VIDEO_RATIO: str = "9:16"
HOT_OPENING_DEFAULT_VIDEO_RESOLUTION: str = "480p"
HOT_OPENING_DEFAULT_TARGET_PLATFORM: str = "抖音"
# 拆镜复刻配置。
# 原始上传视频和拆镜片段都属于 uploads 素材域;只有 generate 生成结果走 token 验签。
SHOT_ANALYSIS_TIMEOUT_SECONDS: int = 180
SHOT_ANALYSIS_TEMPERATURE: float = 0.1
SHOT_ANALYSIS_MAX_TOKENS: int = 5000
SHOT_ANALYSIS_VIDEO_FPS: float = 1.0
SHOT_ANALYSIS_MAX_LOCAL_VIDEO_MB: int = 45
SHOT_SEGMENT_LOCAL_PATH: str = "./storage/uploads/shot_segments"
SHOT_SEGMENT_URL_PREFIX: str = "/uploads/shot_segments"
SHOT_SPLIT_MIN_SECONDS: float = 2
SHOT_SPLIT_MAX_SECONDS: float = 15
SHOT_SPLIT_END_TOLERANCE_SECONDS: float = 0.5
SHOT_DURATION_TOLERANCE_SECONDS: float = 1.0
SHOT_FFMPEG_TIMEOUT_SECONDS: int = 120
SHOT_FFPROBE_TIMEOUT_SECONDS: int = 20
FFPROBE_BIN: str = ""
# 继续复用 gen_result_download 队列,但限制 ffmpeg 并发,避免拖慢 Chat 下载。
SHOT_SPLIT_MAX_CONCURRENT: int = 1
SHOT_SPLIT_MAX_RETRY_COUNT: int = 3
SHOT_SPLIT_RETRY_BACKOFF_SECONDS: int = 30
SHOT_SPLIT_LEASE_SECONDS: int = 10 * 60
SHOT_SPLIT_PENDING_TIMEOUT_SECONDS: int = 5 * 60
SHOT_SPLIT_RECOVERY_BATCH_SIZE: int = 50
SHOT_SPLIT_LOCK_KEY_PREFIX: str = "vg:shot_replicate:split:lock"
SHOT_SPLIT_SEMAPHORE_KEY_PREFIX: str = "vg:shot_replicate:split:semaphore"
SHOT_REPLICATE_DEFAULT_VIDEO_DURATION: int = 4
SHOT_REPLICATE_DEFAULT_VIDEO_RATIO: str = "9:16"
SHOT_REPLICATE_DEFAULT_VIDEO_RESOLUTION: str = "480p"
SHOT_REPLICATE_DEFAULT_TARGET_PLATFORM: str = "抖音"
settings = Settings()