@becrafter/prompt-manager 0.1.1 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +304 -121
- package/app/cli/commands/start.js +28 -4
- package/app/cli/support/argv.js +6 -0
- package/env.example +32 -0
- package/package.json +36 -6
- package/packages/server/api/admin.routes.js +409 -1
- package/packages/server/api/open.routes.js +7 -2
- package/packages/server/api/tool.routes.js +479 -0
- package/packages/server/app.js +97 -25
- package/packages/server/configs/models/built-in/bigmodel.yaml +6 -0
- package/packages/server/configs/models/providers.yaml +50 -0
- package/packages/server/configs/templates/built-in/general-iteration.yaml +60 -0
- package/packages/server/configs/templates/built-in/general-optimize.yaml +63 -0
- package/packages/server/configs/templates/built-in/output-format-optimize.yaml +95 -0
- package/packages/server/mcp/heartbeat-patch.js +73 -0
- package/packages/server/mcp/mcp.server.js +63 -314
- package/packages/server/mcp/prompt.handler.js +26 -0
- package/packages/server/mcp/thinking-toolkit.handler.js +380 -0
- package/packages/server/package.json +35 -3
- package/packages/server/server.js +114 -12
- package/packages/server/services/TerminalService.js +498 -0
- package/packages/server/services/WebSocketService.js +484 -0
- package/packages/server/services/manager.js +38 -7
- package/packages/server/services/model.service.js +473 -0
- package/packages/server/services/optimization.service.js +457 -0
- package/packages/server/services/template.service.js +333 -0
- package/packages/server/toolm/tool-description-generator-optimized.service.js +5 -2
- package/packages/server/toolm/tool-sync.service.js +47 -3
- package/packages/server/utils/config.js +8 -1
- package/packages/server/utils/port-checker.js +63 -0
- package/packages/server/utils/util.js +27 -0
- package/IFLOW.md +0 -175
- package/app/desktop/assets/app.1.png +0 -0
- package/app/desktop/assets/app.png +0 -0
- package/app/desktop/assets/icons/icon.icns +0 -0
- package/app/desktop/assets/icons/icon.ico +0 -0
- package/app/desktop/assets/icons/icon.png +0 -0
- package/app/desktop/assets/icons/tray.png +0 -0
- package/app/desktop/assets/templates/about.html +0 -147
- package/app/desktop/assets/tray.1.png +0 -0
- package/app/desktop/assets/tray.png +0 -0
- package/app/desktop/main.js +0 -241
- package/app/desktop/package-lock.json +0 -4997
- package/app/desktop/package.json +0 -100
- package/app/desktop/preload.js +0 -7
- package/app/desktop/src/core/error-handler.js +0 -108
- package/app/desktop/src/core/event-emitter.js +0 -84
- package/app/desktop/src/core/logger.js +0 -108
- package/app/desktop/src/core/state-manager.js +0 -125
- package/app/desktop/src/services/module-loader.js +0 -214
- package/app/desktop/src/services/runtime-manager.js +0 -301
- package/app/desktop/src/services/service-manager.js +0 -169
- package/app/desktop/src/services/update-manager.js +0 -268
- package/app/desktop/src/ui/about-dialog-manager.js +0 -208
- package/app/desktop/src/ui/admin-window-manager.js +0 -757
- package/app/desktop/src/ui/splash-manager.js +0 -253
- package/app/desktop/src/ui/tray-manager.js +0 -186
- package/app/desktop/src/utils/icon-manager.js +0 -133
- package/app/desktop/src/utils/path-utils.js +0 -58
- package/app/desktop/src/utils/resource-paths.js +0 -49
- package/app/desktop/src/utils/resource-sync.js +0 -260
- package/app/desktop/src/utils/runtime-sync.js +0 -241
- package/app/desktop/src/utils/template-renderer.js +0 -284
- package/app/desktop/src/utils/version-utils.js +0 -59
- package/examples/prompts/developer/code-review.yaml +0 -32
- package/examples/prompts/developer/code_refactoring.yaml +0 -31
- package/examples/prompts/developer/doc-generator.yaml +0 -36
- package/examples/prompts/developer/error-code-fixer.yaml +0 -35
- package/examples/prompts/engineer/engineer-professional.yaml +0 -92
- package/examples/prompts/engineer/laowang-engineer.yaml +0 -132
- package/examples/prompts/engineer/nekomata-engineer.yaml +0 -123
- package/examples/prompts/engineer/ojousama-engineer.yaml +0 -124
- package/examples/prompts/generator/gen_3d_edu_webpage_html.yaml +0 -117
- package/examples/prompts/generator/gen_3d_webpage_html.yaml +0 -75
- package/examples/prompts/generator/gen_bento_grid_html.yaml +0 -112
- package/examples/prompts/generator/gen_html_web_page.yaml +0 -88
- package/examples/prompts/generator/gen_knowledge_card_html.yaml +0 -83
- package/examples/prompts/generator/gen_magazine_card_html.yaml +0 -82
- package/examples/prompts/generator/gen_mimeng_headline_title.yaml +0 -71
- package/examples/prompts/generator/gen_podcast_script.yaml +0 -69
- package/examples/prompts/generator/gen_prd_prototype_html.yaml +0 -175
- package/examples/prompts/generator/gen_summarize.yaml +0 -157
- package/examples/prompts/generator/gen_title.yaml +0 -119
- package/examples/prompts/generator/others/api_documentation.yaml +0 -32
- package/examples/prompts/generator/others/build_mcp_server.yaml +0 -26
- package/examples/prompts/generator/others/project_architecture.yaml +0 -31
- package/examples/prompts/generator/others/test_case_generator.yaml +0 -30
- package/examples/prompts/generator/others/writing_assistant.yaml +0 -72
- package/examples/prompts/recommend/human_3-0_growth_diagnostic_coach_prompt.yaml +0 -105
- package/examples/prompts/workflow/sixstep-workflow.yaml +0 -192
- package/packages/admin-ui/.babelrc +0 -3
- package/packages/admin-ui/admin.html +0 -412
- package/packages/admin-ui/css/codemirror-theme_xq-light.css +0 -43
- package/packages/admin-ui/css/codemirror.css +0 -344
- package/packages/admin-ui/css/main.css +0 -2592
- package/packages/admin-ui/css/recommended-prompts.css +0 -610
- package/packages/admin-ui/package-lock.json +0 -6981
- package/packages/admin-ui/package.json +0 -36
- package/packages/admin-ui/src/codemirror.js +0 -53
- package/packages/admin-ui/src/index.js +0 -3188
- package/packages/admin-ui/webpack.config.js +0 -76
- package/packages/server/toolm/test-tools.js +0 -264
- package/scripts/build-icons.js +0 -135
- package/scripts/build.sh +0 -57
- package/scripts/postinstall.js +0 -34
- package/scripts/surge/CNAME +0 -1
- package/scripts/surge/README.md +0 -47
- package/scripts/surge/package-lock.json +0 -34
- package/scripts/surge/package.json +0 -20
- package/scripts/surge/sync-to-surge.js +0 -151
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { templateManager } from './template.service.js';
|
|
2
|
+
import { modelManager } from './model.service.js';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 优化服务类
|
|
7
|
+
*/
|
|
8
|
+
class OptimizationService {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.sessionIterations = new Map(); // 会话级迭代追踪
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 优化提示词(支持流式)
|
|
15
|
+
* @param {string} prompt - 原始提示词
|
|
16
|
+
* @param {string} templateId - 模板ID
|
|
17
|
+
* @param {string} modelId - 模型ID
|
|
18
|
+
* @param {Function} onChunk - 流式输出回调函数
|
|
19
|
+
* @param {string} sessionId - 会话ID(用于迭代优化)
|
|
20
|
+
* @returns {Promise<Object>} 优化结果
|
|
21
|
+
*/
|
|
22
|
+
async optimizePrompt(prompt, templateId, modelId, onChunk, sessionId = null) {
|
|
23
|
+
try {
|
|
24
|
+
// 1. 加载模板
|
|
25
|
+
let template = templateManager.getTemplate(templateId);
|
|
26
|
+
if (!template) {
|
|
27
|
+
// 尝试获取第一个系统优化模板
|
|
28
|
+
template = templateManager.getTemplates().find(t => (t.type || 'optimize') === 'optimize');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!template) {
|
|
32
|
+
throw new Error(`未找到可用模板: ${templateId}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// 2. 加载模型配置
|
|
36
|
+
const model = modelManager.getModel(modelId);
|
|
37
|
+
if (!model) {
|
|
38
|
+
throw new Error(`模型不存在: ${modelId}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// 检查模型是否启用
|
|
42
|
+
if (model.enabled !== true) {
|
|
43
|
+
throw new Error(`模型未启用: ${model.name}`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 检查 API Key
|
|
47
|
+
if (!model.apiKey) {
|
|
48
|
+
throw new Error(`模型 ${model.name} 的 API Key 未配置`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 3. 构建优化消息列表
|
|
52
|
+
const messages = this.buildMessages(prompt, template);
|
|
53
|
+
|
|
54
|
+
logger.info(`开始优化提示词,使用模板: ${template.name},模型: ${model.name}`);
|
|
55
|
+
|
|
56
|
+
// 4. 调用 AI API(流式)
|
|
57
|
+
const result = await this.callAIModel(messages, model, onChunk);
|
|
58
|
+
|
|
59
|
+
// 5. 如果提供了 sessionId,记录迭代信息
|
|
60
|
+
if (sessionId) {
|
|
61
|
+
this.sessionIterations.set(sessionId, {
|
|
62
|
+
count: 1,
|
|
63
|
+
originalPrompt: prompt, // 记录原始提示词
|
|
64
|
+
lastResult: result,
|
|
65
|
+
lastTemplateId: templateId,
|
|
66
|
+
lastModelId: modelId
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
} catch (error) {
|
|
72
|
+
logger.error('优化提示词失败:', error);
|
|
73
|
+
throw error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 迭代优化(在当前结果基础上继续优化)
|
|
79
|
+
* @param {string} currentResult - 当前优化结果
|
|
80
|
+
* @param {string} templateId - 模板ID
|
|
81
|
+
* @param {string} modelId - 模型ID
|
|
82
|
+
* @param {Function} onChunk - 流式输出回调函数
|
|
83
|
+
* @param {string} sessionId - 会话ID
|
|
84
|
+
* @param {string} guideText - 优化指导(可选)
|
|
85
|
+
* @returns {Promise<Object>} 优化结果
|
|
86
|
+
*/
|
|
87
|
+
async iterateOptimization(currentResult, templateId, modelId, onChunk, sessionId, guideText = '') {
|
|
88
|
+
try {
|
|
89
|
+
// 检查会话是否存在
|
|
90
|
+
const session = this.sessionIterations.get(sessionId);
|
|
91
|
+
if (!session) {
|
|
92
|
+
throw new Error('会话不存在,请先进行初始优化');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 检查迭代次数限制(最多 10 次)
|
|
96
|
+
if (session.count >= 10) {
|
|
97
|
+
throw new Error('已达到最大迭代次数(10次)');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 1. 加载模板
|
|
101
|
+
let template = templateManager.getTemplate(templateId);
|
|
102
|
+
if (!template) {
|
|
103
|
+
// 尝试获取第一个迭代优化模板
|
|
104
|
+
template = templateManager.getTemplates().find(t => t.type === 'iterate');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!template) {
|
|
108
|
+
// 回退到简单迭代逻辑(如果没有迭代模板)
|
|
109
|
+
template = {
|
|
110
|
+
name: '默认迭代',
|
|
111
|
+
format: 'simple',
|
|
112
|
+
type: 'iterate',
|
|
113
|
+
content: '{{prompt}}'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 2. 加载模型配置
|
|
118
|
+
const model = modelManager.getModel(modelId);
|
|
119
|
+
if (!model) {
|
|
120
|
+
throw new Error(`模型不存在: ${modelId}`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 检查模型是否启用
|
|
124
|
+
if (model.enabled !== true) {
|
|
125
|
+
throw new Error(`模型未启用: ${model.name}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// 检查 API Key
|
|
129
|
+
if (!model.apiKey) {
|
|
130
|
+
throw new Error(`模型 ${model.name} 的 API Key 未配置`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 3. 构建迭代优化消息列表
|
|
134
|
+
const messages = this.buildIterationMessages(
|
|
135
|
+
currentResult,
|
|
136
|
+
session.lastResult,
|
|
137
|
+
template,
|
|
138
|
+
session.count,
|
|
139
|
+
guideText,
|
|
140
|
+
session.originalPrompt // 传入原始提示词
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
logger.info(`开始迭代优化(第 ${session.count + 1} 次),使用模板: ${template.name},模型: ${model.name}${guideText ? ',有优化指导' : ''}`);
|
|
144
|
+
|
|
145
|
+
// 4. 调用 AI API(流式)
|
|
146
|
+
const result = await this.callAIModel(messages, model, onChunk);
|
|
147
|
+
|
|
148
|
+
// 5. 更新会话信息
|
|
149
|
+
this.sessionIterations.set(sessionId, {
|
|
150
|
+
...session, // 保留 originalPrompt 等信息
|
|
151
|
+
count: session.count + 1,
|
|
152
|
+
lastResult: result,
|
|
153
|
+
lastTemplateId: templateId,
|
|
154
|
+
lastModelId: modelId
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
return result;
|
|
158
|
+
} catch (error) {
|
|
159
|
+
logger.error('迭代优化失败:', error);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 替换提示词内容中的变量
|
|
166
|
+
* @param {string} content - 提示词内容
|
|
167
|
+
* @param {Object} variables - 变量映射
|
|
168
|
+
* @returns {string} 替换后的内容
|
|
169
|
+
*/
|
|
170
|
+
replaceVariables(content, variables) {
|
|
171
|
+
if (!content || typeof content !== 'string') return content;
|
|
172
|
+
let result = content;
|
|
173
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
174
|
+
// 允许使用 {{key}} 或 {{ key }} 格式
|
|
175
|
+
const placeholder = new RegExp(`{{\\s*${key}\\s*}}`, 'g');
|
|
176
|
+
result = result.replace(placeholder, String(value ?? ''));
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* 构建消息列表
|
|
183
|
+
* @param {string} prompt - 原始提示词
|
|
184
|
+
* @param {Object} template - 模板对象
|
|
185
|
+
* @returns {Array} 消息列表
|
|
186
|
+
*/
|
|
187
|
+
buildMessages(prompt, template) {
|
|
188
|
+
if (template.format === 'advanced' && Array.isArray(template.content)) {
|
|
189
|
+
const variables = {
|
|
190
|
+
originalPrompt: prompt,
|
|
191
|
+
prompt: prompt, // 兼容旧模板
|
|
192
|
+
input: prompt // 兼容旧模板
|
|
193
|
+
};
|
|
194
|
+
return template.content.map(msg => ({
|
|
195
|
+
role: msg.role,
|
|
196
|
+
content: this.replaceVariables(msg.content, variables)
|
|
197
|
+
}));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 简单模板处理
|
|
201
|
+
const variables = { prompt };
|
|
202
|
+
let content = template.content;
|
|
203
|
+
if (typeof content !== 'string') {
|
|
204
|
+
content = JSON.stringify(content);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 如果模板中没有包含变量占位符,则自动追加
|
|
208
|
+
if (!content.includes('{{prompt}}') && !content.includes('{{input}}')) {
|
|
209
|
+
content += '\n\n请优化以下提示词:\n\n{{prompt}}';
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return [
|
|
213
|
+
{
|
|
214
|
+
role: 'user',
|
|
215
|
+
content: this.replaceVariables(content, variables)
|
|
216
|
+
}
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* 构建迭代消息列表
|
|
222
|
+
* @param {string} currentInput - 当前输入(界面上展示的待迭代内容)
|
|
223
|
+
* @param {string} previousResult - 上一次结果(会话记录)
|
|
224
|
+
* @param {Object} template - 模板对象
|
|
225
|
+
* @param {number} iterationCount - 迭代次数
|
|
226
|
+
* @param {string} guideText - 指导文字
|
|
227
|
+
* @param {string} originalPrompt - 最初的原始提示词
|
|
228
|
+
* @returns {Array} 消息列表
|
|
229
|
+
*/
|
|
230
|
+
buildIterationMessages(currentInput, previousResult, template, iterationCount, guideText = '', originalPrompt = '') {
|
|
231
|
+
if (template.format === 'advanced' && Array.isArray(template.content)) {
|
|
232
|
+
const variables = {
|
|
233
|
+
originalPrompt: originalPrompt || '',
|
|
234
|
+
lastOptimizedPrompt: currentInput, // 当前界面显示的结果即为“上一次优化结果”
|
|
235
|
+
iterateInput: guideText || '',
|
|
236
|
+
// 兼容别名
|
|
237
|
+
prompt: currentInput,
|
|
238
|
+
previousResult: previousResult || currentInput,
|
|
239
|
+
iterationCount: iterationCount + 1,
|
|
240
|
+
guideText: guideText || ''
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
return template.content.map(msg => ({
|
|
244
|
+
role: msg.role,
|
|
245
|
+
content: this.replaceVariables(msg.content, variables)
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 简单模板逻辑保持简单
|
|
250
|
+
const variables = {
|
|
251
|
+
prompt: currentInput,
|
|
252
|
+
previousResult: previousResult || currentInput,
|
|
253
|
+
iterationCount: iterationCount + 1,
|
|
254
|
+
guideText: guideText || ''
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
let content = template.content;
|
|
258
|
+
if (typeof content !== 'string') {
|
|
259
|
+
content = JSON.stringify(content);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 构建默认迭代上下文(如果模板是简单的且没有包含占位符)
|
|
263
|
+
let finalContent = '';
|
|
264
|
+
|
|
265
|
+
// 如果没有使用任何变量占位符,执行默认拼接逻辑
|
|
266
|
+
const hasVariables = ['{{prompt}}', '{{previousResult}}', '{{guideText}}']
|
|
267
|
+
.some(v => content.includes(v));
|
|
268
|
+
|
|
269
|
+
if (!hasVariables) {
|
|
270
|
+
if (!content.includes('{{previousResult}}')) {
|
|
271
|
+
finalContent += `这是第 ${variables.iterationCount} 次优化。上一次的优化结果如下:\n\n${variables.previousResult}\n\n`;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (guideText && !content.includes('{{guideText}}')) {
|
|
275
|
+
finalContent += `本次优化的具体要求:\n${guideText}\n\n`;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
finalContent += `请基于以上上下文,继续优化以下内容:\n\n{{prompt}}`;
|
|
279
|
+
} else {
|
|
280
|
+
finalContent = content;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return [
|
|
284
|
+
{
|
|
285
|
+
role: 'user',
|
|
286
|
+
content: this.replaceVariables(finalContent, variables)
|
|
287
|
+
}
|
|
288
|
+
];
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* 调用 AI 模型(支持流式)
|
|
293
|
+
* @param {Array} messages - 消息列表
|
|
294
|
+
* @param {Object} model - 模型配置
|
|
295
|
+
* @param {Function} onChunk - 流式输出回调函数
|
|
296
|
+
* @returns {Promise<string>} 完整的响应内容
|
|
297
|
+
*/
|
|
298
|
+
async callAIModel(messages, model, onChunk) {
|
|
299
|
+
try {
|
|
300
|
+
// 记录请求日志
|
|
301
|
+
logger.info(`[AI Request] 模型: ${model.name}, 消息数: ${messages.length}`);
|
|
302
|
+
messages.forEach((msg, i) => {
|
|
303
|
+
logger.debug(`[Message ${i}] Role: ${msg.role}, Content: ${msg.content.substring(0, 1000)}${msg.content.length > 1000 ? '...' : ''}`);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// 构建 API 请求
|
|
307
|
+
const requestBody = {
|
|
308
|
+
model: model.model,
|
|
309
|
+
messages,
|
|
310
|
+
stream: true
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const headers = {
|
|
314
|
+
'Content-Type': 'application/json',
|
|
315
|
+
}
|
|
316
|
+
if (model.apiKey) {
|
|
317
|
+
headers['Authorization'] = `Bearer ${model.apiKey}`;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// 发起请求
|
|
321
|
+
const response = await fetch(model.apiEndpoint, {
|
|
322
|
+
method: 'POST',
|
|
323
|
+
headers: headers,
|
|
324
|
+
body: JSON.stringify(requestBody)
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
if (!response.ok) {
|
|
328
|
+
const errorText = await response.text();
|
|
329
|
+
let errorDetail = errorText;
|
|
330
|
+
try {
|
|
331
|
+
const errorJson = JSON.parse(errorText);
|
|
332
|
+
if (errorJson.error && errorJson.error.message) {
|
|
333
|
+
errorDetail = errorJson.error.message;
|
|
334
|
+
} else if (errorJson.message) {
|
|
335
|
+
errorDetail = errorJson.message;
|
|
336
|
+
}
|
|
337
|
+
} catch (e) {
|
|
338
|
+
// 如果不是 JSON,限制长度
|
|
339
|
+
if (errorDetail.length > 200) {
|
|
340
|
+
errorDetail = errorDetail.substring(0, 200) + '...';
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
throw new Error(`API 请求失败 (${response.status} ${response.statusText}): ${errorDetail}`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// 处理流式响应
|
|
347
|
+
const reader = response.body.getReader();
|
|
348
|
+
const decoder = new TextDecoder();
|
|
349
|
+
let fullContent = '';
|
|
350
|
+
|
|
351
|
+
while (true) {
|
|
352
|
+
const { done, value } = await reader.read();
|
|
353
|
+
|
|
354
|
+
if (done) {
|
|
355
|
+
break;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// 解码数据
|
|
359
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
360
|
+
|
|
361
|
+
// 解析 SSE 格式数据
|
|
362
|
+
const lines = chunk.split('\n');
|
|
363
|
+
|
|
364
|
+
for (const line of lines) {
|
|
365
|
+
if (line.startsWith('data: ')) {
|
|
366
|
+
const data = line.slice(6);
|
|
367
|
+
|
|
368
|
+
if (data === '[DONE]') {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
try {
|
|
373
|
+
const parsed = JSON.parse(data);
|
|
374
|
+
|
|
375
|
+
// 提取内容
|
|
376
|
+
if (parsed.choices && parsed.choices[0] && parsed.choices[0].delta) {
|
|
377
|
+
const content = parsed.choices[0].delta.content;
|
|
378
|
+
|
|
379
|
+
if (content) {
|
|
380
|
+
fullContent += content;
|
|
381
|
+
|
|
382
|
+
// 调用回调函数
|
|
383
|
+
if (onChunk) {
|
|
384
|
+
onChunk(content);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
} catch (error) {
|
|
389
|
+
// logger.warn('解析 SSE 数据失败:', error.message);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
logger.info(`AI 模型调用完成,返回 ${fullContent.length} 个字符`);
|
|
396
|
+
logger.debug(`[AI Response] Content: ${fullContent.substring(0, 5000)}${fullContent.length > 5000 ? '...' : ''}`);
|
|
397
|
+
return fullContent;
|
|
398
|
+
} catch (error) {
|
|
399
|
+
logger.error('调用 AI 模型失败:', error);
|
|
400
|
+
throw error;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* 清除会话迭代信息
|
|
406
|
+
* @param {string} sessionId - 会话ID
|
|
407
|
+
*/
|
|
408
|
+
clearSession(sessionId) {
|
|
409
|
+
this.sessionIterations.delete(sessionId);
|
|
410
|
+
logger.debug(`清除会话迭代信息: ${sessionId}`);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* 获取会话迭代信息
|
|
415
|
+
* @param {string} sessionId - 会话ID
|
|
416
|
+
* @returns {Object|null} 会话信息
|
|
417
|
+
*/
|
|
418
|
+
getSessionInfo(sessionId) {
|
|
419
|
+
return this.sessionIterations.get(sessionId) || null;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* 测试模型连接
|
|
424
|
+
* @param {string} modelId - 模型ID
|
|
425
|
+
* @returns {Promise<Object>} 测试结果
|
|
426
|
+
*/
|
|
427
|
+
async testModel(modelId) {
|
|
428
|
+
try {
|
|
429
|
+
const model = modelManager.getModel(modelId);
|
|
430
|
+
if (!model) {
|
|
431
|
+
throw new Error(`模型不存在: ${modelId}`);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// 发送一个简单的测试请求
|
|
435
|
+
const messages = [{ role: 'user', content: '请回复"测试成功"' }];
|
|
436
|
+
const result = await this.callAIModel(messages, model, null);
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
success: true,
|
|
440
|
+
message: '模型连接测试成功',
|
|
441
|
+
response: result
|
|
442
|
+
};
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return {
|
|
445
|
+
success: false,
|
|
446
|
+
message: `模型连接测试失败: ${error.message}`,
|
|
447
|
+
error: error.message
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// 创建全局OptimizationService实例
|
|
454
|
+
export const optimizationService = new OptimizationService();
|
|
455
|
+
|
|
456
|
+
// 导出OptimizationService类供测试使用
|
|
457
|
+
export { OptimizationService };
|