alemonjs-aichat 1.0.31-beta.2 → 1.0.31
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/lib/api/aitools.js
CHANGED
|
@@ -181,7 +181,7 @@ const tools = [
|
|
|
181
181
|
description: "要执行的终端命令",
|
|
182
182
|
},
|
|
183
183
|
},
|
|
184
|
-
required: ["command"],
|
|
184
|
+
required: ["userId", "command"],
|
|
185
185
|
},
|
|
186
186
|
},
|
|
187
187
|
},
|
|
@@ -234,7 +234,7 @@ const tools = [
|
|
|
234
234
|
type: "function",
|
|
235
235
|
function: {
|
|
236
236
|
name: "MemoryOperation",
|
|
237
|
-
description: "这个工具用于获取或修改对于用户的记忆数据, 包括用户形象, 用户偏好, 历史对话等. 你可以使用这个工具来存储一些需要长期记忆的信息, 例如用户的兴趣爱好,
|
|
237
|
+
description: "这个工具用于获取或修改对于用户的记忆数据, 包括用户形象, 用户偏好, 历史对话等. 你可以使用这个工具来存储一些需要长期记忆的信息, 例如用户的兴趣爱好, 重要事件等, 在不认识对方时可以尝试一下获取. 当你想要获取或修改这些信息时, 可以调用这个工具并提供具体的操作指令和数据. 例如, 在聊天过程中他对你的态度,以及他喜欢的东西等,可以通过这个工具及时记录下来, 也可以通过这个工具获取之前的对话记录,便于继续之前的话题",
|
|
238
238
|
parameters: {
|
|
239
239
|
type: "object",
|
|
240
240
|
properties: {
|
|
@@ -55,7 +55,7 @@ var res = onResponse(selects, async (e) => {
|
|
|
55
55
|
message.send(format(Text("你又再骗我画涩图了喵~已经保存到主人的收藏夹了,不给你看,哼!~")));
|
|
56
56
|
}
|
|
57
57
|
else {
|
|
58
|
-
message.send(format(Text("画图完成喵~\n"), Text(content), Image(
|
|
58
|
+
message.send(format(Text("画图完成喵~\n"), Text(content), Image(imgUrl)));
|
|
59
59
|
}
|
|
60
60
|
await redisClient.addImgUrl(e.guid, imgUrl);
|
|
61
61
|
}
|
|
@@ -66,7 +66,7 @@ var res = onResponse(selects, async (e) => {
|
|
|
66
66
|
message.send(format(Text(json.error)));
|
|
67
67
|
}
|
|
68
68
|
catch (error) {
|
|
69
|
-
message.send(format(Text("
|
|
69
|
+
message.send(format(Text("修图报错了喵~:" + res)));
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -4,7 +4,7 @@ import OpenAi from 'openai';
|
|
|
4
4
|
import { TTSClient } from '../../api/tts.js';
|
|
5
5
|
import { availableTools } from '../../api/aitools.js';
|
|
6
6
|
import redisClient from '../../config.js';
|
|
7
|
-
import { shouldSkipAIReply, getChatConfig, buildUserMessage } from './getChatConfig.js';
|
|
7
|
+
import { shouldSkipAIReply, getChatConfig, buildUserMessage, getDeepThoughtReasoning } from './getChatConfig.js';
|
|
8
8
|
import { createTTSMessage } from './tts.js';
|
|
9
9
|
import { parseAIReply } from './tools.js';
|
|
10
10
|
|
|
@@ -44,46 +44,34 @@ const CApiReply = async (e) => {
|
|
|
44
44
|
createParams["tools"] = cfg.toolConfig.cApiToolList;
|
|
45
45
|
createParams["tool_choice"] = "auto";
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
const deepThoughtReasoning = getDeepThoughtReasoning(cfg);
|
|
48
|
+
Object.assign(createParams, deepThoughtReasoning);
|
|
49
|
+
createParams["stream"] = false;
|
|
50
|
+
log("请求AI,参数:", createParams);
|
|
51
51
|
const stream = (await openai.chat.completions.create(createParams));
|
|
52
|
+
log("AI回复原始数据:\n", JSON.stringify(stream, null, 2));
|
|
52
53
|
let fullContent = "";
|
|
53
54
|
let toolCalls = [];
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
function: { name: "", arguments: "" },
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
if (tc.id)
|
|
72
|
-
toolCalls[tc.index].id = tc.id;
|
|
73
|
-
if (tc.function?.name)
|
|
74
|
-
toolCalls[tc.index].function.name += tc.function.name;
|
|
75
|
-
if (tc.function?.arguments)
|
|
76
|
-
toolCalls[tc.index].function.arguments += tc.function.arguments;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
55
|
+
const completion = stream;
|
|
56
|
+
const aiReplyMessage = completion?.choices?.[0]?.message;
|
|
57
|
+
if (aiReplyMessage?.content) {
|
|
58
|
+
fullContent = aiReplyMessage.content;
|
|
59
|
+
}
|
|
60
|
+
if (Array.isArray(aiReplyMessage?.tool_calls)) {
|
|
61
|
+
toolCalls = aiReplyMessage.tool_calls.map((tc) => ({
|
|
62
|
+
id: tc.id || "",
|
|
63
|
+
type: "function",
|
|
64
|
+
function: {
|
|
65
|
+
name: tc.function?.name || "",
|
|
66
|
+
arguments: tc.function?.arguments || "",
|
|
67
|
+
},
|
|
68
|
+
}));
|
|
80
69
|
}
|
|
81
70
|
let res = {
|
|
82
71
|
choices: [
|
|
83
72
|
{
|
|
84
73
|
message: {
|
|
85
|
-
|
|
86
|
-
content: fullContent || null,
|
|
74
|
+
...aiReplyMessage,
|
|
87
75
|
tool_calls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
88
76
|
},
|
|
89
77
|
},
|
|
@@ -95,13 +83,17 @@ const CApiReply = async (e) => {
|
|
|
95
83
|
}
|
|
96
84
|
messages.push(usermessage);
|
|
97
85
|
await redisClient.addAIChatHistory(e.guid, usermessage);
|
|
86
|
+
if (res.choices[0].message?.tool_calls && fullContent.trim() !== "") {
|
|
87
|
+
message.send(format(Text(fullContent)));
|
|
88
|
+
}
|
|
98
89
|
// 检查是否有工具调用需要处理
|
|
99
90
|
while (res.choices[0].message?.tool_calls?.length) {
|
|
100
91
|
const responseMessage = res.choices[0].message;
|
|
92
|
+
log("AI返回工具调用,内容:-----", res.choices[0]);
|
|
101
93
|
// 先处理对话
|
|
102
94
|
messages.push(responseMessage);
|
|
103
95
|
await redisClient.addAIChatHistory(e.guid, responseMessage);
|
|
104
|
-
|
|
96
|
+
log("模型决定调用工具:", responseMessage.tool_calls);
|
|
105
97
|
if (cfg.toolConfig.toolPromptSwitch === "1") {
|
|
106
98
|
const useToolsMessage = responseMessage.tool_calls.map((toolCall) => {
|
|
107
99
|
return `工具调用: ${toolCall.function.name}(${cfg.toolConfig.toolPromptArgsSwitch === "1" ? toolCall.function.arguments : ""})`;
|
|
@@ -165,6 +157,7 @@ const CApiReply = async (e) => {
|
|
|
165
157
|
tool_call_id: toolCall.id,
|
|
166
158
|
name: functionName,
|
|
167
159
|
content: toolContent,
|
|
160
|
+
reasoning_content: responseMessage.reasoning_content || "",
|
|
168
161
|
});
|
|
169
162
|
// 记录工具调用结果
|
|
170
163
|
await redisClient.addAIChatHistory(e.guid, {
|
|
@@ -172,15 +165,20 @@ const CApiReply = async (e) => {
|
|
|
172
165
|
tool_call_id: toolCall.id,
|
|
173
166
|
name: functionName,
|
|
174
167
|
content: toolContent,
|
|
168
|
+
reasoning_content: responseMessage.reasoning_content || "",
|
|
175
169
|
});
|
|
176
170
|
}
|
|
177
|
-
|
|
178
|
-
res = await openai.chat.completions.create({
|
|
171
|
+
const params = {
|
|
179
172
|
model: cfg.config.model,
|
|
180
173
|
messages: messages,
|
|
181
174
|
tools: cfg.toolConfig.cApiToolList,
|
|
182
175
|
tool_choice: "auto",
|
|
183
|
-
}
|
|
176
|
+
};
|
|
177
|
+
const deepThoughtReasoning = getDeepThoughtReasoning(cfg);
|
|
178
|
+
Object.assign(params, deepThoughtReasoning);
|
|
179
|
+
log("重新请求AI,参数:", params);
|
|
180
|
+
// 重新请求
|
|
181
|
+
res = await openai.chat.completions.create(params);
|
|
184
182
|
// 检查是否还有工具调用需要处理
|
|
185
183
|
if (!res.choices || res.choices.length === 0) {
|
|
186
184
|
log("AI未返回内容");
|
|
@@ -193,7 +191,7 @@ const CApiReply = async (e) => {
|
|
|
193
191
|
log("AI选择不回复");
|
|
194
192
|
return;
|
|
195
193
|
}
|
|
196
|
-
console.log("AI回复原文:\n",
|
|
194
|
+
console.log("AI回复原文:\n", JSON.stringify(res, null, 2));
|
|
197
195
|
// 处理消息
|
|
198
196
|
// 提取ai发送的消息有多少条
|
|
199
197
|
const aireply = parseAIReply(reply, cfg, message, e);
|
|
@@ -101,16 +101,25 @@ const getChatConfig = async (e) => {
|
|
|
101
101
|
当场景为私聊时, 用户昵称前方会出现[私聊]标识
|
|
102
102
|
当平台适配环境较好时,用户消息前面会包含消息id, 例如: [私聊]用户昵称(用户id)(发送时间)(msgid:消息id):消息内容
|
|
103
103
|
你发送的消息内容会被框架自动加上消息id, 以便你在需要撤回消息时使用
|
|
104
|
+
|
|
104
105
|
### 你的回复格式
|
|
105
106
|
${botName}:消息内容
|
|
106
107
|
#### 拒绝回复:
|
|
107
108
|
在讨论中如果你觉得不适合回复或觉得与你无关又或者不感兴趣, 可以直接回复"[]"来拒绝本次回复, 例如:
|
|
108
109
|
${botName}:[]
|
|
109
|
-
|
|
110
|
+
#### 图片
|
|
111
|
+
${botName}:<img=http://example.com/image.jpg>
|
|
112
|
+
${botName}:<img=./path/to/image.jpg>
|
|
113
|
+
#### 艾特用户
|
|
114
|
+
${botName}:<at=用户id>消息内容
|
|
115
|
+
#### 撤回消息
|
|
116
|
+
${botName}:<revoke=消息id>
|
|
110
117
|
${complexOutputIsOpen === "1" && isOpenTTSReply === "1"
|
|
111
|
-
?
|
|
118
|
+
? `#### 语音
|
|
119
|
+
${botName}:<tts=你好这是一个语音消息>
|
|
120
|
+
#### 切换音色
|
|
121
|
+
${botName}:<音色=派蒙-默认><tts=这是派蒙的默认声音哦>`
|
|
112
122
|
: "#### 语音回复: 当前不可用"}
|
|
113
|
-
|
|
114
123
|
${isOpenR18 === "1"
|
|
115
124
|
? ""
|
|
116
125
|
: `
|
|
@@ -330,5 +339,48 @@ const buildUserMessage = async (e, cfg, mode = "capi") => {
|
|
|
330
339
|
],
|
|
331
340
|
};
|
|
332
341
|
};
|
|
342
|
+
const getDeepThoughtReasoning = (cfg) => {
|
|
343
|
+
if (cfg.deepThoughtSwitch === "1") {
|
|
344
|
+
// 开启深度思考, 深度 中等medium
|
|
345
|
+
if (cfg.config.model.includes("deepseek")) {
|
|
346
|
+
return {
|
|
347
|
+
thinking: { type: "enabled" },
|
|
348
|
+
reasoning_effort: "medium",
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (cfg.config.model.includes("doubao")) {
|
|
352
|
+
return {
|
|
353
|
+
reasoning: {
|
|
354
|
+
effort: "medium",
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
if (cfg.config.model.includes("qwen")) {
|
|
359
|
+
return {
|
|
360
|
+
enable_thinking: true,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
else {
|
|
365
|
+
// 关闭深度思考
|
|
366
|
+
if (cfg.config.model.includes("deepseek")) {
|
|
367
|
+
return {
|
|
368
|
+
thinking: { type: "disabled" },
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
if (cfg.config.model.includes("doubao")) {
|
|
372
|
+
return {
|
|
373
|
+
reasoning: {
|
|
374
|
+
effort: "minimal",
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
if (cfg.config.model.includes("qwen")) {
|
|
379
|
+
return {
|
|
380
|
+
enable_thinking: false,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
};
|
|
333
385
|
|
|
334
|
-
export { buildUserMessage, getChatConfig, normalizeTools, shouldSkipAIReply };
|
|
386
|
+
export { buildUserMessage, getChatConfig, getDeepThoughtReasoning, normalizeTools, shouldSkipAIReply };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alemonjs-aichat",
|
|
3
|
-
"version": "1.0.31
|
|
3
|
+
"version": "1.0.31",
|
|
4
4
|
"description": "alemonjs-aichat",
|
|
5
5
|
"author": "suancaixianyu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"@alemonjs/bubble": "^2.1.10",
|
|
20
20
|
"@alemonjs/db": "^0.0.16",
|
|
21
21
|
"@alemonjs/onebot": "^2.1.14",
|
|
22
|
-
"@types/node": "^22",
|
|
23
|
-
"alemonjs": "2.1.
|
|
22
|
+
"@types/node": "^22.19.17",
|
|
23
|
+
"alemonjs": "2.1.65",
|
|
24
24
|
"cssnano": "^7",
|
|
25
|
-
"jsxp": "^1.
|
|
25
|
+
"jsxp": "^1.4.0",
|
|
26
26
|
"lvyjs": "^0.2.25",
|
|
27
27
|
"pm2": "^5",
|
|
28
28
|
"tailwindcss": "3"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: send-media
|
|
3
|
-
description: 发送媒体文件,
|
|
3
|
+
description: 发送媒体文件, 包括文本、图片、音频和视频等格式规范, 在与用户对话之前请务必仔细阅读该技能文档, 以免发送消息失败
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Send Media Skill
|
|
@@ -25,7 +25,7 @@ description: 发送媒体文件, 包括文本、图片、音频和视频等格
|
|
|
25
25
|
|
|
26
26
|
```txt
|
|
27
27
|
小咸鱼: <img=http://example.com/image.jpg>
|
|
28
|
-
小咸鱼: <img
|
|
28
|
+
小咸鱼: <img=./path/to/image.jpg>
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
## 3. 发送音频
|