"""LLM 的 OpenAI 兼容 base_url:仅从 ``os.getenv`` / ``os.environ`` 读取。 启动时在 ``core.main`` 会先 ``load_dotenv``;本模块在 import 时也会对 ``backend/.env`` 执行一次 ``load_dotenv``,保证仅 import ``llm_env`` / ``llm_catalog`` 时 ``os.getenv`` 也能读到 ``.env``。 """ from __future__ import annotations import os from pathlib import Path from dotenv import load_dotenv load_dotenv(Path(__file__).resolve().parent.parent / ".env") def _strip_optional_quotes(raw: str) -> str: s = raw.strip() if len(s) >= 2 and s[0] == s[-1] and s[0] in "\"'": return s[1:-1].strip() return s def _getenv_nonempty(*keys: str) -> str: """依次尝试多个键名(含大小写变体),取第一个非空的 ``os.getenv`` 结果。""" for k in keys: for variant in (k, k.upper(), k.lower()): v = os.getenv(variant) if v is not None and str(v).strip(): return _strip_optional_quotes(str(v).strip()) return "" def tongyi_openai_compatible_base_url() -> str: """通义等 OpenAI SDK(聊天、视觉等):仅从 ``DASHSCOPE_API_BASE`` 读取,无内置默认。""" return _getenv_nonempty("DASHSCOPE_API_BASE", "dashscope_api_base").strip().rstrip("/") def dashscope_native_http_api_base() -> str: """ DashScope **原生** HTTP 根路径(``Generation`` / ``ImageSynthesis`` 等 ``dashscope`` SDK)。 与 OpenAI 兼容网关 ``.../compatible-mode/v1`` 不同;若 ``DASHSCOPE_API_BASE`` 指向兼容模式, 则替换为同一主机下的 ``/api/v1``,避免 SDK 拼出非法 URL(服务端 ``InvalidParameter: url error``)。 """ raw = tongyi_openai_compatible_base_url() default = "https://dashscope.aliyuncs.com/api/v1" if not raw: return default if "compatible-mode" in raw: host_and_before = raw.split("/compatible-mode", 1)[0].rstrip("/") return f"{host_and_before}/api/v1" return raw def resolved_deepseek_chat_base_url() -> str: """DeepSeek OpenAI 兼容 base:仅从 ``DEEPSEEK_API_BASE`` 读取,无内置默认。""" return _getenv_nonempty("DEEPSEEK_API_BASE", "deepseek_api_base").strip().rstrip("/")