from __future__ import annotations import os from dataclasses import dataclass from pathlib import Path from dotenv import load_dotenv ROOT_DIR = Path(__file__).resolve().parents[2] load_dotenv(ROOT_DIR.parent / ".env") load_dotenv(ROOT_DIR / ".env") def _bool(name: str, default: bool = False) -> bool: value = os.getenv(name) if value is None: return default return value.strip().lower() in {"1", "true", "yes", "on"} @dataclass(frozen=True) class Settings: app_env: str = os.getenv("APP_ENV", "development") workspace_id: str = os.getenv("WORKSPACE_ID", "local-workspace") data_dir: Path = Path(os.getenv("DATA_DIR", str(ROOT_DIR / "data"))) demo_fallback: bool = _bool("DEMO_FALLBACK", True) llm_base_url: str = os.getenv("LLM_BASE_URL", "https://api.openai.com/v1").rstrip("/") llm_api_key: str = os.getenv("LLM_API_KEY", "") llm_model: str = os.getenv("LLM_MODEL", "gpt-4o-mini") embedding_base_url: str = os.getenv("EMBEDDING_BASE_URL", "https://api.openai.com/v1").rstrip("/") embedding_api_key: str = os.getenv("EMBEDDING_API_KEY", "") embedding_model: str = os.getenv("EMBEDDING_MODEL", "text-embedding-3-small") embedding_dimensions: int = int(os.getenv("EMBEDDING_DIMENSIONS", "1536")) embedding_min_score: float = float(os.getenv("EMBEDDING_MIN_SCORE", "0.35")) database_url: str = os.getenv( "DATABASE_URL", "postgresql://memory:memory@localhost:54329/memory_agents", ) redis_url: str = os.getenv("REDIS_URL", "redis://localhost:6379/0") letta_base_url: str = os.getenv("LETTA_BASE_URL", "http://localhost:8283").rstrip("/") letta_api_key: str = os.getenv("LETTA_API_KEY", "") letta_enabled: bool = _bool("LETTA_ENABLED") mem0_enabled: bool = _bool("MEM0_ENABLED") reme_enabled: bool = _bool("REME_ENABLED") memu_enabled: bool = _bool("MEMU_ENABLED") settings = Settings() if not 0.0 <= settings.embedding_min_score <= 1.0: raise ValueError("EMBEDDING_MIN_SCORE 必须在 0 到 1 之间") settings.data_dir.mkdir(parents=True, exist_ok=True) # Some optional SDKs, especially Mem0's default local client, look for the # conventional OpenAI environment names. Keep the project-facing configuration # unified while making those SDKs inherit the same OpenAI-compatible endpoint. if settings.llm_api_key: os.environ.setdefault("OPENAI_API_KEY", settings.llm_api_key) os.environ.setdefault("DEEPSEEK_API_KEY", settings.llm_api_key) if settings.llm_base_url: os.environ.setdefault("OPENAI_BASE_URL", settings.llm_base_url) os.environ.setdefault("OPENAI_API_BASE", settings.llm_base_url) os.environ.setdefault("LLM_BACKEND", "openai") os.environ.setdefault("LLM_API_KEY", settings.llm_api_key) os.environ.setdefault("LLM_BASE_URL", settings.llm_base_url) os.environ.setdefault("LLM_MODEL_NAME", settings.llm_model)