from __future__ import annotations from functools import lru_cache from pathlib import Path from typing import Literal, Optional from pydantic_settings import BaseSettings, SettingsConfigDict def _guess_env_file(app_env: str) -> Optional[str]: """ 根据 APP_ENV 选择 env 文件。 说明: - `.env.dev` / `.env.prod` 不进入仓库,通常由运维在部署时放到 `server/` 目录 - 如果文件不存在,则返回 None,让系统从“真实环境变量”读取 """ base_dir = Path(__file__).resolve().parents[2] # .../server/app -> .../server candidates = { "dev": base_dir / ".env.dev", "prod": base_dir / ".env.prod", } p = candidates.get(app_env) if p and p.exists(): return str(p) return None class Settings(BaseSettings): """ 应用配置(统一从环境变量读取)。 注意:请不要把真实账号密码写入仓库;使用 `.env.dev/.env.prod` 或部署系统注入。 """ app_env: Literal["dev", "prod"] = "dev" app_name: str = "mindfulness-server" app_host: str = "0.0.0.0" app_port: int = 8000 database_url: str redis_url: str celery_broker_url: str celery_result_backend: Optional[str] = None model_config = SettingsConfigDict( env_prefix="", case_sensitive=False, extra="ignore", ) @lru_cache def get_settings() -> Settings: """ 获取配置(带缓存)。 加载顺序: - 优先使用 `.env.dev/.env.prod`(若存在) - 否则使用系统环境变量 """ import os env = os.getenv("APP_ENV", "dev").strip() or "dev" env_file = _guess_env_file(env) return Settings(_env_file=env_file)