from functools import lru_cache from pathlib import Path from dotenv import load_dotenv from pydantic_settings import BaseSettings, SettingsConfigDict # .env 在仓库根(server/ 的上一级),供各部分共用 _ROOT_DIR = Path(__file__).resolve().parents[2] load_dotenv(_ROOT_DIR / ".env") class Settings(BaseSettings): """运行时与密钥。模型清单见 config/models.yaml。""" model_config = SettingsConfigDict( env_file=str(_ROOT_DIR / ".env"), env_file_encoding="utf-8", extra="ignore", ) # ── AI 密钥 ── deepseek_api_key: str = "" openai_api_key: str = "" dashscope_api_key: str = "" # 华北2(北京)业务空间时需填:https://{WorkspaceId}.cn-beijing.maas.aliyuncs.com/api/v1 dashscope_base_http_api_url: str = "" # ── 运行 ── host: str = "127.0.0.1" port: int = 8800 cors_origins: str = "" # ── V2:数据层 ── # 本地过渡用 SQLite;上线切 PostgreSQL:postgresql+asyncpg://user:pass@host:5432/ozon_seller database_url: str = "sqlite+aiosqlite:///./data/app.db" # ── V2:鉴权 ── app_token: str = "" # MVP 单用户登录 token(换发 JWT 用) secret_key: str = "" # 店铺凭证 AES-GCM 加密密钥 + JWT 签名密钥 jwt_expire_minutes: int = 60 * 24 * 7 # JWT 有效期(默认 7 天) # ── V2:七牛(图片存储)── qiniu_access_key: str = "" qiniu_secret_key: str = "" qiniu_bucket: str = "" qiniu_domain: str = "" # 绑定域名,如 https://cdn.example.com # 为空时用本地文件系统兜底(开发期),不为空时走七牛 storage_backend: str = "local" # local | qiniu # ── V2:对外地址(插件/前端回写、生成图回调)── app_base_url: str = "http://127.0.0.1:8800" # ── V2.1 套图生图(provider 路由与 image-suite-studio 一致)── image_provider: str = "doubao" # 未知模型时的兜底 provider:doubao | tongyi | rightapi request_timeout: int = 300 # 单张生图请求超时(秒) poll_max_wait: int = 600 # 异步任务轮询上限(秒) # 水印徽章源图(图片水印用,可 .env 覆盖) watermark_image_path: str = str(Path(__file__).resolve().parents[1] / "assets" / "watermark.jpg") # 豆包 / 火山方舟 Seedream ark_api_key: str = "" ark_base_url: str = "https://ark.cn-beijing.volces.com/api/v3/images/generations" ark_image_model: str = "doubao-seedream-4-5-251128" # 通义 / DashScope(key 复用上方 dashscope_api_key;dashscope_base_http_api_url 是业务空间专用,与此处无关) dashscope_model: str = "wan2.7-image-pro" dashscope_base_url: str = "" # 留空按模型自动选择万象异步/千问同步端点 # RightAPI(OpenAI 兼容中转:gpt-image / nano-banana 系列) rightapi_api_key: str = "" rightapi_base_url: str = "https://rightapi.ai/draw" rightapi_image_model: str = "gpt-image-2" rightapi_max_retries: int = 3 # 429/5xx/超时的重试次数(1 = 不重试) rightapi_retry_wait: int = 60 # 重试基础等待秒数,按 60→120→240 递增 # DeepSeek 出图方案规划器(key 复用上方 deepseek_api_key;文案生成的模型走 config/models.yaml,互不影响) deepseek_base_url: str = "https://api.deepseek.com/v1" deepseek_model: str = "deepseek-v4-flash" @property def cors_origin_list(self) -> list[str]: if not self.cors_origins.strip(): return [] return [o.strip() for o in self.cors_origins.split(",") if o.strip()] @property def use_qiniu(self) -> bool: return self.storage_backend == "qiniu" and bool( self.qiniu_access_key and self.qiniu_secret_key and self.qiniu_bucket ) @lru_cache def get_settings() -> Settings: return Settings()