Files
beige/backend/app/core/config.py
yangqianqian 6a2632da70 baseline: Clover 独立仓库首次基线提交
将 Clover 从上层产品包旧仓库中独立出来,建立专属版本控制。
当前状态=纵切片端到端已打通(登录→选品→出文出图→审核→下载包),
M1文案质量去套路化已验收。此提交作为后续按核销清单逐条修复的基线。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 11:30:22 +08:00

81 lines
3.0 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.
"""
app/core/config.py — 环境变量加载 + 启动校验
必填项缺失则启动失败,不静默。
"""
import os
from functools import lru_cache
from pydantic import field_validator
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
# ── 必填(缺失启动保护)───────────────────────────
FERNET_KEY: str
JWT_SECRET: str
DATABASE_URL: str
MONGO_URI: str
REDIS_URL: str
# ── AI 提供商(不写死默认,可配置)──────────────────
IMAGE_PROVIDER_PRIMARY: str = "gpt"
IMAGE_PROVIDER_FALLBACK: str = "gemini"
IMAGE_API_BASE: str = ""
IMAGE_MODEL: str = "gpt-image-2"
MODEL_IMAGE: str = "gpt-image-2" # 别名,与 IMAGE_MODEL 同义
MODEL_TEXT: str = "claude-opus-4-8"
MODEL_VISION: str = "" # 视觉模型verify_real_image 脚本用)
CLAUDE_API_URL: str = ""
GEMINI_API_URL: str = ""
# ── 多 Provider Key各人自录测试/真实出图脚本用)──
APIPORTS_BASE_URL: str = ""
APIPORTS_KEY: str = ""
CODEPROXY_BASE_URL: str = ""
CODEPROXY_KEY: str = ""
# ── 应用配置 ──────────────────────────────────────
APP_ENV: str = "development"
JWT_EXPIRE_MINUTES: int = 60 * 24 * 7 # 7天
CELERY_BROKER_URL: str = ""
CELERY_RESULT_BACKEND: str = ""
# ── 并发限制(可配置,不写死)─────────────────────
MAX_CONCURRENT_TASKS_PER_USER: int = 2
# ── 文件存储路径 ──────────────────────────────────
UPLOAD_BASE_PATH: str = "uploads/packages"
# StaticFiles 实际服务的绝对目录(与 main.py app.mount("/uploads", .../uploads) 一致)。
# 容器内 main.py 在 /app/main.py故 uploads 绝对根 = /app/uploads。
# 所有写盘/读盘统一锚定此根,避免 api(cwd=/app) 与 worker(cwd=/) 相对路径解析不一致。
UPLOAD_ABS_ROOT: str = "/app/uploads"
model_config = {"env_file": ".env", "case_sensitive": True, "extra": "ignore"}
@field_validator("FERNET_KEY")
@classmethod
def fernet_key_not_empty(cls, v: str) -> str:
if not v or len(v) < 32:
raise ValueError("FERNET_KEY must be set and at least 32 chars")
return v
@field_validator("JWT_SECRET")
@classmethod
def jwt_secret_not_empty(cls, v: str) -> str:
if not v or len(v) < 32:
raise ValueError("JWT_SECRET must be at least 32 characters")
return v
def celery_broker(self) -> str:
return self.CELERY_BROKER_URL or self.REDIS_URL
def celery_backend(self) -> str:
return self.CELERY_RESULT_BACKEND or self.REDIS_URL
@lru_cache()
def get_settings() -> Settings:
"""单例配置,启动时校验一次。"""
return Settings()