wechaty-web-panel 1.6.120 → 1.6.122
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/handlers/on-callback-message.js +19 -10
- package/dist/handlers/on-claw-message.js +38 -27
- package/dist/handlers/on-message.js +3 -3
- package/dist/package-json.js +1 -1
- package/dist/proxy/aibotk.js +1 -1
- package/package.json +1 -1
- package/src/handlers/on-callback-message.js +19 -10
- package/src/handlers/on-claw-message.js +38 -27
- package/src/handlers/on-message.js +3 -3
- package/src/package-json.js +1 -1
- package/src/proxy/aibotk.js +1 -1
|
@@ -34,6 +34,16 @@ async function onRecordMessage(msg) {
|
|
|
34
34
|
if (isOfficial)
|
|
35
35
|
return;
|
|
36
36
|
console.log('msg', msg);
|
|
37
|
+
let isMention = false;
|
|
38
|
+
if (room) {
|
|
39
|
+
const userSelfName = this.currentUser?.name() || '';
|
|
40
|
+
const msgText = msg.type() === this.Message.Type.Text ? msg.text() : '';
|
|
41
|
+
isMention = (await msg.mentionSelf()) || msgText.includes(`@${userSelfName}`);
|
|
42
|
+
const isMentionAll = await msg.isMentionAll();
|
|
43
|
+
if (isMentionAll && isMention) {
|
|
44
|
+
isMention = false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
37
47
|
const baseMsg = {
|
|
38
48
|
conversionId: room ? room.id : contact.id,
|
|
39
49
|
conversionName: room ? roomName : contactName,
|
|
@@ -43,7 +53,8 @@ async function onRecordMessage(msg) {
|
|
|
43
53
|
chatAlias: contactAlias,
|
|
44
54
|
chatUserWeixin: userWeixin,
|
|
45
55
|
isMyself: !!msgSelf,
|
|
46
|
-
|
|
56
|
+
isMention,
|
|
57
|
+
time: String(timestamp).length > 10 ? Math.floor(timestamp / 1000) : timestamp
|
|
47
58
|
};
|
|
48
59
|
switch (type) {
|
|
49
60
|
case this.Message.Type.Channel:
|
|
@@ -127,12 +138,12 @@ async function onRecordMessage(msg) {
|
|
|
127
138
|
break;
|
|
128
139
|
case this.Message.Type.ChatHistory:
|
|
129
140
|
const historys = await msg.toChatHistory();
|
|
130
|
-
const contents = await formatHistory(this, historys.payload, conversationRecord);
|
|
141
|
+
const contents = await formatHistory(this, historys.payload, conversationRecord, msgId);
|
|
131
142
|
baseMsg.type = '历史记录';
|
|
132
143
|
baseMsg.content = contents;
|
|
133
144
|
break;
|
|
134
145
|
case this.Message.Type.Location:
|
|
135
|
-
const
|
|
146
|
+
const locationInfo = await msg.toLocation();
|
|
136
147
|
const locationParse = `【位置解析结果】\n纬度:${locationInfo?.payload?.latitude}\n经度:${locationInfo?.payload?.longitude}\n地点名:${locationInfo?.payload?.name}\n城市:${locationInfo?.payload?.city || ''}\n具体地址:${locationInfo?.payload?.address}\nPoiId:${locationInfo?.payload?.poiId || ''}`;
|
|
137
148
|
baseMsg.type = '位置';
|
|
138
149
|
baseMsg.content = locationParse;
|
|
@@ -149,7 +160,6 @@ async function onRecordMessage(msg) {
|
|
|
149
160
|
baseMsg.content = sysText;
|
|
150
161
|
}
|
|
151
162
|
}
|
|
152
|
-
default:
|
|
153
163
|
break;
|
|
154
164
|
}
|
|
155
165
|
console.log('baseMsg', baseMsg);
|
|
@@ -159,9 +169,9 @@ async function onRecordMessage(msg) {
|
|
|
159
169
|
console.log('记录消息失败', e);
|
|
160
170
|
}
|
|
161
171
|
}
|
|
162
|
-
async function formatHistory(that,
|
|
172
|
+
async function formatHistory(that, historyList, conversationRecord, msgId) {
|
|
163
173
|
const contents = [];
|
|
164
|
-
for (const history of
|
|
174
|
+
for (const history of historyList) {
|
|
165
175
|
if (history.type === that.Message.Type.Text) {
|
|
166
176
|
contents.push(history.message);
|
|
167
177
|
}
|
|
@@ -169,20 +179,19 @@ async function formatHistory(that, history, conversationRecord) {
|
|
|
169
179
|
const attachFileBox = await history.message.toFileBox();
|
|
170
180
|
const fileExtname = path.extname(attachFileBox.name);
|
|
171
181
|
const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif');
|
|
172
|
-
baseMsg.type = isImage ? '图片' : '文件';
|
|
173
182
|
const buffer = await attachFileBox.toBuffer();
|
|
174
183
|
const url = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${msgId}_${dayjs().valueOf()}_${attachFileBox.name}`, buffer);
|
|
175
|
-
contents.push(`
|
|
184
|
+
contents.push(`[${isImage ? '图片' : '文件'}](${url})`);
|
|
176
185
|
}
|
|
177
186
|
else if (history.type === that.Message.Type.ChatHistory) {
|
|
178
|
-
const res = await formatHistory(that, history.message, conversationRecord);
|
|
187
|
+
const res = await formatHistory(that, history.message, conversationRecord, msgId);
|
|
179
188
|
contents.push(res);
|
|
180
189
|
}
|
|
181
190
|
}
|
|
182
191
|
return contents.join('\n');
|
|
183
192
|
}
|
|
184
193
|
function sendMessage(msgInfo, recordConfig, robotInfo) {
|
|
185
|
-
const blackKey =
|
|
194
|
+
const blackKey = Object.keys(msgInfo);
|
|
186
195
|
const baseData = {
|
|
187
196
|
...msgInfo
|
|
188
197
|
};
|
|
@@ -19,19 +19,19 @@ async function checkAllow(clawConfig, contactId, roomId) {
|
|
|
19
19
|
}
|
|
20
20
|
else if (allowScope === 2) {
|
|
21
21
|
// 仅所有群
|
|
22
|
-
return !!
|
|
22
|
+
return !!roomId;
|
|
23
23
|
}
|
|
24
24
|
else if (allowScope === 3) {
|
|
25
25
|
// 仅所有好友
|
|
26
|
-
return !
|
|
26
|
+
return !roomId;
|
|
27
27
|
}
|
|
28
28
|
else if (allowScope === 4) {
|
|
29
29
|
// 部分群和部分好友
|
|
30
|
-
if (
|
|
30
|
+
if (roomId) {
|
|
31
31
|
return allowRooms.some(r => r.value === roomId);
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
return allowFriends.some(f => f.
|
|
34
|
+
return allowFriends.some(f => f.id === contactId);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
return false;
|
|
@@ -71,6 +71,16 @@ async function onClawMessage(msg) {
|
|
|
71
71
|
if (isOfficial)
|
|
72
72
|
return;
|
|
73
73
|
console.log('msg', msg);
|
|
74
|
+
let isMention = false;
|
|
75
|
+
if (room) {
|
|
76
|
+
const userSelfName = this.currentUser?.name() || '';
|
|
77
|
+
const msgText = type === this.Message.Type.Text ? msg.text() : '';
|
|
78
|
+
isMention = (await msg.mentionSelf()) || msgText.includes(`@${userSelfName}`);
|
|
79
|
+
const isMentionAll = await msg.isMentionAll();
|
|
80
|
+
if (isMentionAll && isMention) {
|
|
81
|
+
isMention = false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
74
84
|
const baseMsg = {
|
|
75
85
|
conversionId: room ? room.id : contact.id,
|
|
76
86
|
conversionName: room ? roomName : contactName,
|
|
@@ -80,14 +90,15 @@ async function onClawMessage(msg) {
|
|
|
80
90
|
chatAlias: contactAlias,
|
|
81
91
|
chatUserWeixin: userWeixin,
|
|
82
92
|
isMyself: !!msgSelf,
|
|
83
|
-
time: timestamp.length > 10 ?
|
|
93
|
+
time: String(timestamp).length > 10 ? Math.floor(timestamp / 1000) : timestamp,
|
|
84
94
|
msgId: msg.id,
|
|
95
|
+
isMention,
|
|
85
96
|
};
|
|
86
97
|
switch (type) {
|
|
87
98
|
case this.Message.Type.Channel:
|
|
88
99
|
baseMsg.type = '视频号';
|
|
89
100
|
const channelInfo = await msg.toChannel();
|
|
90
|
-
baseMsg.content = `【视频号消息】\n视频号昵称:${channelInfo.nickname()}\n视频号简介:${channelInfo.desc}\n视频号链接:${channelInfo.url}`;
|
|
101
|
+
baseMsg.content = `【视频号消息】\n视频号昵称:${channelInfo.nickname()}\n视频号简介:${channelInfo.desc()}\n视频号链接:${channelInfo.url()}`;
|
|
91
102
|
baseMsg.mediaInfo = {
|
|
92
103
|
nickname: channelInfo.nickname(),
|
|
93
104
|
coverUrl: channelInfo.coverUrl(),
|
|
@@ -144,7 +155,7 @@ async function onClawMessage(msg) {
|
|
|
144
155
|
}
|
|
145
156
|
else {
|
|
146
157
|
// 没有配置OSS,使用base64
|
|
147
|
-
const base64 = attachFileBox.toBase64();
|
|
158
|
+
const base64 = await attachFileBox.toBase64();
|
|
148
159
|
baseMsg.url = base64;
|
|
149
160
|
baseMsg.content = `【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n文件大小:${buffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`;
|
|
150
161
|
}
|
|
@@ -165,7 +176,7 @@ async function onClawMessage(msg) {
|
|
|
165
176
|
}
|
|
166
177
|
else {
|
|
167
178
|
// 没有配置OSS,使用base64
|
|
168
|
-
const audioBase64 = audioFileBox.toBase64();
|
|
179
|
+
const audioBase64 = await audioFileBox.toBase64();
|
|
169
180
|
baseMsg.url = audioBase64;
|
|
170
181
|
baseMsg.content = `【语音消息】\n文件名:${audioFileBox.name}\n文件大小:${audioBuffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`;
|
|
171
182
|
}
|
|
@@ -177,7 +188,7 @@ async function onClawMessage(msg) {
|
|
|
177
188
|
baseMsg.content = contents;
|
|
178
189
|
break;
|
|
179
190
|
case this.Message.Type.Location:
|
|
180
|
-
const
|
|
191
|
+
const locationInfo = await msg.toLocation();
|
|
181
192
|
const locationParse = `【位置解析结果】\n纬度:${locationInfo?.payload?.latitude}\n经度:${locationInfo?.payload?.longitude}\n地点名:${locationInfo?.payload?.name}\n城市:${locationInfo?.payload?.city || ''}\n具体地址:${locationInfo?.payload?.address}\nPoiId:${locationInfo?.payload?.poiId || ''}`;
|
|
182
193
|
baseMsg.type = '位置';
|
|
183
194
|
baseMsg.content = locationParse;
|
|
@@ -204,9 +215,9 @@ async function onClawMessage(msg) {
|
|
|
204
215
|
console.log('claw 消息处理失败', e);
|
|
205
216
|
}
|
|
206
217
|
}
|
|
207
|
-
async function formatHistory(that,
|
|
218
|
+
async function formatHistory(that, historyList, clawConfig) {
|
|
208
219
|
const contents = [];
|
|
209
|
-
for (const history of
|
|
220
|
+
for (const history of historyList) {
|
|
210
221
|
if (history.type === that.Message.Type.Text) {
|
|
211
222
|
contents.push(history.message);
|
|
212
223
|
}
|
|
@@ -214,7 +225,6 @@ async function formatHistory(that, history, clawConfig) {
|
|
|
214
225
|
const attachFileBox = await history.message.toFileBox();
|
|
215
226
|
const fileExtname = path.extname(attachFileBox.name);
|
|
216
227
|
const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif');
|
|
217
|
-
baseMsg.type = isImage ? '图片' : '文件';
|
|
218
228
|
if (attachFileBox.remoteUrl) {
|
|
219
229
|
// 直接使用远程链接,无需上传
|
|
220
230
|
const url = attachFileBox.remoteUrl;
|
|
@@ -223,7 +233,7 @@ async function formatHistory(that, history, clawConfig) {
|
|
|
223
233
|
}
|
|
224
234
|
const buffer = await attachFileBox.toBuffer();
|
|
225
235
|
if (!clawConfig?.ossConfig.type) {
|
|
226
|
-
const base64 = attachFileBox.toBase64();
|
|
236
|
+
const base64 = await attachFileBox.toBase64();
|
|
227
237
|
contents.push(`【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n文件大小:${buffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`);
|
|
228
238
|
continue;
|
|
229
239
|
}
|
|
@@ -252,21 +262,22 @@ function publishClawMessage(baseMsg, robotInfo) {
|
|
|
252
262
|
isGroup: baseMsg.isRoom,
|
|
253
263
|
groupId: baseMsg.isRoom ? baseMsg.conversionId : undefined,
|
|
254
264
|
groupName: baseMsg.isRoom ? baseMsg.conversionName : undefined,
|
|
255
|
-
|
|
265
|
+
isGroupMention: baseMsg.isMention,
|
|
266
|
+
timestamp: baseMsg.time * 1000, // 转换为 13 位毫秒时间戳
|
|
256
267
|
messageId: baseMsg.msgId,
|
|
257
268
|
type: baseMsg.type,
|
|
258
269
|
mediaInfo: baseMsg.mediaInfo,
|
|
259
270
|
url: baseMsg.url,
|
|
260
271
|
};
|
|
261
|
-
console.log('发布
|
|
272
|
+
console.log('发布 OpenClaw(小龙虾) 消息', payload);
|
|
262
273
|
clawMqttClient.publish(clawMqttClient._clawReciveTopic, JSON.stringify(payload), { qos: 1 });
|
|
263
274
|
}
|
|
264
275
|
catch (e) {
|
|
265
|
-
console.log('发布
|
|
276
|
+
console.log('发布 OpenClaw(小龙虾) 消息失败', e);
|
|
266
277
|
}
|
|
267
278
|
}
|
|
268
279
|
/**
|
|
269
|
-
* 初始化
|
|
280
|
+
* 初始化 OpenClaw(小龙虾) 连接
|
|
270
281
|
* 1. 连接 MQTT,将入站消息发布到 reciveTopic
|
|
271
282
|
* 2. 订阅 sendTopic,收到消息后通过微信发送
|
|
272
283
|
*/
|
|
@@ -285,7 +296,7 @@ async function initClawMqtt(that) {
|
|
|
285
296
|
const { port, host, username, password, clientId, reciveTopic, sendTopic } = mqttConfig;
|
|
286
297
|
if (!host)
|
|
287
298
|
return;
|
|
288
|
-
clawMqttClient = mqtt.connect(
|
|
299
|
+
clawMqttClient = mqtt.connect(`${host}:${port}`, {
|
|
289
300
|
username,
|
|
290
301
|
password,
|
|
291
302
|
clientId: clientId + randomRange(1, 10000),
|
|
@@ -293,21 +304,21 @@ async function initClawMqtt(that) {
|
|
|
293
304
|
// 在 client 上挂载 topic 便于 publishClawMessage 使用
|
|
294
305
|
clawMqttClient._clawReciveTopic = reciveTopic;
|
|
295
306
|
clawMqttClient.on('connect', function () {
|
|
296
|
-
console.log('
|
|
307
|
+
console.log('OpenClaw(小龙虾) 连接成功');
|
|
297
308
|
clawMqttClient.subscribe(sendTopic, function (err) {
|
|
298
309
|
if (err) {
|
|
299
|
-
console.log('
|
|
310
|
+
console.log('OpenClaw(小龙虾) 订阅失败', err);
|
|
300
311
|
}
|
|
301
312
|
else {
|
|
302
|
-
console.log(`
|
|
313
|
+
console.log(`OpenClaw(小龙虾) 订阅成功`);
|
|
303
314
|
}
|
|
304
315
|
});
|
|
305
316
|
});
|
|
306
317
|
clawMqttClient.on('reconnect', function () {
|
|
307
|
-
console.log('
|
|
318
|
+
console.log('OpenClaw(小龙虾) 重连中...');
|
|
308
319
|
});
|
|
309
320
|
clawMqttClient.on('error', function (e) {
|
|
310
|
-
console.log('
|
|
321
|
+
console.log('OpenClaw(小龙虾) 连接错误', e);
|
|
311
322
|
});
|
|
312
323
|
clawMqttClient.on('message', async function (topic, message) {
|
|
313
324
|
try {
|
|
@@ -331,7 +342,7 @@ async function initClawMqtt(that) {
|
|
|
331
342
|
if (isGroup && groupId) {
|
|
332
343
|
const room = await that.Room.find({ id: groupId });
|
|
333
344
|
if (!room) {
|
|
334
|
-
console.log(`
|
|
345
|
+
console.log(`OpenClaw(小龙虾): 查找不到群 ${groupId}`);
|
|
335
346
|
return;
|
|
336
347
|
}
|
|
337
348
|
// 解析 @ 联系人
|
|
@@ -362,7 +373,7 @@ async function initClawMqtt(that) {
|
|
|
362
373
|
else if (!isGroup && contactId) {
|
|
363
374
|
const contact = await that.Contact.find({ id: contactId });
|
|
364
375
|
if (!contact) {
|
|
365
|
-
console.log(`
|
|
376
|
+
console.log(`OpenClaw(小龙虾): 查找不到联系人 ${contactId}`);
|
|
366
377
|
return;
|
|
367
378
|
}
|
|
368
379
|
for (const msg of messages) {
|
|
@@ -378,12 +389,12 @@ async function initClawMqtt(that) {
|
|
|
378
389
|
}
|
|
379
390
|
}
|
|
380
391
|
catch (e) {
|
|
381
|
-
console.log('
|
|
392
|
+
console.log('OpenClaw(小龙虾) 处理消息失败', e);
|
|
382
393
|
}
|
|
383
394
|
});
|
|
384
395
|
}
|
|
385
396
|
catch (e) {
|
|
386
|
-
console.log('
|
|
397
|
+
console.log('OpenClaw(小龙虾) 初始化失败', e);
|
|
387
398
|
}
|
|
388
399
|
}
|
|
389
400
|
function closeClawMqtt() {
|
|
@@ -139,7 +139,7 @@ async function dispatchFriendFilterByMsgType(that, msg) {
|
|
|
139
139
|
const text = puppetInfo.puppetType.includes('PuppetService') && !msg.text().startsWith('@') ? msg.text().trim() : await getVoiceText(audioFileBox, finalConfig.botConfig.whisperConfig);
|
|
140
140
|
console.log('语音解析结果:', text);
|
|
141
141
|
const keyword = finalConfig.botConfig.whisperConfig?.keywords?.length ? finalConfig.botConfig?.whisperConfig.keywords?.find((item) => text.includes(item)) : true;
|
|
142
|
-
const isIgnore = checkIgnore(
|
|
142
|
+
const isIgnore = checkIgnore(text.trim(), aibotConfig.ignoreMessages);
|
|
143
143
|
if (text.trim() && !isIgnore && keyword) {
|
|
144
144
|
const gpt4vReplys = await getGpt4vChat({
|
|
145
145
|
that,
|
|
@@ -332,7 +332,7 @@ async function dispatchRoomFilterByMsgType(that, room, msg) {
|
|
|
332
332
|
const type = msg.type();
|
|
333
333
|
const receiver = msg.to();
|
|
334
334
|
let content = '';
|
|
335
|
-
let replys =
|
|
335
|
+
let replys = [];
|
|
336
336
|
let contactId = contact.id;
|
|
337
337
|
let contactAvatar = await contact.avatar();
|
|
338
338
|
const userSelfName = that.currentUser?.name() || that.userSelf()?.name();
|
|
@@ -526,7 +526,7 @@ async function dispatchRoomFilterByMsgType(that, room, msg) {
|
|
|
526
526
|
const text = puppetInfo.puppetType.includes('PuppetService') && !msg.text().startsWith('@') ? msg.text().trim() : await getVoiceText(audioFileBox, finalConfig.botConfig.whisperConfig);
|
|
527
527
|
console.log('语音解析结果', text);
|
|
528
528
|
const keyword = finalConfig.botConfig.whisperConfig?.keywords?.length ? finalConfig.botConfig?.whisperConfig?.keywords?.find((item) => text.includes(item)) : true;
|
|
529
|
-
const isIgnore = checkIgnore(
|
|
529
|
+
const isIgnore = checkIgnore(text.trim(), aibotConfig.ignoreMessages);
|
|
530
530
|
if (text.trim() && !isIgnore && keyword) {
|
|
531
531
|
const gpt4vReplys = await getGpt4vChat({
|
|
532
532
|
that,
|
package/dist/package-json.js
CHANGED
package/dist/proxy/aibotk.js
CHANGED
|
@@ -237,9 +237,9 @@ async function getConfig() {
|
|
|
237
237
|
uploadFileConfig: null,
|
|
238
238
|
ignoreFiles: false,
|
|
239
239
|
filterLinkContent: false,
|
|
240
|
+
clawConfig: { open: false, allowScope: 1, allowFriends: [], allowRooms: [], forwardAllMsg: true, forwardIncludeKeywordsMsg: [], forwardMediaMsg: false, ossConfig: {} },
|
|
240
241
|
...config,
|
|
241
242
|
cloudRoom,
|
|
242
|
-
clawConfig: { open: false, allowScope: 1, allowFriends: [], allowRooms: [], forwardAllMsg: true, forwardIncludeKeywordsMsg: [], forwardMediaMsg: false, ossConfig: {} }
|
|
243
243
|
});
|
|
244
244
|
return cres;
|
|
245
245
|
}
|
package/package.json
CHANGED
|
@@ -34,6 +34,16 @@ async function onRecordMessage(msg) {
|
|
|
34
34
|
const userWeixin = contact && contact.weixin() || ''
|
|
35
35
|
if (isOfficial) return
|
|
36
36
|
console.log('msg', msg)
|
|
37
|
+
let isMention = false
|
|
38
|
+
if (room) {
|
|
39
|
+
const userSelfName = this.currentUser?.name() || ''
|
|
40
|
+
const msgText = msg.type() === this.Message.Type.Text ? msg.text() : ''
|
|
41
|
+
isMention = (await msg.mentionSelf()) || msgText.includes(`@${userSelfName}`)
|
|
42
|
+
const isMentionAll = await msg.isMentionAll()
|
|
43
|
+
if (isMentionAll && isMention) {
|
|
44
|
+
isMention = false
|
|
45
|
+
}
|
|
46
|
+
}
|
|
37
47
|
const baseMsg = {
|
|
38
48
|
conversionId: room ? room.id : contact.id,
|
|
39
49
|
conversionName: room ? roomName : contactName,
|
|
@@ -43,7 +53,8 @@ async function onRecordMessage(msg) {
|
|
|
43
53
|
chatAlias: contactAlias,
|
|
44
54
|
chatUserWeixin: userWeixin,
|
|
45
55
|
isMyself: !!msgSelf,
|
|
46
|
-
|
|
56
|
+
isMention,
|
|
57
|
+
time: String(timestamp).length > 10 ? Math.floor(timestamp / 1000) : timestamp
|
|
47
58
|
}
|
|
48
59
|
switch (type) {
|
|
49
60
|
case this.Message.Type.Channel:
|
|
@@ -127,12 +138,12 @@ async function onRecordMessage(msg) {
|
|
|
127
138
|
break
|
|
128
139
|
case this.Message.Type.ChatHistory:
|
|
129
140
|
const historys = await msg.toChatHistory()
|
|
130
|
-
const contents = await formatHistory(this, historys.payload, conversationRecord)
|
|
141
|
+
const contents = await formatHistory(this, historys.payload, conversationRecord, msgId)
|
|
131
142
|
baseMsg.type = '历史记录'
|
|
132
143
|
baseMsg.content = contents
|
|
133
144
|
break
|
|
134
145
|
case this.Message.Type.Location:
|
|
135
|
-
const
|
|
146
|
+
const locationInfo = await msg.toLocation()
|
|
136
147
|
const locationParse = `【位置解析结果】\n纬度:${locationInfo?.payload?.latitude}\n经度:${locationInfo?.payload?.longitude}\n地点名:${locationInfo?.payload?.name}\n城市:${locationInfo?.payload?.city || ''}\n具体地址:${locationInfo?.payload?.address}\nPoiId:${locationInfo?.payload?.poiId || ''}`
|
|
137
148
|
baseMsg.type = '位置'
|
|
138
149
|
baseMsg.content = locationParse
|
|
@@ -148,7 +159,6 @@ async function onRecordMessage(msg) {
|
|
|
148
159
|
baseMsg.content = sysText
|
|
149
160
|
}
|
|
150
161
|
}
|
|
151
|
-
default:
|
|
152
162
|
break
|
|
153
163
|
}
|
|
154
164
|
console.log('baseMsg', baseMsg)
|
|
@@ -158,21 +168,20 @@ async function onRecordMessage(msg) {
|
|
|
158
168
|
}
|
|
159
169
|
}
|
|
160
170
|
|
|
161
|
-
async function formatHistory(that,
|
|
171
|
+
async function formatHistory(that, historyList, conversationRecord, msgId) {
|
|
162
172
|
const contents = []
|
|
163
|
-
for (const history of
|
|
173
|
+
for (const history of historyList) {
|
|
164
174
|
if (history.type === that.Message.Type.Text) {
|
|
165
175
|
contents.push(history.message)
|
|
166
176
|
} else if (history.type === that.Message.Type.Recalled || history.type === that.Message.Type.Attachment || history.type === that.Message.Type.Image || history.type === that.Message.Type.Video) {
|
|
167
177
|
const attachFileBox = await history.message.toFileBox();
|
|
168
178
|
const fileExtname = path.extname(attachFileBox.name);
|
|
169
179
|
const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif')
|
|
170
|
-
baseMsg.type = isImage ? '图片' : '文件'
|
|
171
180
|
const buffer = await attachFileBox.toBuffer()
|
|
172
181
|
const url = await uploadOssFile(`${conversationRecord?.ossConfig?.custom_path || ''}${msgId}_${dayjs().valueOf()}_${attachFileBox.name}`, buffer)
|
|
173
|
-
contents.push(`
|
|
182
|
+
contents.push(`[${isImage ? '图片' : '文件'}](${url})`)
|
|
174
183
|
} else if (history.type === that.Message.Type.ChatHistory) {
|
|
175
|
-
const res = await formatHistory(that, history.message, conversationRecord)
|
|
184
|
+
const res = await formatHistory(that, history.message, conversationRecord, msgId)
|
|
176
185
|
contents.push(res)
|
|
177
186
|
}
|
|
178
187
|
}
|
|
@@ -180,7 +189,7 @@ async function formatHistory(that, history, conversationRecord) {
|
|
|
180
189
|
}
|
|
181
190
|
|
|
182
191
|
function sendMessage(msgInfo, recordConfig, robotInfo) {
|
|
183
|
-
const blackKey =
|
|
192
|
+
const blackKey = Object.keys(msgInfo)
|
|
184
193
|
const baseData = {
|
|
185
194
|
...msgInfo
|
|
186
195
|
}
|
|
@@ -21,16 +21,16 @@ async function checkAllow(clawConfig, contactId, roomId) {
|
|
|
21
21
|
return true
|
|
22
22
|
} else if (allowScope === 2) {
|
|
23
23
|
// 仅所有群
|
|
24
|
-
return !!
|
|
24
|
+
return !!roomId
|
|
25
25
|
} else if (allowScope === 3) {
|
|
26
26
|
// 仅所有好友
|
|
27
|
-
return !
|
|
27
|
+
return !roomId
|
|
28
28
|
} else if (allowScope === 4) {
|
|
29
29
|
// 部分群和部分好友
|
|
30
|
-
if (
|
|
30
|
+
if (roomId) {
|
|
31
31
|
return allowRooms.some(r => r.value === roomId)
|
|
32
32
|
} else {
|
|
33
|
-
return allowFriends.some(f => f.
|
|
33
|
+
return allowFriends.some(f => f.id === contactId)
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
return false
|
|
@@ -70,6 +70,16 @@ async function onClawMessage(msg) {
|
|
|
70
70
|
const userWeixin = contact && contact.weixin() || ''
|
|
71
71
|
if (isOfficial) return
|
|
72
72
|
console.log('msg', msg)
|
|
73
|
+
let isMention = false
|
|
74
|
+
if (room) {
|
|
75
|
+
const userSelfName = this.currentUser?.name() || ''
|
|
76
|
+
const msgText = type === this.Message.Type.Text ? msg.text() : ''
|
|
77
|
+
isMention = (await msg.mentionSelf()) || msgText.includes(`@${userSelfName}`)
|
|
78
|
+
const isMentionAll = await msg.isMentionAll()
|
|
79
|
+
if (isMentionAll && isMention) {
|
|
80
|
+
isMention = false
|
|
81
|
+
}
|
|
82
|
+
}
|
|
73
83
|
const baseMsg = {
|
|
74
84
|
conversionId: room ? room.id : contact.id,
|
|
75
85
|
conversionName: room ? roomName : contactName,
|
|
@@ -79,14 +89,15 @@ async function onClawMessage(msg) {
|
|
|
79
89
|
chatAlias: contactAlias,
|
|
80
90
|
chatUserWeixin: userWeixin,
|
|
81
91
|
isMyself: !!msgSelf,
|
|
82
|
-
time: timestamp.length > 10 ?
|
|
92
|
+
time: String(timestamp).length > 10 ? Math.floor(timestamp / 1000) : timestamp,
|
|
83
93
|
msgId: msg.id,
|
|
94
|
+
isMention,
|
|
84
95
|
}
|
|
85
96
|
switch (type) {
|
|
86
97
|
case this.Message.Type.Channel:
|
|
87
98
|
baseMsg.type = '视频号'
|
|
88
99
|
const channelInfo = await msg.toChannel();
|
|
89
|
-
baseMsg.content = `【视频号消息】\n视频号昵称:${channelInfo.nickname()}\n视频号简介:${channelInfo.desc}\n视频号链接:${channelInfo.url}`
|
|
100
|
+
baseMsg.content = `【视频号消息】\n视频号昵称:${channelInfo.nickname()}\n视频号简介:${channelInfo.desc()}\n视频号链接:${channelInfo.url()}`
|
|
90
101
|
baseMsg.mediaInfo = {
|
|
91
102
|
nickname: channelInfo.nickname(),
|
|
92
103
|
coverUrl: channelInfo.coverUrl(),
|
|
@@ -143,7 +154,7 @@ async function onClawMessage(msg) {
|
|
|
143
154
|
baseMsg.content = `【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n下载链接:${url}`
|
|
144
155
|
} else {
|
|
145
156
|
// 没有配置OSS,使用base64
|
|
146
|
-
const base64 = attachFileBox.toBase64()
|
|
157
|
+
const base64 = await attachFileBox.toBase64()
|
|
147
158
|
baseMsg.url = base64
|
|
148
159
|
baseMsg.content = `【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n文件大小:${buffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`
|
|
149
160
|
}
|
|
@@ -163,7 +174,7 @@ async function onClawMessage(msg) {
|
|
|
163
174
|
baseMsg.content = `【语音消息】\n文件名:${audioFileBox.name}\n下载链接:${audioUrl}`
|
|
164
175
|
} else {
|
|
165
176
|
// 没有配置OSS,使用base64
|
|
166
|
-
const audioBase64 = audioFileBox.toBase64()
|
|
177
|
+
const audioBase64 = await audioFileBox.toBase64()
|
|
167
178
|
baseMsg.url = audioBase64
|
|
168
179
|
baseMsg.content = `【语音消息】\n文件名:${audioFileBox.name}\n文件大小:${audioBuffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`
|
|
169
180
|
}
|
|
@@ -175,7 +186,7 @@ async function onClawMessage(msg) {
|
|
|
175
186
|
baseMsg.content = contents
|
|
176
187
|
break
|
|
177
188
|
case this.Message.Type.Location:
|
|
178
|
-
const
|
|
189
|
+
const locationInfo = await msg.toLocation()
|
|
179
190
|
const locationParse = `【位置解析结果】\n纬度:${locationInfo?.payload?.latitude}\n经度:${locationInfo?.payload?.longitude}\n地点名:${locationInfo?.payload?.name}\n城市:${locationInfo?.payload?.city || ''}\n具体地址:${locationInfo?.payload?.address}\nPoiId:${locationInfo?.payload?.poiId || ''}`
|
|
180
191
|
baseMsg.type = '位置'
|
|
181
192
|
baseMsg.content = locationParse
|
|
@@ -199,16 +210,15 @@ async function onClawMessage(msg) {
|
|
|
199
210
|
}
|
|
200
211
|
}
|
|
201
212
|
|
|
202
|
-
async function formatHistory(that,
|
|
213
|
+
async function formatHistory(that, historyList, clawConfig) {
|
|
203
214
|
const contents = []
|
|
204
|
-
for (const history of
|
|
215
|
+
for (const history of historyList) {
|
|
205
216
|
if (history.type === that.Message.Type.Text) {
|
|
206
217
|
contents.push(history.message)
|
|
207
218
|
} else if (history.type === that.Message.Type.Recalled || history.type === that.Message.Type.Attachment || history.type === that.Message.Type.Image || history.type === that.Message.Type.Video) {
|
|
208
219
|
const attachFileBox = await history.message.toFileBox();
|
|
209
220
|
const fileExtname = path.extname(attachFileBox.name);
|
|
210
221
|
const isImage = fileExtname.includes('.png') || fileExtname.includes('.jpg') || fileExtname.includes('.jpeg') || fileExtname.includes('.gif')
|
|
211
|
-
baseMsg.type = isImage ? '图片' : '文件'
|
|
212
222
|
if (attachFileBox.remoteUrl) {
|
|
213
223
|
// 直接使用远程链接,无需上传
|
|
214
224
|
const url = attachFileBox.remoteUrl
|
|
@@ -217,7 +227,7 @@ async function formatHistory(that, history, clawConfig) {
|
|
|
217
227
|
}
|
|
218
228
|
const buffer = await attachFileBox.toBuffer()
|
|
219
229
|
if (!clawConfig?.ossConfig.type) {
|
|
220
|
-
const base64 = attachFileBox.toBase64()
|
|
230
|
+
const base64 = await attachFileBox.toBase64()
|
|
221
231
|
contents.push(`【${isImage ? '图片' : '文件'}消息】\n文件名:${attachFileBox.name}\n文件大小:${buffer.length} bytes\n(文件内容未上传,仅提供base64字符串)`)
|
|
222
232
|
continue
|
|
223
233
|
}
|
|
@@ -245,21 +255,22 @@ function publishClawMessage(baseMsg, robotInfo) {
|
|
|
245
255
|
isGroup: baseMsg.isRoom,
|
|
246
256
|
groupId: baseMsg.isRoom ? baseMsg.conversionId : undefined,
|
|
247
257
|
groupName: baseMsg.isRoom ? baseMsg.conversionName : undefined,
|
|
248
|
-
|
|
258
|
+
isGroupMention: baseMsg.isMention,
|
|
259
|
+
timestamp: baseMsg.time * 1000, // 转换为 13 位毫秒时间戳
|
|
249
260
|
messageId: baseMsg.msgId,
|
|
250
261
|
type: baseMsg.type,
|
|
251
262
|
mediaInfo: baseMsg.mediaInfo,
|
|
252
263
|
url: baseMsg.url,
|
|
253
264
|
}
|
|
254
|
-
console.log('发布
|
|
265
|
+
console.log('发布 OpenClaw(小龙虾) 消息', payload)
|
|
255
266
|
clawMqttClient.publish(clawMqttClient._clawReciveTopic, JSON.stringify(payload), { qos: 1 })
|
|
256
267
|
} catch (e) {
|
|
257
|
-
console.log('发布
|
|
268
|
+
console.log('发布 OpenClaw(小龙虾) 消息失败', e)
|
|
258
269
|
}
|
|
259
270
|
}
|
|
260
271
|
|
|
261
272
|
/**
|
|
262
|
-
* 初始化
|
|
273
|
+
* 初始化 OpenClaw(小龙虾) 连接
|
|
263
274
|
* 1. 连接 MQTT,将入站消息发布到 reciveTopic
|
|
264
275
|
* 2. 订阅 sendTopic,收到消息后通过微信发送
|
|
265
276
|
*/
|
|
@@ -277,7 +288,7 @@ async function initClawMqtt(that) {
|
|
|
277
288
|
const { port, host, username, password, clientId, reciveTopic, sendTopic } = mqttConfig
|
|
278
289
|
if (!host) return
|
|
279
290
|
|
|
280
|
-
clawMqttClient = mqtt.connect(
|
|
291
|
+
clawMqttClient = mqtt.connect(`${host}:${port}`, {
|
|
281
292
|
username,
|
|
282
293
|
password,
|
|
283
294
|
clientId: clientId + randomRange(1, 10000),
|
|
@@ -286,22 +297,22 @@ async function initClawMqtt(that) {
|
|
|
286
297
|
clawMqttClient._clawReciveTopic = reciveTopic
|
|
287
298
|
|
|
288
299
|
clawMqttClient.on('connect', function () {
|
|
289
|
-
console.log('
|
|
300
|
+
console.log('OpenClaw(小龙虾) 连接成功')
|
|
290
301
|
clawMqttClient.subscribe(sendTopic, function (err) {
|
|
291
302
|
if (err) {
|
|
292
|
-
console.log('
|
|
303
|
+
console.log('OpenClaw(小龙虾) 订阅失败', err)
|
|
293
304
|
} else {
|
|
294
|
-
console.log(`
|
|
305
|
+
console.log(`OpenClaw(小龙虾) 订阅成功`)
|
|
295
306
|
}
|
|
296
307
|
})
|
|
297
308
|
})
|
|
298
309
|
|
|
299
310
|
clawMqttClient.on('reconnect', function () {
|
|
300
|
-
console.log('
|
|
311
|
+
console.log('OpenClaw(小龙虾) 重连中...')
|
|
301
312
|
})
|
|
302
313
|
|
|
303
314
|
clawMqttClient.on('error', function (e) {
|
|
304
|
-
console.log('
|
|
315
|
+
console.log('OpenClaw(小龙虾) 连接错误', e)
|
|
305
316
|
})
|
|
306
317
|
|
|
307
318
|
clawMqttClient.on('message', async function (topic, message) {
|
|
@@ -326,7 +337,7 @@ async function initClawMqtt(that) {
|
|
|
326
337
|
if (isGroup && groupId) {
|
|
327
338
|
const room = await that.Room.find({ id: groupId })
|
|
328
339
|
if (!room) {
|
|
329
|
-
console.log(`
|
|
340
|
+
console.log(`OpenClaw(小龙虾): 查找不到群 ${groupId}`)
|
|
330
341
|
return
|
|
331
342
|
}
|
|
332
343
|
// 解析 @ 联系人
|
|
@@ -353,7 +364,7 @@ async function initClawMqtt(that) {
|
|
|
353
364
|
} else if (!isGroup && contactId) {
|
|
354
365
|
const contact = await that.Contact.find({ id: contactId })
|
|
355
366
|
if (!contact) {
|
|
356
|
-
console.log(`
|
|
367
|
+
console.log(`OpenClaw(小龙虾): 查找不到联系人 ${contactId}`)
|
|
357
368
|
return
|
|
358
369
|
}
|
|
359
370
|
for (const msg of messages) {
|
|
@@ -367,11 +378,11 @@ async function initClawMqtt(that) {
|
|
|
367
378
|
}
|
|
368
379
|
}
|
|
369
380
|
} catch (e) {
|
|
370
|
-
console.log('
|
|
381
|
+
console.log('OpenClaw(小龙虾) 处理消息失败', e)
|
|
371
382
|
}
|
|
372
383
|
})
|
|
373
384
|
} catch (e) {
|
|
374
|
-
console.log('
|
|
385
|
+
console.log('OpenClaw(小龙虾) 初始化失败', e)
|
|
375
386
|
}
|
|
376
387
|
}
|
|
377
388
|
|
|
@@ -137,7 +137,7 @@ async function dispatchFriendFilterByMsgType(that, msg) {
|
|
|
137
137
|
const text = puppetInfo.puppetType.includes('PuppetService') && !msg.text().startsWith('@') ? msg.text().trim() : await getVoiceText(audioFileBox, finalConfig.botConfig.whisperConfig)
|
|
138
138
|
console.log('语音解析结果:', text)
|
|
139
139
|
const keyword = finalConfig.botConfig.whisperConfig?.keywords?.length ? finalConfig.botConfig?.whisperConfig.keywords?.find((item) => text.includes(item)) : true
|
|
140
|
-
const isIgnore = checkIgnore(
|
|
140
|
+
const isIgnore = checkIgnore(text.trim(), aibotConfig.ignoreMessages)
|
|
141
141
|
if (text.trim() && !isIgnore && keyword) {
|
|
142
142
|
const gpt4vReplys = await getGpt4vChat({
|
|
143
143
|
that,
|
|
@@ -333,7 +333,7 @@ async function dispatchRoomFilterByMsgType(that, room, msg) {
|
|
|
333
333
|
const type = msg.type()
|
|
334
334
|
const receiver = msg.to()
|
|
335
335
|
let content = ''
|
|
336
|
-
let replys =
|
|
336
|
+
let replys = []
|
|
337
337
|
let contactId = contact.id
|
|
338
338
|
let contactAvatar = await contact.avatar()
|
|
339
339
|
const userSelfName = that.currentUser?.name() || that.userSelf()?.name()
|
|
@@ -532,7 +532,7 @@ async function dispatchRoomFilterByMsgType(that, room, msg) {
|
|
|
532
532
|
const text = puppetInfo.puppetType.includes('PuppetService') && !msg.text().startsWith('@') ? msg.text().trim() : await getVoiceText(audioFileBox, finalConfig.botConfig.whisperConfig)
|
|
533
533
|
console.log('语音解析结果', text)
|
|
534
534
|
const keyword = finalConfig.botConfig.whisperConfig?.keywords?.length ? finalConfig.botConfig?.whisperConfig?.keywords?.find((item) => text.includes(item)) : true
|
|
535
|
-
const isIgnore = checkIgnore(
|
|
535
|
+
const isIgnore = checkIgnore(text.trim(), aibotConfig.ignoreMessages)
|
|
536
536
|
if (text.trim() && !isIgnore && keyword) {
|
|
537
537
|
const gpt4vReplys = await getGpt4vChat({
|
|
538
538
|
that,
|
package/src/package-json.js
CHANGED
package/src/proxy/aibotk.js
CHANGED
|
@@ -239,9 +239,9 @@ async function getConfig() {
|
|
|
239
239
|
uploadFileConfig: null,
|
|
240
240
|
ignoreFiles: false,
|
|
241
241
|
filterLinkContent: false,
|
|
242
|
+
clawConfig: { open: false, allowScope: 1, allowFriends: [], allowRooms: [], forwardAllMsg: true, forwardIncludeKeywordsMsg: [], forwardMediaMsg: false, ossConfig: {} },
|
|
242
243
|
...config,
|
|
243
244
|
cloudRoom,
|
|
244
|
-
clawConfig: { open: false, allowScope: 1, allowFriends: [], allowRooms: [], forwardAllMsg: true, forwardIncludeKeywordsMsg: [], forwardMediaMsg: false, ossConfig: {} }
|
|
245
245
|
})
|
|
246
246
|
return cres
|
|
247
247
|
} catch (e) {
|