doomiaichat 7.1.9 → 7.1.11

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/dist/corzbot.d.ts CHANGED
@@ -8,10 +8,10 @@ import { ApiResult } from './declare';
8
8
  export default class CorzBot extends GptBase {
9
9
  private authorizationProvider;
10
10
  private setting;
11
- protected botid: string;
12
- protected workflowid: string;
11
+ private botid;
12
+ private workflowid;
13
+ private talkflowid;
13
14
  private apiKey;
14
- private lastThinkingMessage;
15
15
  /**
16
16
  *
17
17
  * @param apikey 调用AI中台 的key
@@ -23,6 +23,11 @@ export default class CorzBot extends GptBase {
23
23
  * 发起一次会话
24
24
  */
25
25
  createCoversation(client?: CozeAPI): Promise<string | null>;
26
+ /**
27
+ * 设置Coze的变量
28
+ * @param params
29
+ * @returns
30
+ */
26
31
  setVariables(params: any): Promise<ApiResult>;
27
32
  /**
28
33
  * 获取设置的变量
@@ -50,6 +55,13 @@ export default class CorzBot extends GptBase {
50
55
  * @param _axiosOption
51
56
  */
52
57
  chatRequest(message: any[] | string, callChatOption?: any, _axiosOption?: any): Promise<any>;
58
+ /**
59
+ * 提取XML标签中间的内容,
60
+ * @param xmlStr
61
+ * @param tagName
62
+ * @returns
63
+ */
64
+ extractXmlContent(xmlStr: string, tagName: string): string;
53
65
  /**
54
66
  * 解析深度思考的JSON内容
55
67
  * @param content
package/dist/corzbot.js CHANGED
@@ -25,23 +25,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
25
25
  const api_1 = require("@coze/api");
26
26
  const gptbase_1 = __importDefault(require("./gptbase"));
27
27
  const querystring_1 = require("querystring");
28
- // 定义深度思考的动作
29
- var DeepThinkingAction;
30
- (function (DeepThinkingAction) {
31
- DeepThinkingAction["process"] = "process_msg";
32
- DeepThinkingAction["content"] = "reasoning_content";
33
- DeepThinkingAction["card"] = "card_resource";
34
- })(DeepThinkingAction || (DeepThinkingAction = {}));
28
+ // 定义深度思考的动作标签
29
+ // 这是小鹭里面专用的几个思考动作标签
30
+ const DeepThinkingAction = {
31
+ thinking: { start: '<xiaolu-think>', end: '</xiaolu-think>', tag: 'xiaolu-think' },
32
+ reasoning: { start: '<xiaolu-reason>', end: '</xiaolu-reason>', tag: 'xiaolu-reason' },
33
+ card: { start: '<xiaolu-card>', end: '</xiaolu-card>', tag: 'xiaolu-card' },
34
+ };
35
35
  // 定义深度思考的状态
36
36
  var DeepThinkingStatus;
37
37
  (function (DeepThinkingStatus) {
38
38
  DeepThinkingStatus[DeepThinkingStatus["None"] = 0] = "None";
39
39
  DeepThinkingStatus[DeepThinkingStatus["Thinking"] = 1] = "Thinking";
40
- DeepThinkingStatus[DeepThinkingStatus["ContentOutput"] = 2] = "ContentOutput";
41
- DeepThinkingStatus[DeepThinkingStatus["ThinkingOver"] = 3] = "ThinkingOver";
40
+ // ContentOutput,
41
+ DeepThinkingStatus[DeepThinkingStatus["ThinkingOver"] = 2] = "ThinkingOver";
42
42
  })(DeepThinkingStatus || (DeepThinkingStatus = {}));
43
+ // type TThinkingMessage = { action: string, textposition: number }
43
44
  class CorzBot extends gptbase_1.default {
44
- // protected client: CozeAPI;
45
45
  /**
46
46
  *
47
47
  * @param apikey 调用AI中台 的key
@@ -51,10 +51,18 @@ class CorzBot extends gptbase_1.default {
51
51
  super();
52
52
  this.authorizationProvider = authorizationProvider;
53
53
  this.setting = setting;
54
- this.lastThinkingMessage = { action: '', textposition: 0 };
54
+ this.botid = null; // 智能体id
55
+ this.workflowid = null; // 工作流id
56
+ this.talkflowid = null; // 对话流id
55
57
  ////初始化扣子客户端
56
- this.botid = this.setting['botid'] || this.setting['botID'];
57
- this.workflowid = this.setting['workflowid'];
58
+ if (this.setting.workflowid)
59
+ this.workflowid = this.setting.workflowid;
60
+ else if (this.setting.talkflowid)
61
+ this.talkflowid = this.setting.talkflowid;
62
+ else if (this.setting.botid || this.setting.botID)
63
+ this.botid = this.setting.botid || this.setting.botID;
64
+ else
65
+ throw new Error('no botid or talkflowid or workflowid setting for coze');
58
66
  this.apiKey = this.setting['apiKey'];
59
67
  }
60
68
  createClient() {
@@ -85,6 +93,11 @@ class CorzBot extends gptbase_1.default {
85
93
  }
86
94
  });
87
95
  }
96
+ /**
97
+ * 设置Coze的变量
98
+ * @param params
99
+ * @returns
100
+ */
88
101
  setVariables(params) {
89
102
  return __awaiter(this, void 0, void 0, function* () {
90
103
  const client = yield this.createClient();
@@ -115,27 +128,38 @@ class CorzBot extends gptbase_1.default {
115
128
  * @param _axiosOption
116
129
  */
117
130
  getRequestStream(client, message, callChatOption = {}) {
118
- var _a;
131
+ var _a, _b;
119
132
  return __awaiter(this, void 0, void 0, function* () {
120
133
  //简单的对话请求
121
134
  const conversation_id = (_a = callChatOption.session_id) !== null && _a !== void 0 ? _a : yield this.createCoversation(client);
122
- if (!this.workflowid) {
135
+ if (this.botid) {
123
136
  const req = {
124
137
  bot_id: this.botid,
125
138
  additional_messages: message,
126
139
  user_id: callChatOption.userid || callChatOption.cozeUserID,
127
- conversation_id
140
+ conversation_id,
141
+ parameters: Object.assign({ request_src: 1 }, callChatOption.parameters || {}),
128
142
  };
129
143
  req.custom_variables = Object.assign({}, this.setting.customVariables || {}, callChatOption.customVariables || {});
130
144
  return req;
131
145
  }
146
+ if (this.workflowid) {
147
+ const worflowreq = {
148
+ ext: callChatOption.ext,
149
+ workflow_id: this.workflowid,
150
+ is_async: false,
151
+ // parameters: Object.assign({ input: message[0]?.content }, this.setting.customVariables || {}, callChatOption.customVariables || {}),
152
+ parameters: Object.assign({ request_src: 1 }, callChatOption.parameters || {}, { input: (_b = message[0]) === null || _b === void 0 ? void 0 : _b.content })
153
+ };
154
+ return worflowreq;
155
+ }
132
156
  const worflowreq = {
133
- bot_id: this.botid,
134
157
  additional_messages: message,
135
158
  ext: callChatOption.ext,
136
- workflow_id: this.workflowid,
159
+ workflow_id: this.talkflowid,
137
160
  conversation_id,
138
- parameters: Object.assign({}, this.setting.customVariables || {}, callChatOption.customVariables || {}),
161
+ parameters: Object.assign({ request_src: 1 }, callChatOption.parameters || {}) //Object.assign({}, this.setting.customVariables || {}, callChatOption.customVariables || {}),
162
+ //parameters: { input: message[0]?.content }
139
163
  };
140
164
  return worflowreq;
141
165
  });
@@ -182,7 +206,7 @@ class CorzBot extends gptbase_1.default {
182
206
  ////如果参数中用的是Workflow,则调用对话流来输出结果
183
207
  ////否则用智能体的对话来输出结果
184
208
  const params = yield this.getRequestStream(client, message, callChatOption);
185
- const response = !this.workflowid ? yield client.chat.create(params) : yield client.workflows.runs.create(params);
209
+ const response = this.botid ? yield client.chat.create(params) : yield client.workflows.runs.create(params);
186
210
  if (this.workflowid && response.msg === 'Success') {
187
211
  const resp = response.data;
188
212
  try {
@@ -207,68 +231,57 @@ class CorzBot extends gptbase_1.default {
207
231
  return { successed: false, error: { message: '聊天未完成' } };
208
232
  });
209
233
  }
234
+ /**
235
+ * 提取XML标签中间的内容,
236
+ * @param xmlStr
237
+ * @param tagName
238
+ * @returns
239
+ */
240
+ extractXmlContent(xmlStr, tagName) {
241
+ // 构建匹配标签的正则(支持任意空白字符和大小写)
242
+ const regex = new RegExp(`<\\s*${tagName}\\s*>([\\s\\S]*?)<\\s*\\/\\s*${tagName}\\s*>`, 'i');
243
+ const match = xmlStr.match(regex);
244
+ if (match && match[1])
245
+ return match[1].trim();
246
+ return ''; // 未找到标签或内容
247
+ }
210
248
  /**
211
249
  * 解析深度思考的JSON内容
212
250
  * @param content
213
251
  * @param status
214
252
  * @returns
215
253
  */
216
- parseDeepThinkingJson(content, status) {
254
+ parseDeepThinkingJson(content) {
217
255
  // const thinkingStartIndex = status === DeepThinkingStatus.Thinking ? content.indexOf("{\"process_msg") :
218
256
  // (status===DeepThinkingStatus.ReasonOutput ? content.indexOf("{\"reasoning_content") : content.indexOf("{\"card_resource")) ;
219
- const tagLocation = [content.indexOf("{\"process_msg"),
220
- content.indexOf("{\"reasoning_content"),
221
- content.indexOf("{\"card_resource")].filter(x => x >= 0);
222
- const thinkingStartIndex = tagLocation.length > 0 ? Math.min(...tagLocation) : -1;
223
- const thinkingEndIndex = content.indexOf("\"}");
224
- // 如果没有找到相关的JSON内容,则直接返回
225
- if (thinkingStartIndex < 0)
226
- return { successed: true, content, status: DeepThinkingStatus.ThinkingOver };
227
- let jsonStr = null;
228
- try {
229
- jsonStr = content.substring(thinkingStartIndex, thinkingEndIndex >= 0 ? thinkingEndIndex : undefined) + "\"}";
230
- // 转换JSON的时候需要将非法字符过滤掉
231
- const thinkingObject = JSON.parse(jsonStr.replace(/[\x00-\x1F\x7F]/g, ''));
232
- const thinkingAction = Object.keys(thinkingObject)[0];
233
- // 需要将内容的原文返回
234
- const originalContent = jsonStr.split('":"')[1];
235
- // 如果正确的解析JSON,并且当前有包含JSON结束的字符,则把当前思考的JSON内容替换掉
236
- if (thinkingEndIndex >= 0)
237
- content = content.substring(thinkingEndIndex + 2);
238
- // 如果正常输出了卡片资源,并且json结束 card_resource 只有一个,所以一旦结束,则整个思考过程完毕
239
- // if (status === DeepThinkingStatus.ContentOutput && thinkingEndIndex >= 0) status = DeepThinkingStatus.ThinkingOver;
240
- // 判断整个思考过程是否到达等待卡片资源(有可能智能体输出不了卡片资源) reasoning_content 只有一个,所以一旦结束,则进入下一个阶段 card_resource
241
- //if (status === DeepThinkingStatus.ContentOutput && thinkingEndIndex >= 0) status = DeepThinkingStatus.ContentOutput;
242
- // 判断当前是否从前期思考切换到思考内容输出
243
- if (status === DeepThinkingStatus.Thinking && thinkingAction !== DeepThinkingAction.process)
244
- status = DeepThinkingStatus.ContentOutput;
245
- //if (status === DeepThinkingStatus.Thinking && content.indexOf("{\"reasoning_content") >= 0) status=DeepThinkingStatus.ReasonOutput;
246
- //const removeOutputContent = content.replace(originalContent!.substring(1, originalContent!.length - 2),"")
247
- let thinkingContent = originalContent === null || originalContent === void 0 ? void 0 : originalContent.substring(0, originalContent.length - 2);
248
- const outputLength = (thinkingContent === null || thinkingContent === void 0 ? void 0 : thinkingContent.length) || 0;
249
- // 用lastThinkingMessage来记录上一次的思考内容,避免重复输出内容,导致的网络传输内容过多
250
- if (this.lastThinkingMessage.action === thinkingAction && this.lastThinkingMessage.textposition) {
251
- thinkingContent = thinkingContent.substring(this.lastThinkingMessage.textposition);
257
+ const xmlTagLocation = [content.indexOf(DeepThinkingAction.thinking.start),
258
+ content.indexOf(DeepThinkingAction.reasoning.start),
259
+ content.indexOf(DeepThinkingAction.card.start)];
260
+ let minLocation = 10000, minIndex = -1;
261
+ // 找到最小的并且大于0 的位置的下标
262
+ xmlTagLocation.forEach((x, index) => {
263
+ if (x >= 0 && x < minLocation) {
264
+ minLocation = x;
265
+ minIndex = index;
252
266
  }
253
- this.lastThinkingMessage = thinkingEndIndex >= 0 ? { action: thinkingAction, textposition: 0 } : { action: thinkingAction, textposition: outputLength };
254
- return {
255
- successed: true, thinking: {
256
- action: thinkingAction,
257
- text: thinkingContent,
258
- completed: thinkingEndIndex >= 0
259
- }, content, status
260
- };
261
- }
262
- catch (error) {
263
- // 如果在content之后发生了错误,可能该智能体输出不了卡片类型的数据,则输出的内容已经是正文了
264
- if (status === DeepThinkingStatus.ContentOutput) {
265
- status = DeepThinkingStatus.ThinkingOver;
266
- return { successed: true, content, status };
267
- }
268
- console.error('解析JSON出错了:', jsonStr, status);
269
- // 当前解析出错,等待下一次解析
270
- return { successed: false, content, status };
271
- }
267
+ });
268
+ // const tagLocation = xmlTagLocation.filter(x => x >= 0);
269
+ const thinkingStartIndex = minIndex >= 0 ? minLocation : -1; //tagLocation.length > 0 ? Math.min(...tagLocation) : -1;
270
+ if (thinkingStartIndex < 0)
271
+ return { content, status: DeepThinkingStatus.ThinkingOver };
272
+ const currentAction = [DeepThinkingAction.thinking, DeepThinkingAction.reasoning, DeepThinkingAction.card][minIndex];
273
+ const currentActionIsOver = content.indexOf(currentAction.end, thinkingStartIndex);
274
+ const thinkingEndIndex = currentActionIsOver >= 0 ? currentActionIsOver : content.indexOf('</', thinkingStartIndex);
275
+ const thinkingContent = this.extractXmlContent(content.substring(thinkingStartIndex, thinkingEndIndex >= 0 ? thinkingEndIndex : undefined) + currentAction.end, currentAction.tag); //"\"}";
276
+ if (currentActionIsOver >= 0)
277
+ content = content.substring(currentActionIsOver + currentAction.end.length);
278
+ return {
279
+ thinking: {
280
+ action: currentAction,
281
+ text: thinkingContent,
282
+ completed: currentActionIsOver >= 0
283
+ }, content
284
+ };
272
285
  }
273
286
  /**
274
287
  * 流式传输聊天请求
@@ -280,6 +293,7 @@ class CorzBot extends gptbase_1.default {
280
293
  */
281
294
  chatRequestInStream(message, callChatOption = {}, attach, _axiosOption) {
282
295
  var _a, e_1, _b, _c;
296
+ var _d, _e, _f;
283
297
  return __awaiter(this, void 0, void 0, function* () {
284
298
  if (!message)
285
299
  this.emit('chaterror', { successed: false, error: 'no message in chat' });
@@ -297,56 +311,59 @@ class CorzBot extends gptbase_1.default {
297
311
  ////否则用智能体的对话来输出结果
298
312
  let requestid = Math.ceil(Math.random() * (new Date().getTime() * Math.random()) / 1000), index = 0;
299
313
  const params = yield this.getRequestStream(client, message, callChatOption);
300
- const stream = !this.workflowid ? client.chat.stream(params) : client.workflows.runs.stream(params);
314
+ const stream = this.botid ? client.chat.stream(params) :
315
+ (this.workflowid ? client.workflows.runs.stream(params) :
316
+ client.workflows.chat.stream(params));
301
317
  let deltaindex = 0, fullanswer = [], followup = [], cardData = [];
302
318
  let deepThinking = '', thinkingStatus = DeepThinkingStatus.None, cardResource = ''; // 是否在深度思考中
303
319
  try {
304
- for (var _d = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = yield stream_1.next(), _a = stream_1_1.done, !_a;) {
320
+ for (var _g = true, stream_1 = __asyncValues(stream), stream_1_1; stream_1_1 = yield stream_1.next(), _a = stream_1_1.done, !_a;) {
305
321
  _c = stream_1_1.value;
306
- _d = false;
322
+ _g = false;
307
323
  try {
308
324
  const part = _c;
309
325
  if (part.event === api_1.ChatEventType.ERROR)
310
326
  return this.emit('chaterror', { successed: false, error: 'call failed' });
311
- if (part.event === api_1.ChatEventType.CONVERSATION_MESSAGE_DELTA) {
312
- let { conversation_id, content_type, type, role, content } = part.data;
327
+ if (part.event === api_1.ChatEventType.CONVERSATION_MESSAGE_DELTA ||
328
+ part.event === api_1.WorkflowEventType.MESSAGE) {
329
+ let { conversation_id, content_type, type = 'answer', role = 'assistant', content, reasoning_content: reasoning } = part.data;
330
+ if (!content && reasoning) {
331
+ this.emit('chatthinking', { text: reasoning, completed: false, action: 'deep-thinking' });
332
+ continue;
333
+ }
313
334
  // 如果存在深度思考,则一开始就会带有相关的关键信息
314
- if (deltaindex === 0 && content.startsWith("{\"process_msg")) {
335
+ if (deltaindex === 0 && content.startsWith("<xiaolu-")) {
315
336
  thinkingStatus = DeepThinkingStatus.Thinking;
316
337
  deltaindex++;
317
338
  }
318
339
  // 如果在深度思考中,则不输出消息
319
- if (thinkingStatus !== DeepThinkingStatus.None
320
- && thinkingStatus !== DeepThinkingStatus.ThinkingOver) {
340
+ if (thinkingStatus === DeepThinkingStatus.Thinking) {
321
341
  deepThinking += content;
322
- const result = this.parseDeepThinkingJson(deepThinking, thinkingStatus);
323
- if (result.successed) {
324
- const thinking = result.thinking;
325
- if (thinking) {
326
- deepThinking = result.content;
327
- if (thinking.action === DeepThinkingAction.card) {
328
- cardResource += result.thinking.text;
329
- // 卡片流结束,解析卡片资源数据
330
- if (result.thinking.completed) {
331
- const allCards = cardResource.replace(/[\x00-\x1F\x7F]/g, '').split('|');
332
- for (const item of allCards) {
333
- const cardinfo = (0, querystring_1.parse)(item);
334
- if (cardinfo.type && cardinfo.tag)
335
- cardData.push({ type: Number(cardinfo.type), tag: cardinfo.tag });
336
- }
337
- // 将卡片资源返回给客户端
338
- this.emit('chatcard', cardData);
342
+ const result = this.parseDeepThinkingJson(deepThinking);
343
+ const thinking = result.thinking;
344
+ if (thinking) {
345
+ deepThinking = result.content;
346
+ if (thinking.action === DeepThinkingAction.card) {
347
+ cardResource += result.thinking.text;
348
+ // 卡片流结束,解析卡片资源数据
349
+ if (result.thinking.completed) {
350
+ const allCards = cardResource.replace(/[\x00-\x1F\x7F]/g, '').split('|');
351
+ for (const item of allCards) {
352
+ const cardinfo = (0, querystring_1.parse)(item);
353
+ if (cardinfo.type && cardinfo.tag)
354
+ cardData.push({ type: Number(cardinfo.type), tag: cardinfo.tag });
339
355
  }
356
+ // 将卡片资源返回给客户端
357
+ this.emit('chatcard', cardData);
340
358
  }
341
- else {
342
- this.emit('chatthinking', result.thinking);
343
- }
344
359
  }
345
- thinkingStatus = result.status;
360
+ else {
361
+ this.emit('chatthinking', { text: result.thinking.text, completed: result.thinking.completed, action: (_d = thinking.action) === null || _d === void 0 ? void 0 : _d.tag });
362
+ }
346
363
  }
347
- if (thinkingStatus != DeepThinkingStatus.ThinkingOver)
364
+ if (result.status != DeepThinkingStatus.ThinkingOver)
348
365
  continue;
349
- // thinkingStatus = DeepThinkingStatus.None;
366
+ thinkingStatus = DeepThinkingStatus.ThinkingOver;
350
367
  // 将排除了thinking之后的消息内容要带下去成为正式的输出内容
351
368
  content = deepThinking;
352
369
  }
@@ -358,28 +375,29 @@ class CorzBot extends gptbase_1.default {
358
375
  }
359
376
  ////在流式传输中,提取相关推荐问题
360
377
  if (part.event === api_1.ChatEventType.CONVERSATION_MESSAGE_COMPLETED) {
361
- const { type, content } = part.data;
378
+ const { type, content } = (_e = part.data) !== null && _e !== void 0 ? _e : {};
362
379
  if (type === 'follow_up')
363
380
  followup.push(content);
364
381
  }
365
382
  ///整个对话结束
366
- if (part.event === api_1.ChatEventType.CONVERSATION_CHAT_COMPLETED) {
367
- const { conversation_id } = part.data;
368
- let output = { successed: true, cards: cardData.length ? cardData : null, followup, type: 'answer', content_type: 'text', role: api_1.RoleType.Assistant, requestid, segment: null, text: fullanswer.join(''), index: index++, session_id: conversation_id };
383
+ if (part.event === api_1.ChatEventType.CONVERSATION_CHAT_COMPLETED ||
384
+ part.event === api_1.WorkflowEventType.DONE) {
385
+ const { conversation_id, content } = (_f = (part.data)) !== null && _f !== void 0 ? _f : {};
386
+ let output = { successed: true, cards: cardData.length ? cardData : null, followup, type: 'answer', content_type: 'text', role: api_1.RoleType.Assistant, requestid, segment: null, text: content !== null && content !== void 0 ? content : fullanswer.join(''), index: index++, session_id: conversation_id };
369
387
  if (attach)
370
388
  output = Object.assign({}, output, attach);
371
389
  this.emit('chatdone', output);
372
390
  }
373
391
  }
374
392
  finally {
375
- _d = true;
393
+ _g = true;
376
394
  }
377
395
  }
378
396
  }
379
397
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
380
398
  finally {
381
399
  try {
382
- if (!_d && !_a && (_b = stream_1.return)) yield _b.call(stream_1);
400
+ if (!_g && !_a && (_b = stream_1.return)) yield _b.call(stream_1);
383
401
  }
384
402
  finally { if (e_1) throw e_1.error; }
385
403
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doomiaichat",
3
- "version": "7.1.9",
3
+ "version": "7.1.11",
4
4
  "description": "Doomisoft OpenAI",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
package/src/corzbot.ts CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  RoleType,
9
9
  StreamChatReq,
10
10
  EnterMessage,
11
- ChatWorkflowReq,
11
+ // ChatWorkflowReq,
12
12
  // CreateChatReq,
13
13
  // ChatStatus,
14
14
  VariableUpdateReq,
@@ -17,35 +17,37 @@ import {
17
17
  RunWorkflowReq,
18
18
  RunWorkflowData,
19
19
  CreateChatData,
20
- ChatStatus
20
+ ChatStatus,
21
+ WorkflowEventType,
22
+ ChatWorkflowReq
21
23
  } from '@coze/api';
22
24
  import GptBase from "./gptbase"
23
25
  import { CorzAuthorization } from './corzauthorization';
24
26
  import { parse } from 'querystring'
25
27
  import { ApiResult } from './declare';
26
28
 
27
- // 定义深度思考的动作
28
- enum DeepThinkingAction {
29
- process = 'process_msg',
30
- content = 'reasoning_content',
31
- card = 'card_resource'
29
+ // 定义深度思考的动作标签
30
+ // 这是小鹭里面专用的几个思考动作标签
31
+ const DeepThinkingAction: any = {
32
+ thinking: { start: '<xiaolu-think>', end: '</xiaolu-think>', tag: 'xiaolu-think' },
33
+ reasoning: { start: '<xiaolu-reason>', end: '</xiaolu-reason>', tag: 'xiaolu-reason' },
34
+ card: { start: '<xiaolu-card>', end: '</xiaolu-card>', tag: 'xiaolu-card' },
32
35
  }
33
36
  // 定义深度思考的状态
34
37
  enum DeepThinkingStatus {
35
38
  None,
36
39
  Thinking,
37
- ContentOutput,
40
+ // ContentOutput,
38
41
  ThinkingOver
39
42
  }
40
43
  // 智能体思考时输出的动作
41
44
  type CardType = { type: number, tag: string }
42
- type TThinkingMessage = { action: string, textposition: number }
45
+ // type TThinkingMessage = { action: string, textposition: number }
43
46
  export default class CorzBot extends GptBase {
44
- protected botid: string;
45
- protected workflowid: string;
47
+ private botid: string | null = null; // 智能体id
48
+ private workflowid: string | null = null; // 工作流id
49
+ private talkflowid: string | null = null; // 对话流id
46
50
  private apiKey: string;
47
- private lastThinkingMessage: TThinkingMessage = { action: '', textposition: 0 };
48
- // protected client: CozeAPI;
49
51
  /**
50
52
  *
51
53
  * @param apikey 调用AI中台 的key
@@ -54,8 +56,15 @@ export default class CorzBot extends GptBase {
54
56
  constructor(private authorizationProvider: CorzAuthorization, private setting: any = {}) {
55
57
  super();
56
58
  ////初始化扣子客户端
57
- this.botid = this.setting['botid'] || this.setting['botID'];
58
- this.workflowid = this.setting['workflowid'];
59
+
60
+ if (this.setting.workflowid)
61
+ this.workflowid = this.setting.workflowid;
62
+ else if (this.setting.talkflowid)
63
+ this.talkflowid = this.setting.talkflowid;
64
+ else if (this.setting.botid || this.setting.botID)
65
+ this.botid = this.setting.botid || this.setting.botID;
66
+ else
67
+ throw new Error('no botid or talkflowid or workflowid setting for coze');
59
68
  this.apiKey = this.setting['apiKey'];
60
69
  }
61
70
  private async createClient(): Promise<CozeAPI> {
@@ -79,7 +88,11 @@ export default class CorzBot extends GptBase {
79
88
  return null;
80
89
  }
81
90
  }
82
-
91
+ /**
92
+ * 设置Coze的变量
93
+ * @param params
94
+ * @returns
95
+ */
83
96
  override async setVariables(params: any): Promise<ApiResult> {
84
97
  const client = await this.createClient();
85
98
  const cozeParams: VariableUpdateReq = Object.assign({}, this.botid ? { bot_id: this.botid } : {}, params);
@@ -107,23 +120,34 @@ export default class CorzBot extends GptBase {
107
120
  async getRequestStream<T>(client: CozeAPI, message: EnterMessage[], callChatOption: any = {}): Promise<T> {
108
121
  //简单的对话请求
109
122
  const conversation_id = callChatOption.session_id ?? await this.createCoversation(client);
110
- if (!this.workflowid) {
123
+ if (this.botid) {
111
124
  const req: StreamChatReq = {
112
125
  bot_id: this.botid,
113
126
  additional_messages: message,
114
127
  user_id: callChatOption.userid || callChatOption.cozeUserID,
115
- conversation_id
128
+ conversation_id,
129
+ parameters: Object.assign({ request_src:1 }, callChatOption.parameters || {}),
116
130
  }
117
131
  req.custom_variables = Object.assign({}, this.setting.customVariables || {}, callChatOption.customVariables || {});
118
132
  return req as T;
119
133
  }
134
+ if (this.workflowid){
135
+ const worflowreq: RunWorkflowReq = {
136
+ ext: callChatOption.ext,
137
+ workflow_id: this.workflowid,//callChatOption.workflowid,
138
+ is_async: false,
139
+ // parameters: Object.assign({ input: message[0]?.content }, this.setting.customVariables || {}, callChatOption.customVariables || {}),
140
+ parameters: Object.assign({ request_src :1},callChatOption.parameters || {}, { input: message[0]?.content})
141
+ }
142
+ return worflowreq as T;
143
+ }
120
144
  const worflowreq: ChatWorkflowReq = {
121
- bot_id: this.botid,
122
145
  additional_messages: message,
123
146
  ext: callChatOption.ext,
124
- workflow_id: this.workflowid,//callChatOption.workflowid,
147
+ workflow_id: this.talkflowid!,//callChatOption.workflowid,
125
148
  conversation_id,
126
- parameters: Object.assign({}, this.setting.customVariables || {}, callChatOption.customVariables || {}),
149
+ parameters: Object.assign({request_src:1},callChatOption.parameters || {}) //Object.assign({}, this.setting.customVariables || {}, callChatOption.customVariables || {}),
150
+ //parameters: { input: message[0]?.content }
127
151
  }
128
152
  return worflowreq as T;
129
153
  }
@@ -138,10 +162,10 @@ export default class CorzBot extends GptBase {
138
162
  while ((Date.now() - startTime) < maxWaitTime) {
139
163
  const chatinfo = await client.chat.retrieve(conversation_id, chatid);
140
164
  // 状态已经是完成了,可以去获取对话的内容了
141
- if (chatinfo.status === ChatStatus.COMPLETED) return { usage: chatinfo.usage, messages: await client.chat.messages.list(conversation_id, chatid)};
165
+ if (chatinfo.status === ChatStatus.COMPLETED) return { usage: chatinfo.usage, messages: await client.chat.messages.list(conversation_id, chatid) };
142
166
  await new Promise(resolve => setTimeout(resolve, 1500)); // 等待1500ms
143
167
  }
144
- return null;
168
+ return null;
145
169
  }
146
170
  /**
147
171
  * 非流式传输聊天请求
@@ -160,15 +184,15 @@ export default class CorzBot extends GptBase {
160
184
  }
161
185
  ];
162
186
  const client = await this.createClient();
163
-
187
+
164
188
  ////如果参数中用的是Workflow,则调用对话流来输出结果
165
189
  ////否则用智能体的对话来输出结果
166
190
  const params = await this.getRequestStream(client, message, callChatOption);
167
- const response = !this.workflowid ? await client.chat.create(params as CreateChatReq) : await client.workflows.runs.create(params as RunWorkflowReq);
191
+ const response = this.botid ? await client.chat.create(params as CreateChatReq) :await client.workflows.runs.create(params as RunWorkflowReq);
168
192
  if (this.workflowid && (response as RunWorkflowData).msg === 'Success') {
169
193
  const resp = (response as RunWorkflowData).data;
170
194
  try {
171
- return { successed: true, message: [{ role: 'assistant', type:'answer', content: JSON.parse(resp).data }]};
195
+ return { successed: true, message: [{ role: 'assistant', type: 'answer', content: JSON.parse(resp).data }] };
172
196
  } catch (error) {
173
197
  return { successed: true, message: [{ role: 'assistant', type: 'answer', content: resp }] };
174
198
  }
@@ -176,17 +200,30 @@ export default class CorzBot extends GptBase {
176
200
  if (!this.workflowid && (response as CreateChatData).conversation_id && (response as CreateChatData).id) {
177
201
  const ccd = response as CreateChatData;
178
202
  const chatData = await this.getChatDetail(client, ccd.conversation_id, ccd.id);
179
- if (chatData){
203
+ if (chatData) {
180
204
  const message = chatData.messages.filter(x => x.type === 'answer').map(item => ({
181
205
  role: item.role,
182
206
  type: item.type,
183
207
  content: item.content,
184
208
  }));
185
- return { successed: true, message, usage: chatData.usage,session_id:ccd.conversation_id };
209
+ return { successed: true, message, usage: chatData.usage, session_id: ccd.conversation_id };
186
210
  }
187
211
  }
188
212
  return { successed: false, error: { message: '聊天未完成' } };
189
-
213
+
214
+ }
215
+ /**
216
+ * 提取XML标签中间的内容,
217
+ * @param xmlStr
218
+ * @param tagName
219
+ * @returns
220
+ */
221
+ extractXmlContent(xmlStr: string, tagName: string): string {
222
+ // 构建匹配标签的正则(支持任意空白字符和大小写)
223
+ const regex = new RegExp(`<\\s*${tagName}\\s*>([\\s\\S]*?)<\\s*\\/\\s*${tagName}\\s*>`, 'i');
224
+ const match = xmlStr.match(regex);
225
+ if (match && match[1]) return match[1].trim();
226
+ return ''; // 未找到标签或内容
190
227
  }
191
228
  /**
192
229
  * 解析深度思考的JSON内容
@@ -194,63 +231,35 @@ export default class CorzBot extends GptBase {
194
231
  * @param status
195
232
  * @returns
196
233
  */
197
- private parseDeepThinkingJson(content: string, status: DeepThinkingStatus) {
198
-
234
+ private parseDeepThinkingJson(content: string) {
199
235
  // const thinkingStartIndex = status === DeepThinkingStatus.Thinking ? content.indexOf("{\"process_msg") :
200
236
  // (status===DeepThinkingStatus.ReasonOutput ? content.indexOf("{\"reasoning_content") : content.indexOf("{\"card_resource")) ;
201
- const tagLocation = [content.indexOf("{\"process_msg"),
202
- content.indexOf("{\"reasoning_content"),
203
- content.indexOf("{\"card_resource")].filter(x => x >= 0);
204
- const thinkingStartIndex = tagLocation.length > 0 ? Math.min(...tagLocation) : -1;
205
- const thinkingEndIndex = content.indexOf("\"}");
206
- // 如果没有找到相关的JSON内容,则直接返回
207
- if (thinkingStartIndex < 0) return { successed: true, content, status: DeepThinkingStatus.ThinkingOver };
208
- let jsonStr = null;
209
- try {
210
- jsonStr = content.substring(thinkingStartIndex, thinkingEndIndex >= 0 ? thinkingEndIndex : undefined) + "\"}";
211
- // 转换JSON的时候需要将非法字符过滤掉
212
- const thinkingObject = JSON.parse(jsonStr.replace(/[\x00-\x1F\x7F]/g, ''));
213
- const thinkingAction = Object.keys(thinkingObject)[0];
214
- // 需要将内容的原文返回
215
- const originalContent = jsonStr.split('":"')[1];
216
- // 如果正确的解析JSON,并且当前有包含JSON结束的字符,则把当前思考的JSON内容替换掉
217
- if (thinkingEndIndex >= 0) content = content.substring(thinkingEndIndex + 2);
218
- // 如果正常输出了卡片资源,并且json结束 card_resource 只有一个,所以一旦结束,则整个思考过程完毕
219
- // if (status === DeepThinkingStatus.ContentOutput && thinkingEndIndex >= 0) status = DeepThinkingStatus.ThinkingOver;
220
- // 判断整个思考过程是否到达等待卡片资源(有可能智能体输出不了卡片资源) reasoning_content 只有一个,所以一旦结束,则进入下一个阶段 card_resource
221
- //if (status === DeepThinkingStatus.ContentOutput && thinkingEndIndex >= 0) status = DeepThinkingStatus.ContentOutput;
222
- // 判断当前是否从前期思考切换到思考内容输出
223
- if (status === DeepThinkingStatus.Thinking && thinkingAction !== DeepThinkingAction.process)
224
- status = DeepThinkingStatus.ContentOutput;
225
- //if (status === DeepThinkingStatus.Thinking && content.indexOf("{\"reasoning_content") >= 0) status=DeepThinkingStatus.ReasonOutput;
226
- //const removeOutputContent = content.replace(originalContent!.substring(1, originalContent!.length - 2),"")
227
- let thinkingContent = originalContent?.substring(0, originalContent.length - 2)
228
- const outputLength = thinkingContent?.length || 0;
229
-
230
- // 用lastThinkingMessage来记录上一次的思考内容,避免重复输出内容,导致的网络传输内容过多
231
- if (this.lastThinkingMessage.action === thinkingAction && this.lastThinkingMessage.textposition) {
232
- thinkingContent = thinkingContent!.substring(this.lastThinkingMessage.textposition)
237
+ const xmlTagLocation = [content.indexOf(DeepThinkingAction.thinking.start),
238
+ content.indexOf(DeepThinkingAction.reasoning.start),
239
+ content.indexOf(DeepThinkingAction.card.start)];
240
+ let minLocation = 10000, minIndex = -1;
241
+ // 找到最小的并且大于0 的位置的下标
242
+ xmlTagLocation.forEach((x, index) => {
243
+ if (x >= 0 && x < minLocation) {
244
+ minLocation = x;
245
+ minIndex = index;
233
246
  }
234
- this.lastThinkingMessage = thinkingEndIndex >= 0 ? { action: thinkingAction!, textposition: 0 } : { action: thinkingAction!, textposition: outputLength }
235
-
236
- return {
237
- successed: true, thinking: {
238
- action: thinkingAction,
239
- text: thinkingContent,//Object.values(thinkingObject)[0]
240
- completed: thinkingEndIndex >= 0
241
- }, content, status
242
- }
243
- }
244
- catch (error) {
245
- // 如果在content之后发生了错误,可能该智能体输出不了卡片类型的数据,则输出的内容已经是正文了
246
- if (status === DeepThinkingStatus.ContentOutput) {
247
- status = DeepThinkingStatus.ThinkingOver;
248
- return { successed: true, content, status };
249
- }
250
- console.error('解析JSON出错了:', jsonStr, status)
251
- // 当前解析出错,等待下一次解析
252
- return { successed: false, content, status }
253
- }
247
+ });
248
+ // const tagLocation = xmlTagLocation.filter(x => x >= 0);
249
+ const thinkingStartIndex = minIndex >= 0 ? minLocation : -1; //tagLocation.length > 0 ? Math.min(...tagLocation) : -1;
250
+ if (thinkingStartIndex < 0) return { content, status: DeepThinkingStatus.ThinkingOver };
251
+ const currentAction = [DeepThinkingAction.thinking, DeepThinkingAction.reasoning, DeepThinkingAction.card][minIndex];
252
+ const currentActionIsOver = content.indexOf(currentAction.end, thinkingStartIndex);
253
+ const thinkingEndIndex = currentActionIsOver >= 0 ? currentActionIsOver: content.indexOf('</', thinkingStartIndex);
254
+ const thinkingContent = this.extractXmlContent(content.substring(thinkingStartIndex, thinkingEndIndex >= 0 ? thinkingEndIndex : undefined) + currentAction.end, currentAction.tag); //"\"}";
255
+ if (currentActionIsOver >= 0) content = content.substring(currentActionIsOver + currentAction.end.length);
256
+ return {
257
+ thinking: {
258
+ action: currentAction,
259
+ text: thinkingContent,//Object.values(thinkingObject)[0]
260
+ completed: currentActionIsOver >= 0
261
+ }, content};
262
+
254
263
  }
255
264
  /**
256
265
  * 流式传输聊天请求
@@ -275,48 +284,51 @@ export default class CorzBot extends GptBase {
275
284
  ////否则用智能体的对话来输出结果
276
285
  let requestid = Math.ceil(Math.random() * (new Date().getTime() * Math.random()) / 1000), index = 0;
277
286
  const params = await this.getRequestStream(client, message, callChatOption);
278
- const stream = !this.workflowid ? client.chat.stream(params as StreamChatReq) : client.workflows.runs.stream(params as RunWorkflowReq);
287
+ const stream = this.botid ? client.chat.stream(params as StreamChatReq) :
288
+ (this.workflowid ? client.workflows.runs.stream(params as RunWorkflowReq) :
289
+ client.workflows.chat.stream(params as ChatWorkflowReq)) ;
279
290
  let deltaindex = 0, fullanswer: string[] = [], followup: string[] = [], cardData: CardType[] = [];
280
291
  let deepThinking = '', thinkingStatus = DeepThinkingStatus.None, cardResource = ''; // 是否在深度思考中
281
292
  for await (const part of stream) {
282
293
  if (part.event === ChatEventType.ERROR) return this.emit('chaterror', { successed: false, error: 'call failed' });
283
- if (part.event === ChatEventType.CONVERSATION_MESSAGE_DELTA) {
284
- let { conversation_id, content_type, type, role, content } = part.data;
294
+ if (part.event === ChatEventType.CONVERSATION_MESSAGE_DELTA ||
295
+ part.event === WorkflowEventType.MESSAGE
296
+ ) {
297
+ let { conversation_id, content_type, type = 'answer', role = 'assistant', content, reasoning_content: reasoning } = part.data as any;
298
+ if (!content&& reasoning) {
299
+ this.emit('chatthinking', { text: reasoning, completed: false, action: 'deep-thinking' });
300
+ continue;
301
+ }
285
302
  // 如果存在深度思考,则一开始就会带有相关的关键信息
286
- if (deltaindex === 0 && content.startsWith("{\"process_msg")) {
303
+ if (deltaindex === 0 && content.startsWith("<xiaolu-")) {
287
304
  thinkingStatus = DeepThinkingStatus.Thinking;
288
305
  deltaindex++;
289
306
  }
290
307
  // 如果在深度思考中,则不输出消息
291
- if (thinkingStatus !== DeepThinkingStatus.None
292
- && thinkingStatus !== DeepThinkingStatus.ThinkingOver
293
- ) {
308
+ if (thinkingStatus === DeepThinkingStatus.Thinking) {
294
309
  deepThinking += content;
295
- const result = this.parseDeepThinkingJson(deepThinking, thinkingStatus)
296
- if (result.successed) {
297
- const thinking = result.thinking;
298
- if (thinking) {
299
- deepThinking = result.content;
300
- if (thinking.action === DeepThinkingAction.card) {
301
- cardResource += result.thinking.text;
302
- // 卡片流结束,解析卡片资源数据
303
- if (result.thinking.completed) {
304
- const allCards = cardResource.replace(/[\x00-\x1F\x7F]/g, '').split('|')
305
- for (const item of allCards) {
306
- const cardinfo: any = parse(item);
307
- if (cardinfo.type && cardinfo.tag) cardData.push({ type: Number(cardinfo.type), tag: cardinfo.tag })
308
- }
309
- // 将卡片资源返回给客户端
310
- this.emit('chatcard', cardData);
310
+ const result = this.parseDeepThinkingJson(deepThinking)
311
+ const thinking = result.thinking;
312
+ if (thinking) {
313
+ deepThinking = result.content;
314
+ if (thinking.action === DeepThinkingAction.card) {
315
+ cardResource += result.thinking.text;
316
+ // 卡片流结束,解析卡片资源数据
317
+ if (result.thinking.completed) {
318
+ const allCards = cardResource.replace(/[\x00-\x1F\x7F]/g, '').split('|')
319
+ for (const item of allCards) {
320
+ const cardinfo: any = parse(item);
321
+ if (cardinfo.type && cardinfo.tag) cardData.push({ type: Number(cardinfo.type), tag: cardinfo.tag })
311
322
  }
312
- } else {
313
- this.emit('chatthinking', result.thinking);
323
+ // 将卡片资源返回给客户端
324
+ this.emit('chatcard', cardData);
314
325
  }
326
+ } else {
327
+ this.emit('chatthinking', { text: result.thinking.text, completed: result.thinking.completed, action: thinking.action?.tag });
315
328
  }
316
- thinkingStatus = result.status;
317
329
  }
318
- if (thinkingStatus != DeepThinkingStatus.ThinkingOver) continue;
319
- // thinkingStatus = DeepThinkingStatus.None;
330
+ if (result.status != DeepThinkingStatus.ThinkingOver) continue;
331
+ thinkingStatus = DeepThinkingStatus.ThinkingOver;
320
332
  // 将排除了thinking之后的消息内容要带下去成为正式的输出内容
321
333
  content = deepThinking;
322
334
  }
@@ -327,13 +339,15 @@ export default class CorzBot extends GptBase {
327
339
  }
328
340
  ////在流式传输中,提取相关推荐问题
329
341
  if (part.event === ChatEventType.CONVERSATION_MESSAGE_COMPLETED) {
330
- const { type, content } = part.data;
342
+ const { type, content } = part.data ?? {};
331
343
  if (type === 'follow_up') followup.push(content);
332
344
  }
333
345
  ///整个对话结束
334
- if (part.event === ChatEventType.CONVERSATION_CHAT_COMPLETED) {
335
- const { conversation_id } = part.data;
336
- let output = { successed: true, cards: cardData.length ? cardData : null, followup, type: 'answer', content_type: 'text', role: RoleType.Assistant, requestid, segment: null, text: fullanswer.join(''), index: index++, session_id: conversation_id };
346
+ if (part.event === ChatEventType.CONVERSATION_CHAT_COMPLETED ||
347
+ part.event === WorkflowEventType.DONE
348
+ ) {
349
+ const { conversation_id, content } =( part.data )?? {} as any;
350
+ let output = { successed: true, cards: cardData.length ? cardData : null, followup, type: 'answer', content_type: 'text', role: RoleType.Assistant, requestid, segment: null, text: content??fullanswer.join(''), index: index++, session_id: conversation_id };
337
351
  if (attach) output = Object.assign({}, output, attach);
338
352
  this.emit('chatdone', output)
339
353
  }