alemonjs-aichat 1.0.9 → 1.0.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/README.md +20 -5
- package/lib/config.js +1 -1
- package/lib/data/help.json.js +2 -2
- package/lib/middleware/mw.js +37 -3
- package/lib/response/config/res.js +19 -1
- package/lib/response/setting/res.js +6 -12
- package/lib/response/zreply/res.js +10 -3
- package/lib/s3.js +1 -1
- package/package.json +2 -1
- package/public/image_out/1770144499713.jpg +0 -0
- package/public/image_out/1771955256739.jpg +0 -0
- package/public/image_out/1771955469648.jpg +0 -0
- package/public/image_out/1771955557274.jpg +0 -0
- package/public/image_out/1771955610109.jpg +0 -0
- package/public/image_out/1771955711203.jpg +0 -0
- package/public/image_out/1771955784320.jpg +0 -0
- package/public/image_out/1771955872240.jpg +0 -0
- package/public/image_out/1771956278821.jpg +0 -0
- package/public/image_out/1771956390816.jpg +0 -0
- package/public/image_out/1771956746969.jpg +0 -0
- package/public/image_out/1771958033538.jpg +0 -0
- package/public/image_out/1771958098279.jpg +0 -0
- package/public/image_out/1771958188274.jpg +0 -0
- package/public/image_out/1771958432929.jpg +0 -0
- package/public/image_out/1771958502708.jpg +0 -0
- package/public/image_out/1771958638365.jpg +0 -0
- package/public/image_out/1771958729528.jpg +0 -0
- package/public/image_out/1771958799682.jpg +0 -0
- package/public/image_out/1769255312948.jpg +0 -0
- package/public/image_out/1769257917858.jpg +0 -0
- package/public/image_out/1769258728524.jpg +0 -0
- package/public/image_out/1769259198276.jpg +0 -0
- package/public/image_out/1769259290647.jpg +0 -0
- package/public/image_out/1769259396531.jpg +0 -0
- package/public/image_out/1769259547338.jpg +0 -0
- package/public/image_out/1769265264698.jpg +0 -0
- package/public/image_out/1769265842121.jpg +0 -0
- package/public/image_out/1769266113612.jpg +0 -0
- package/public/image_out/1769266222054.jpg +0 -0
- package/public/image_out/1769266491375.jpg +0 -0
- package/public/image_out/1769266531736.jpg +0 -0
- package/public/image_out/1769266551994.jpg +0 -0
- package/public/image_out/1769266727498.jpg +0 -0
- package/public/image_out/1769266953542.jpg +0 -0
- package/public/image_out/1769267314948.jpg +0 -0
- package/public/image_out/1769267712504.jpg +0 -0
- package/public/image_out/1769269413856.jpg +0 -0
- package/public/image_out/1769333083808.jpg +0 -0
- package/public/image_out/1769334197123.jpg +0 -0
- package/public/image_out/1769334224549.jpg +0 -0
- package/public/image_out/1769334540773.jpg +0 -0
- package/public/image_out/1769334650190.jpg +0 -0
- package/public/image_out/1769334843869.jpg +0 -0
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
##
|
|
2
|
+
## 1.安装
|
|
3
3
|
|
|
4
4
|
### yarn安装方式(推荐)
|
|
5
5
|
|
|
@@ -19,14 +19,14 @@ https://gitee.com/suancaixianyu/alemonjs-aichat.git
|
|
|
19
19
|
release
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
##
|
|
22
|
+
## 2.配置`alemon.config.yaml`
|
|
23
23
|
在配置中添加该插件, 使用`ALemonDesk`只需要启用插件即可
|
|
24
24
|
``` yaml
|
|
25
25
|
app:
|
|
26
26
|
- 'alemonjs-aichat'
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
##
|
|
29
|
+
## 3.配置redis
|
|
30
30
|
`alemon.config.yaml`
|
|
31
31
|
``` yaml
|
|
32
32
|
redis:
|
|
@@ -36,5 +36,20 @@ redis:
|
|
|
36
36
|
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
##
|
|
40
|
-
|
|
39
|
+
## 4.使用
|
|
40
|
+
|
|
41
|
+
需要先使用`#添加ai`,配置一个ai后才能使用对话功能
|
|
42
|
+
|
|
43
|
+
|指令|作用|
|
|
44
|
+
|---|---|
|
|
45
|
+
|#添加ai|添加一个ai, 重名时更新|
|
|
46
|
+
|#切换ai|切换一个ai配置并保留当前对话|
|
|
47
|
+
|#开启对话|在当前位置启用ai聊天|
|
|
48
|
+
|#ai配置|显示当前使用的配置|
|
|
49
|
+
|#添加提示词|添加一个提示词|
|
|
50
|
+
|#提示词列表|查看当前配置的所有提示词|
|
|
51
|
+
|#切换提示词|切换一个提示词并保留当前对话|
|
|
52
|
+
|#清空对话|清空当前对话并保留好感度|
|
|
53
|
+
|#开启好感度|好感度会影响回复时的语气|
|
|
54
|
+
|#好感度|查看自己的好感度|
|
|
55
|
+
|#ai帮助|查看更多指令|
|
package/lib/config.js
CHANGED
|
@@ -213,7 +213,7 @@ const tools = [
|
|
|
213
213
|
type: "function",
|
|
214
214
|
function: {
|
|
215
215
|
name: "StableDiffusionImageToPrompt",
|
|
216
|
-
description: "使用 Stable Diffusion
|
|
216
|
+
description: "使用 Stable Diffusion 将图片转换为提示词, 仅供绘图时使用, 其他场景请勿使用",
|
|
217
217
|
parameters: {
|
|
218
218
|
type: "object",
|
|
219
219
|
properties: {
|
package/lib/data/help.json.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
var title = "IA聊天插件";
|
|
2
2
|
var name = "aichat";
|
|
3
|
-
var version = "v1.0.
|
|
3
|
+
var version = "v1.0.10";
|
|
4
4
|
var by = "AlemonJS";
|
|
5
5
|
var list = [
|
|
6
6
|
{
|
|
@@ -71,7 +71,7 @@ var list = [
|
|
|
71
71
|
},
|
|
72
72
|
{
|
|
73
73
|
cmd: "/[开启|关闭]语音回复",
|
|
74
|
-
desc: "
|
|
74
|
+
desc: "开启或关闭语音回复功能。仅限QQ平台使用。"
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
77
|
cmd: "/[开启|关闭]MCP工具",
|
package/lib/middleware/mw.js
CHANGED
|
@@ -10,7 +10,8 @@ var mw = onMiddleware(selects, async (event, next) => {
|
|
|
10
10
|
event["msg"] = event.MessageText; // 消息内容
|
|
11
11
|
event["guid"] = event.ChannelId ?? event.UserId; // 群号或用户QQ号
|
|
12
12
|
event["uidkey"] = `${event["guid"]}:${event.UserName}(${event.UserId})`; // 唯一标识
|
|
13
|
-
event["nickname"] =
|
|
13
|
+
event["nickname"] =
|
|
14
|
+
`${event.name == "private.message.create" ? "[私信]" : ""}${event.UserName}(${event.UserId})`; // 昵称(用户名+QQ号)
|
|
14
15
|
// console.log('event["nickname"]', event["nickname"]);
|
|
15
16
|
// console.log("event.IsMaster", event.UserId, config.master_id, event.IsMaster);
|
|
16
17
|
if (event.Platform == "testone") {
|
|
@@ -41,7 +42,6 @@ var mw = onMiddleware(selects, async (event, next) => {
|
|
|
41
42
|
if (event.Platform == "onebot") {
|
|
42
43
|
// 获取客户端
|
|
43
44
|
const [client] = useClient(event, API);
|
|
44
|
-
// 获取群成员存入redis
|
|
45
45
|
const botInfo = await client.getLoginInfo();
|
|
46
46
|
event["self_id"] = event.value.self_id; // 机器人QQ号
|
|
47
47
|
event["originalMsg"] = event.value.message; // 原始消息内容
|
|
@@ -58,7 +58,6 @@ var mw = onMiddleware(selects, async (event, next) => {
|
|
|
58
58
|
data: { qq: item.data.qq, nickname: atInfo[0].data.nickname },
|
|
59
59
|
};
|
|
60
60
|
}));
|
|
61
|
-
console.log('event["at"]', event["at"]);
|
|
62
61
|
// 是否at机器人
|
|
63
62
|
event["atBot"] = event["at"].find((item) => item.data.qq == event.self_id);
|
|
64
63
|
// 处理图片消息
|
|
@@ -82,6 +81,41 @@ var mw = onMiddleware(selects, async (event, next) => {
|
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
83
|
}
|
|
84
|
+
if (event.Platform == "scbbs") {
|
|
85
|
+
event["msg"] = `${event["msg"]}`; // 消息内容包含at机器人昵称
|
|
86
|
+
event["self_id"] = event.value.toUser.id; // 机器人ID
|
|
87
|
+
event["originalMsg"] = event.value.content; // 原始消息内容
|
|
88
|
+
event["atBot"] =
|
|
89
|
+
event.name === "private.message.create" && event.Platform == "scbbs";
|
|
90
|
+
// 处理图片消息
|
|
91
|
+
event["img"] = (event.value.content || [])
|
|
92
|
+
.filter((item) => item.type === "image")
|
|
93
|
+
.map((item) => item.data.url);
|
|
94
|
+
// 判断是否为群管理员
|
|
95
|
+
event["isAdmin"] =
|
|
96
|
+
event.value.author.roles?.filter((role) => role.id == 1 || role.id == 2).length > 0;
|
|
97
|
+
event["bot"] = {
|
|
98
|
+
nickname: event.value.toUser.nickname,
|
|
99
|
+
user_id: event.value.toUser.id,
|
|
100
|
+
}; // 机器人信息
|
|
101
|
+
event["raw_message"] = event.value.content
|
|
102
|
+
.map((item) => {
|
|
103
|
+
if (item.type === "text") {
|
|
104
|
+
return item.data.text;
|
|
105
|
+
}
|
|
106
|
+
else if (item.type === "image") {
|
|
107
|
+
return `[CQ:image,${item.data.url}]`;
|
|
108
|
+
}
|
|
109
|
+
else if (item.type === "at") {
|
|
110
|
+
return `[CQ:at,qq=${item.data.id}]`;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return `[${item.type.toUpperCase()}]`;
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
.join("");
|
|
117
|
+
}
|
|
118
|
+
console.log("处理后的事件", JSON.stringify(event, null, 2));
|
|
85
119
|
// 常用于兼容其他框架或增强event功能
|
|
86
120
|
next();
|
|
87
121
|
});
|
|
@@ -8,7 +8,8 @@ const regular$2 = /(\/|#)ai列表$/i;
|
|
|
8
8
|
const regular$3 = /(\/|#)提示词列表$/i;
|
|
9
9
|
const regular$4 = /(\/|#)清空对话$/i;
|
|
10
10
|
const regular$5 = /(\/|#)清空(所有|全部)对话$/i;
|
|
11
|
-
const
|
|
11
|
+
const get = /(\/|#)get (.+)$/i;
|
|
12
|
+
const regular = Regular.or(regular$1, regular$2, regular$3, regular$4, regular$5, get);
|
|
12
13
|
var res = onResponse(selects, async (e, next) => {
|
|
13
14
|
// 创建
|
|
14
15
|
const [message] = useMessage(e);
|
|
@@ -38,6 +39,23 @@ var res = onResponse(selects, async (e, next) => {
|
|
|
38
39
|
await clearAIChatHistory();
|
|
39
40
|
message.send(format(Text("所有对话已清空")));
|
|
40
41
|
}
|
|
42
|
+
// get请求一个地址
|
|
43
|
+
if (get.test(e.msg)) {
|
|
44
|
+
const match = e.msg.match(get);
|
|
45
|
+
if (!match) {
|
|
46
|
+
message.send(format(Text("格式错误,请按照 格式:/get <url> 进行请求")));
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const [, , url] = match;
|
|
50
|
+
try {
|
|
51
|
+
const res = await fetch(url);
|
|
52
|
+
const text = await res.text();
|
|
53
|
+
message.send(format(Text(`GET ${url} 的响应:\n${text}`)));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
message.send(format(Text(`请求 ${url} 失败:${error}`)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
41
59
|
next();
|
|
42
60
|
});
|
|
43
61
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { addAI, switchAI, addPrompt, deletePrompt, switchPrompt, deleteAI, affectionSwitch, getAIList, getAIConfig } from '../../config.js';
|
|
2
2
|
import { redis } from '../../redis.js';
|
|
3
|
-
import {
|
|
4
|
-
import { useMessage, Text } from 'alemonjs';
|
|
3
|
+
import { useMessage, Text, ImageFile } from 'alemonjs';
|
|
5
4
|
import { Regular } from 'alemonjs/utils';
|
|
6
5
|
|
|
7
6
|
const selects = onSelects(["message.create", "private.message.create"]);
|
|
@@ -20,21 +19,16 @@ const regular$14 = /(\/|#)(开启|关闭)语音回复$/i;
|
|
|
20
19
|
const regular$15 = /(\/|#)(开启|关闭)(MCP)?工具$/i;
|
|
21
20
|
const regular$16 = /(\/|#)切换图床(.*)$/i;
|
|
22
21
|
const test = /(\/|#)测试$/i;
|
|
23
|
-
const regular = Regular.or(regular$1, regular$2, regular$3, regular$4, regular$5, regular$6, regular$7, regular$8, regular$10, regular$11, regular$13, regular$14, regular$15, regular$16);
|
|
22
|
+
const regular = Regular.or(regular$1, regular$2, regular$3, regular$4, regular$5, regular$6, regular$7, regular$8, regular$10, regular$11, regular$13, regular$14, regular$15, regular$16, test);
|
|
24
23
|
var res = onResponse(selects, async (e, next) => {
|
|
25
24
|
// 创建
|
|
26
25
|
const [message] = useMessage(e);
|
|
27
26
|
// 测试
|
|
28
27
|
if (test.test(e.msg)) {
|
|
29
|
-
uploadImageToR2("./public/image_out/1769259547338.jpg").then((url) => {
|
|
30
|
-
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
// format(
|
|
34
|
-
// Text("测试消息"),
|
|
35
|
-
// ImageFile("./public/image_out/1769257917858.jpg"),
|
|
36
|
-
// ),
|
|
37
|
-
// );
|
|
28
|
+
// uploadImageToR2("./public/image_out/1769259547338.jpg").then((url) => {
|
|
29
|
+
// console.log("上传成功,图片URL:", url);
|
|
30
|
+
// });
|
|
31
|
+
message.send(format(Text("测试消息"), ImageFile("./public/image_out/1769257917858.jpg")));
|
|
38
32
|
// const a = await availableTools.StableDiffusionGenerateImage({
|
|
39
33
|
// prompt: "a cat playing with a ball",
|
|
40
34
|
// });
|
|
@@ -13,8 +13,11 @@ const regular = /.*/;
|
|
|
13
13
|
let ttsClient;
|
|
14
14
|
var res = onResponse(selects, async (e, next) => {
|
|
15
15
|
console.log("收到消息");
|
|
16
|
+
console.log("e.UserId", e.UserId, e.bot.user_id);
|
|
16
17
|
// 如果是命令则跳过
|
|
17
|
-
if (e.msg.startsWith("/") ||
|
|
18
|
+
if (e.msg.startsWith("/") ||
|
|
19
|
+
e.msg.startsWith("#") ||
|
|
20
|
+
e.UserId == e.bot.user_id) {
|
|
18
21
|
next();
|
|
19
22
|
return;
|
|
20
23
|
}
|
|
@@ -24,19 +27,21 @@ var res = onResponse(selects, async (e, next) => {
|
|
|
24
27
|
const historyMessages = await getAIChatHistory(e.guid);
|
|
25
28
|
const affections = await getAffectionLevelAll(e.guid);
|
|
26
29
|
const imgs = [];
|
|
27
|
-
let rawMessage = e.value.raw_message || e.msg;
|
|
30
|
+
let rawMessage = e.value.raw_message || e.raw_message || e.msg;
|
|
28
31
|
// 好感度开关
|
|
29
32
|
const affectionIsOpen = (await redis.get(`ai:affection:switch:${e.guid}`)) || "1";
|
|
30
33
|
const botName = e.bot.nickname || "小咸鱼";
|
|
31
34
|
const systemPrompt = `你正在一个群聊中跟用户聊天,你的聊天昵称是'${botName}'
|
|
32
35
|
关于回复格式:
|
|
33
36
|
用户的发言方式为: [{'用户昵称(用户id)(发送时间)':回复内容}]
|
|
37
|
+
当聊天场景为私信时, 用户昵称前方会有[私信]前缀, 例如: [{'[私信]用户昵称(用户id)(发送时间)':回复内容}]
|
|
34
38
|
你的回复方式为JSON: [{assistant:回复内容}],你可以在数组中加入多条消息来模拟更真实的聊天
|
|
35
39
|
当然你觉得当前聊的话题确定与你有关是才回复,否则你就回复空数组[]来表示不回复.请尽可能降低回复频率.
|
|
36
40
|
关于图片发送:
|
|
37
41
|
如果你在使用画图工具后需要回复图片, 可在消息中追加image_url, 例如:
|
|
38
42
|
[{'assistant':'画好啦','image_url':'图片地址'}]
|
|
39
43
|
注意:图片地址必须是接口返回的完整地址, 通常是相对路径
|
|
44
|
+
注意:你的回复中除了json必要的双引号之外, 不要再添加多余的双引号, 否则会导致解析失败, 需要在回复内容中使用单引号来表示字符串, 例如: [{"assistant":"这是一个'引号'的例子"}]
|
|
40
45
|
` +
|
|
41
46
|
(affectionIsOpen === "1"
|
|
42
47
|
? `当你认为对方在示好或骂你时,可添加{affections:数字}表示好感度变化,你可以根据好感度来适当改变回复语气.
|
|
@@ -205,8 +210,10 @@ var res = onResponse(selects, async (e, next) => {
|
|
|
205
210
|
}
|
|
206
211
|
}
|
|
207
212
|
// 如果没有工具调用,处理最终回复
|
|
208
|
-
|
|
213
|
+
let reply = res.choices?.[0]?.message?.content?.trim().replace(/'/g, '"') || "";
|
|
209
214
|
log("AI回复内容:", reply);
|
|
215
|
+
// 修复assistant字段中多余的双引号
|
|
216
|
+
reply = reply.replace(/(?<="assistant":")(.*?)(?="[,}])/, (match) => match.replace(/"/g, "'"));
|
|
210
217
|
// 提取好感变化, 使用incrementAffectionLevel更新好感
|
|
211
218
|
if (affectionIsOpen === "1") {
|
|
212
219
|
let affectionUpdated = false;
|
package/lib/s3.js
CHANGED
|
@@ -44,7 +44,7 @@ const uploadImageToR2 = async (source, key) => {
|
|
|
44
44
|
// 1. 处理不同来源 → 统一得到 Buffer + contentType + fileName
|
|
45
45
|
if (source.startsWith("http://") || source.startsWith("https://")) {
|
|
46
46
|
// 远程 URL
|
|
47
|
-
const response = await fetch(source);
|
|
47
|
+
const response = await fetch(source.replace("!/fwfh/368x238", ""));
|
|
48
48
|
if (!response.ok)
|
|
49
49
|
throw new Error(`下载图片失败: ${response.statusText}`);
|
|
50
50
|
buffer = Buffer.from(await response.arrayBuffer());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alemonjs-aichat",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.11",
|
|
4
4
|
"description": "alemonjs-aichat",
|
|
5
5
|
"author": "suancaixianyu",
|
|
6
6
|
"license": "MIT",
|
|
@@ -73,6 +73,7 @@
|
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@aws-sdk/client-s3": "^3.975.0",
|
|
75
75
|
"@aws-sdk/s3-request-presigner": "^3.975.0",
|
|
76
|
+
"alemonjs-aichat": "^1.0.9",
|
|
76
77
|
"mime-types": "^3.0.2",
|
|
77
78
|
"openai": "^6.16.0"
|
|
78
79
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|