87 lines
3.3 KiB
TypeScript
87 lines
3.3 KiB
TypeScript
// server/utils/env.ts - 服务端环境变量读取与规范化
|
|
|
|
/**
|
|
* 允许 `.env` 里保留类似 Python 旧项目的写法:
|
|
* `OPENAI_API_BASE=https://example.com/v1 # 注释`
|
|
* Nuxt/Node 读到的是整行值,所以这里主动裁掉行尾注释
|
|
*/
|
|
const stripInlineComment = (value: string) => {
|
|
return value.replace(/\s+#.*$/u, "").trim();
|
|
};
|
|
|
|
/**
|
|
* 读取字符串环境变量
|
|
*
|
|
* - 空字符串视为未配置,回退到 fallback
|
|
* - 返回值统一去掉行尾注释,避免 baseURL、model 之类配置带上注释文本
|
|
*/
|
|
const readString = (key: string, fallback = "") => {
|
|
const value = process.env[key];
|
|
if (value === undefined || value === null || value.trim() === "") {
|
|
return fallback;
|
|
}
|
|
|
|
return stripInlineComment(value);
|
|
};
|
|
|
|
/** 读取可选字符串;空值统一转成 undefined,方便后续判断是否启用某能力 */
|
|
const readOptionalString = (key: string) => {
|
|
const value = readString(key);
|
|
return value || undefined;
|
|
};
|
|
|
|
/** 兼容常见布尔写法,便于 Docker、面板和手写 `.env` 配置 */
|
|
const readBoolean = (key: string, fallback: boolean) => {
|
|
const value = readString(key);
|
|
if (!value) return fallback;
|
|
return ["1", "true", "yes", "on"].includes(value.toLowerCase());
|
|
};
|
|
|
|
/** 读取整数配置;非法值不抛错,使用默认值保证服务能启动 */
|
|
const readInteger = (key: string, fallback: number) => {
|
|
const value = Number.parseInt(readString(key), 10);
|
|
return Number.isFinite(value) ? value : fallback;
|
|
};
|
|
|
|
/** 读取小数配置,主要用于 OpenAI temperature */
|
|
const readNumber = (key: string, fallback: number) => {
|
|
const value = Number.parseFloat(readString(key));
|
|
return Number.isFinite(value) ? value : fallback;
|
|
};
|
|
|
|
/** OpenAI 兼容接口 baseURL 统一不带结尾斜杠,后续再拼 `/chat/completions` */
|
|
const normalizeBaseUrl = (url: string) => {
|
|
return url.replace(/\/+$/u, "");
|
|
};
|
|
|
|
/**
|
|
* 服务端环境配置的唯一出口
|
|
*
|
|
* 业务代码不要直接读 `process.env`,这样可以把默认值、格式修正和安全边界
|
|
* 都收敛在这里,后续迁移部署平台时也只需要检查这个文件
|
|
*/
|
|
export const serverEnv = {
|
|
/** OpenAI 或兼容中转平台 API Key,仅服务端使用,不能返回给前端 */
|
|
openAiApiKey: readString("OPENAI_API_KEY"),
|
|
/** OpenAI 兼容 API base,例如 `https://api.openai.com/v1` */
|
|
openAiApiBase: normalizeBaseUrl(
|
|
readString("OPENAI_API_BASE", "https://api.openai.com/v1")
|
|
),
|
|
/** Chat Completions 使用的模型名 */
|
|
openAiModel: readString("OPENAI_MODEL", "gpt-3.5-turbo"),
|
|
/** 单次回答最大 token 数,沿用旧 Python 服务的配置语义 */
|
|
maxTokens: readInteger("MAX_TOKENS", 500),
|
|
/** 模型采样温度,越低越稳定 */
|
|
temperature: readNumber("TEMPERATURE", 0.7),
|
|
/** 可选访问令牌;配置后 API 需要 header 或 query 携带 token */
|
|
accessToken: readOptionalString("ACCESS_TOKEN"),
|
|
/** 是否启用内存缓存 */
|
|
enableCache: readBoolean("ENABLE_CACHE", true),
|
|
/** 缓存过期时间,单位秒 */
|
|
cacheExpiration: readInteger("CACHE_EXPIRATION", 86_400),
|
|
/** 预留日志级别配置,目前日志工具只负责安全输出 */
|
|
logLevel: readString("LOG_LEVEL", "INFO"),
|
|
/** 单行 SSE data 的最大字节数,用于防止异常流无限堆内存 */
|
|
maxSseLineBytes: readInteger("OPENAI_STREAM_MAX_SSE_LINE_BYTES", 1_048_576)
|
|
};
|