import sys from pathlib import Path from pydantic import field_validator, model_validator from pydantic_settings import BaseSettings, SettingsConfigDict from typing import Optional _env_path = Path(__file__).resolve().parent.parent.parent / ".env" if not _env_path.exists(): _env_path = Path(".env") class Settings(BaseSettings): model_config = SettingsConfigDict(env_file=str(_env_path), extra="ignore") DATABASE_URL: str = "postgresql+asyncpg://postgres:postgres123@db:5432/geo_platform" REDIS_URL: str = "redis://redis:6379/0" # JWT 密钥:必须通过环境变量设置,不提供任何默认值 JWT_SECRET: str JWT_EXPIRE_HOURS: int = 24 # NextAuth 密钥 SECRET_KEY: Optional[str] = None PLAYWRIGHT_BROWSERS_PATH: str = "/ms-playwright" ENABLE_LLM: bool = False ZHIPU_API_KEY: str = "" TONGYI_API_KEY: str = "" CORS_ORIGINS: str = "http://localhost:3000,http://localhost:3001" # ---- LLM Provider 配置 ---- DEFAULT_LLM_PROVIDER: str = "openai" DEFAULT_LLM_MODEL: str = "qwen3-coder-plus" OPENAI_API_KEY: str = "" OPENAI_MODEL: str = "qwen3-coder-plus" OPENAI_BASE_URL: str = "https://coding.dashscope.aliyuncs.com/v1" DEEPSEEK_API_KEY: str = "" DEEPSEEK_MODEL: str = "deepseek-chat" DEEPSEEK_BASE_URL: str = "https://api.deepseek.com/v1" DEEPSEEK_MAX_CONTEXT: int = 64000 # AI平台API配置 MOONSHOT_API_KEY: str = "" # Kimi (月之暗面) API Key BAIDU_QIANFAN_API_KEY: str = "" # 百度千帆 API Key BAIDU_QIANFAN_SECRET_KEY: str = "" # 百度千帆 Secret Key DOUBAO_API_KEY: str = "" # 豆包 (字节跳动) API Key DOUBAO_ENDPOINT_ID: str = "" # 豆包推理接入点 ID # AI平台API调用频率限制(每分钟请求数) API_RATE_LIMIT_RPM: int = 10 @field_validator("JWT_SECRET") @classmethod def validate_jwt_secret(cls, v: str) -> str: if not v or v.strip() == "": print( "[FATAL] JWT_SECRET is not set. " "Please set a strong secret key (>= 32 characters) in your .env file.", file=sys.stderr, ) sys.exit(1) if len(v) < 32: print( f"[FATAL] JWT_SECRET is too short ({len(v)} chars). " "It must be at least 32 characters long.", file=sys.stderr, ) sys.exit(1) return v @model_validator(mode="after") def validate_secret_key(self) -> "Settings": if self.SECRET_KEY is not None: if len(self.SECRET_KEY) < 32: print( f"[FATAL] SECRET_KEY is too short ({len(self.SECRET_KEY)} chars). " "It must be at least 32 characters long.", file=sys.stderr, ) sys.exit(1) return self settings = Settings()