"use strict"; /** * 从进程环境变量读取 desktop_configs(Rust 注入 AICLIENT_CFG_*)。 * 库表 name 经规范化后作为 env 后缀,如 name=LLM_API_KEY → AICLIENT_CFG_LLM_API_KEY */ const ENV_PREFIX = "AICLIENT_CFG_"; function normalizeKey(name) { return String(name || "") .trim() .replace(/[^a-zA-Z0-9]+/g, "_") .replace(/^_+|_+$/g, "") .toUpperCase(); } /** @returns {Record} 逻辑键(大写+下划线)→ 值 */ function readAllFromEnv() { const out = {}; for (const [ek, ev] of Object.entries(process.env)) { if (!ek.startsWith(ENV_PREFIX) || ev == null || ev === "") continue; const logical = ek.slice(ENV_PREFIX.length); out[logical] = ev; } return out; } function get(logicalKey, fallback = "") { const k = normalizeKey(logicalKey); return process.env[ENV_PREFIX + k] || fallback; } function parseJson(val, fallback = null) { if (!val) return fallback; try { return JSON.parse(val); } catch { return fallback; } } /** * 将扁平配置组装为流水线使用的 modelConfig(兼容现有脚本字段名)。 * 可在库表增加任意键;复杂对象用 JSON 字符串存于 OSS_CONFIG、ASR_SERVER_INFO 等。 */ function buildModelConfig() { const c = readAllFromEnv(); const pick = (...keys) => { for (const k of keys) { const v = c[normalizeKey(k)]; if (v) return v; } return ""; }; let apiUrl = pick("LLM_BASE_URL", "LLM_BASE_URL"); if (apiUrl) { apiUrl = apiUrl.replace(/\/$/, ""); if (!apiUrl.includes("/chat/completions")) { apiUrl = apiUrl.endsWith("/v1") ? `${apiUrl}/chat/completions` : `${apiUrl}/v1/chat/completions`; } } let apiModelId = pick("LLM_MODEL_ID", "LLM_MODEL_ID") || "doubao-seed-2-0-mini-260215"; const asrMode = pick("ASR_MODE", "asr_mode") || "online"; let ossConfig = parseJson(pick("OSS_CONFIG")); if (!ossConfig && pick("OSS_ACCESS_KEY_ID")) { ossConfig = { accessKeyId: pick("OSS_ACCESS_KEY_ID"), accessKeySecret: pick("OSS_ACCESS_KEY_SECRET"), bucket: pick("OSS_BUCKET"), region: pick("OSS_REGION"), endpoint: pick("OSS_ENDPOINT") || undefined, }; } let asrServerInfo = parseJson(pick("ASR_SERVER_INFO")); if (!asrServerInfo && pick("ASR_SERVER_URL")) { asrServerInfo = { name: pick("ASR_SERVER_NAME", "local") || "local", baseUrl: pick("ASR_SERVER_URL").replace(/\/$/, ""), asrPath: pick("ASR_SERVER_ASR_PATH", "/asr") || "/asr", }; } return { providerId: pick("LLM_PROVIDER_ID", "PROVIDER_ID") || "bailian", modelId: pick("LLM_MODEL_ID", "MODEL_ID"), apiUrl, apiKey: pick("LLM_API_KEY", "API_KEY") || "", type: pick("LLM_TYPE", "TYPE") || "bailian", asrMode, apiModelId, aliyunApiKey: pick("BAILIAN_API_KEY", "BAILIAN_API_KEY"), ossConfig: ossConfig || undefined, asrServerInfo: asrServerInfo || undefined, }; } function validateModelConfig(modelConfig) { if (!modelConfig.apiKey) { return { ok: false, error: "缺少配置 LLM_API_KEY(desktop_configs 表)" }; } if (!modelConfig.apiUrl) { return { ok: false, error: "缺少配置 LLM_API_URL" }; } if (modelConfig.asrMode === "online") { if (!modelConfig.aliyunApiKey) { return { ok: false, error: "在线 ASR 需配置 DASHSCOPE_API_KEY" }; } if (!modelConfig.ossConfig?.bucket) { return { ok: false, error: "在线 ASR 需配置 OSS(或 OSS_CONFIG JSON)" }; } } if (modelConfig.asrMode === "local" && !modelConfig.asrServerInfo) { return { ok: false, error: "本地 ASR 需配置 ASR_SERVER_URL 或 ASR_SERVER_INFO" }; } return { ok: true }; } module.exports = { ENV_PREFIX, readAllFromEnv, get, buildModelConfig, validateModelConfig, };