Files
beige/backend/app/core/config.py
yangqianqian df1856d793 上线版: 产品表单统一+form嵌套修复+用户管理+部署+三套叙事
- 产品编辑入口统一走 ProductFormFull(卖点/风格/人群/品牌词全字段);
  修复开任务页 <form> 套 <form> 致"编辑产品"报错、改不了、跳回首个产品
- dashboard 入口卡片对齐实际路由: 系统管理(/config) 与 工作配置(/settings) 分开;
  settings ?tab=products 直达改用挂载后读 URL, 消除 hydration mismatch
- 新增用户管理(users API/admin service/改密页) + alembic 022/023/024
- 上线部署: Dockerfile / docker-compose.prod+https / nginx https / .env.example
- A8 三套正交叙事(痛点/场景/成分背书) + beige 调色去AI化 + 飞轮 text_import 高权重信号

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

83 lines
3.1 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"
CORS_ALLOW_ORIGINS: str = "http://localhost:3000"
JWT_EXPIRE_MINUTES: int = 60 * 24 * 7 # 7天
CELERY_BROKER_URL: str = ""
CELERY_RESULT_BACKEND: str = ""
# ── 并发限制(可配置,不写死)─────────────────────
# 倩倩姐红线:每用户并发上限 5 个任务(客户侧实际跑几个再观察调整)。
MAX_CONCURRENT_TASKS_PER_USER: int = 5
# ── 文件存储路径 ──────────────────────────────────
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()