{"repo": "billbai-longarena/shenyu", "files": {"packages/backend/src/services/model-service.ts": {"255fe6ab513400bddb2b6287e5f41b496690beec": {"t": 1785674644.8021383, "n": 9833, "h": "3636ad52a3d2c674", "c": "import { ModelType } from '../types/api.js';\n\ninterface ModelConfig {\n apiKey: string;\n url: string;\n model: string;\n maxTokens: number;\n temperatureRange: {\n min: number;\n max: number;\n };\n}\n\n// 打印环境变量状态\nconsole.log('[ModelService] Environment variables status:', {\n DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY ? 'exists' : 'missing',\n SILICON_DEEPSEEK_API_KEY: process.env.SILICON_DEEPSEEK_API_KEY ? 'exists' : 'missing',\n KIMI_API_KEY: process.env.KIMI_API_KEY ? 'exists' : 'missing',\n YIWAN_API_KEY: process.env.YIWAN_API_KEY ? 'exists' : 'missing',\n BAIDU_API_KEY: process.env.BAIDU_API_KEY ? 'exists' : 'missing',\n ALIYUN_API_KEY: process.env.ALIYUN_API_KEY ? 'exists' : 'missing',\n VOLCES_API_KEY: process.env.VOLCES_API_KEY ? 'exists' : 'missing',\n TENCENT_API_KEY: process.env.TENCENT_API_KEY ? 'exists' : 'missing',\n MINIMAX_API_KEY: process.env.MINIMAX_API_KEY ? 'exists' : 'missing'\n});\n\n// API配置\nlet API_CONFIGS: Record;\n\nfunction createConfigs(): Record {\n return {\n deepseek: {\n apiKey: process.env.DEEPSEEK_API_KEY || '',\n url: 'https://api.deepseek.com/chat/completions',\n model: 'deepseek-chat',\n maxTokens: 8191,\n temperatureRange: {\n min: 0,\n max: 2.0\n }\n },\n siliconDeepseek: {\n apiKey: process.env.SILICON_DEEPSEEK_API_KEY || '',\n url: 'https://api.siliconflow.cn/v1/chat/completions',\n model: 'deepseek-ai/DeepSeek-V3',\n maxTokens: 4096,\n temperatureRange: {\n min: 0,\n max: 2.0\n }\n },\n kimi: {\n apiKey: process.env.KIMI_API_KEY || '',\n url: 'https://api.moonshot.cn/v1/chat/completions',\n model: 'moonshot-v1-8k',\n maxTokens: 4096,\n temperatureRange: {\n min: 0,\n max: 1\n }\n },\n yiwan: {\n apiKey: process.env.YIWAN_API_KEY || '',\n url: 'https://api.lingyiwanwu.com/v1/chat/completions',\n model: 'yi-lightning',\n maxTokens: 8092,\n temperatureRange: {\n min: 0,\n max: 1\n }\n },\n baiduDeepseek: {\n apiKey: process.env.BAIDU_API_KEY || '',\n url: 'https://qianfan.baidubce.com/v2/chat/completions',\n model: 'deepseek-v3',\n maxTokens: 4092,\n temperatureRange: {\n min: 0,\n max: 2.0\n }\n },\n 'qwen-turbo-latest': {\n apiKey: process.env.ALIYUN_API_KEY || '',\n url: 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',\n model: 'qwen-plus',\n maxTokens: 8191,\n temperatureRange: {\n min: 0,\n max: 1\n }\n },\n 'alideepseekv3': {\n apiKey: process.env.ALIYUN_API_KEY || '',\n url: 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',\n model: 'deepseek-v3',\n maxTokens: 8191,\n temperatureRange: {\n min: 0,\n max: 2.0\n }\n },\n 'alideepseekr1': {\n apiKey: process.env.ALIYUN_API_KEY || '',\n url: 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',\n model: 'deepseek-r1',\n maxTokens: 4191,\n temperatureRange: {\n min: 0,\n max: 1.0\n }\n },\n 'volcesDeepseek': {\n apiKey: process.env.VOLCES_API_KEY || '',\n url: 'https://ark.cn-beijing.volces.com/api/v3/chat/completions',\n model: 'ep-20250328100701-2rxzs',\n maxTokens: 8096,\n temperatureRange: {\n min: 0,\n max: 1.0\n }\n },\n 'volcesDeepseekR1': {\n apiKey: process.env.VOLCES_API_KEY || '',\n url: 'https://ark.cn-beijing.volces.com/api/v3/chat/completions',\n model: 'ep-20250215224020-9nkj4',\n maxTokens: 8096,\n temperatureRange: {\n min: 0,\n max: 1.0\n }\n },\n 'tencentDeepseek': {\n apiKey: process.env.TENCENT_API_KEY || '',\n url: 'https://api.lkeap.cloud.tencent.com/v1/chat/completions',\n model: 'deepseek-v3',\n maxTokens: 4096,\n temperatureRange: {\n min: 0,\n max: 1.0\n }\n },\n 'minimax-text': {\n apiKey: process.env.MINIMAX_API_KEY || '',\n url: 'https://api.minimax.chat/v1/text/chatcompletion_v2',\n model: 'abab5.5-chat',\n maxTokens: 8096,\n temperatureRange: {\n min: 0,\n max: 1.0\n }\n }\n };\n}\n\n// 初始化配置\nAPI_CONFIGS = createConfigs();\n\nclass ModelService {\n private static instance: ModelService;\n private currentModel: ModelType = 'kimi';\n private currentTemperature: number = 0.7;\n\n private constructor() {\n // 初始化时创建配置\n API_CONFIGS = createConfigs();\n }\n\n public reloadConfig(): void {\n console.log('[ModelService] Reloading config with environment variables status:', {\n DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY ? 'exists' : 'missing',\n SILICON_DEEPSEEK_API_KEY: process.env.SILICON_DEEPSEEK_API_KEY ? 'exists' : 'missing',\n KIMI_API_KEY: process.env.KIMI_API_KEY ? 'exists' : 'missing',\n YIWAN_API_KEY: process.env.YIWAN_API_KEY ? 'exists' : 'missing',\n BAIDU_API_KEY: process.env.BAIDU_API_KEY ? 'exists' : 'missing',\n ALIYUN_API_KEY: process.env.ALIYUN_API_KEY ? 'exists' : 'missing',\n VOLCES_API_KEY: process.env.VOLCES_API_KEY ? 'exists' : 'missing',\n TENCENT_API_KEY: process.env.TENCENT_API_KEY ? 'exists' : 'missing',\n MINIMAX_API_KEY: process.env.MINIMAX_API_KEY ? 'exists' : 'missing'\n });\n API_CONFIGS = createConfigs();\n }\n\n public static getInstance(): ModelService {\n if (!ModelService.instance) {\n ModelService.instance = new ModelService();\n }\n return ModelService.instance;\n }\n\n public getConfig(model: ModelType): ModelConfig {\n return API_CONFIGS[model];\n }\n\n public getAllConfigs(): Record {\n return API_CONFIGS;\n }\n\n public getCurrentModel(): ModelType {\n return this.currentModel;\n }\n\n public setCurrentModel(model: ModelType): void {\n if (model in API_CONFIGS) {\n this.currentModel = model;\n }\n }\n\n public getCurrentTemperature(): number {\n return this.currentTemperature;\n }\n\n public setCurrentTemperature(temp: number): void {\n const config = this.getConfig(this.currentModel);\n if (temp >= config.temperatureRange.min && temp <= config.temperatureRange.max) {\n this.currentTemperature = temp;\n }\n }\n\n public getHeaders(model: ModelType): Record {\n const config = this.getConfig(model);\n const headers: Record = {\n 'Content-Type': 'application/json'\n };\n\n // 不同模型需要不同的Authorization格式\n switch (model) {\n case 'kimi':\n // kimi需要sk-前缀,但env中已经包含了sk-前缀\n const kimiKey = config.apiKey.trim();\n headers['Authorization'] = `Bearer ${kimiKey}`;\n break;\n case 'yiwan':\n // yiwan不需要sk-前缀\n const yiwanKey = config.apiKey.replace(/^(Bearer\\s+)?(sk-)?/, '');\n headers['Authorization'] = `Bearer ${yiwanKey}`;\n break;\n case 'baiduDeepseek':\n // 百度API使用原始格式\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n break;\n case 'qwen-turbo-latest':\n case 'alideepseekv3':\n case 'alideepseekr1':\n // 阿里云API使用原始格式\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n break;\n case 'volcesDeepseek':\n case 'volcesDeepseekR1':\n // 火山API使用原始格式\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n break;\n case 'tencentDeepseek':\n // 腾讯云API使用原始格式\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n break;\n case 'minimax-text':\n // MiniMax API使用原始格式\n headers['Authorization'] = `Bearer ${config.apiKey}`;\n break;\n default:\n // 其他模型使用标准Bearer token with sk-\n const standardKey = config.apiKey.replace(/^(Bearer\\s+)?(sk-)?/, '');\n headers['Authorization'] = `Bearer sk-${standardKey}`;\n }\n\n return headers;\n }\n\n public validateTemperature(model: ModelType, temperature: number): number {\n const config = this.getConfig(model);\n return Math.max(\n config.temperatureRange.min,\n Math.min(config.temperatureRange.max, temperature)\n );\n }\n\n public estimateTokens(text: string): number {\n // 简单估算:平均每个字符占用0.25个token\n return Math.ceil(text.length * 0.25);\n }\n\n public calculateMaxTokens(model: ModelType, inputTokens: number): number {\n const config = this.getConfig(model);\n const reservedTokens = Math.ceil(config.maxTokens * 0.2); // 预留20%给响应\n return Math.max(100, config.maxTokens - inputTokens - reservedTokens);\n }\n}\n\nexport default ModelService;\n"}}}}