mioku-plugin-chat 3.0.2 → 3.0.4
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/core/chat-turn.ts +109 -35
- package/handlers/idle-debug.ts +1 -1
- package/handlers/message.ts +11 -26
- package/handlers/tts-command.ts +1 -1
- package/index.ts +54 -2
- package/package.json +2 -30
- package/utils/message.ts +10 -15
package/core/chat-turn.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import type { MiokuContext } from "mioku";
|
|
2
|
-
import type { AITool, ChatRuntimePromptInjection } from "mioku";
|
|
2
|
+
import type { AITool, Bot, ChatRuntimePromptInjection } from "mioku";
|
|
3
3
|
import type { ChatPluginContext, ChatRuntimeState } from "../context";
|
|
4
4
|
import type { ChatConfig, ChatMessage, TargetMessage } from "../types";
|
|
5
|
-
import {
|
|
6
|
-
getGroupHistory,
|
|
7
|
-
getBotRole,
|
|
8
|
-
getQuotedContent,
|
|
9
|
-
} from "../utils";
|
|
5
|
+
import { getGroupHistory, getBotRole, getQuotedContent } from "../utils";
|
|
10
6
|
import { buildStructuredUserInputFromTarget } from "../manage/group-structured-history";
|
|
11
7
|
|
|
12
8
|
export type RuntimeReplyContextType =
|
|
@@ -53,7 +49,8 @@ function buildRuntimeTargetMessageContent(
|
|
|
53
49
|
overrideContent?: string,
|
|
54
50
|
): string {
|
|
55
51
|
if (overrideContent?.trim()) return overrideContent.trim();
|
|
56
|
-
if (!event || !event.message || !Array.isArray(event.message))
|
|
52
|
+
if (!event || !event.message || !Array.isArray(event.message))
|
|
53
|
+
return NO_NEW_MESSAGE;
|
|
57
54
|
return ctx.text(event)?.trim() || NO_NEW_MESSAGE;
|
|
58
55
|
}
|
|
59
56
|
|
|
@@ -74,7 +71,8 @@ function resolveRuntimeContext(
|
|
|
74
71
|
selfId: event.self_id,
|
|
75
72
|
sessionId: groupId ? `group:${groupId}` : `personal:${userId}`,
|
|
76
73
|
personalSessionId: groupId ? `personal:${userId}` : undefined,
|
|
77
|
-
senderName:
|
|
74
|
+
senderName:
|
|
75
|
+
event.sender?.card || event.sender?.nickname || String(userId),
|
|
78
76
|
userRole: event.sender?.role || "member",
|
|
79
77
|
userTitle: event.sender?.title || undefined,
|
|
80
78
|
groupName: event.group_name,
|
|
@@ -85,7 +83,10 @@ function resolveRuntimeContext(
|
|
|
85
83
|
if (typeof options.selfId !== "number") {
|
|
86
84
|
throw new Error("Chat runtime requires either event or selfId");
|
|
87
85
|
}
|
|
88
|
-
if (
|
|
86
|
+
if (
|
|
87
|
+
typeof options.groupId !== "number" &&
|
|
88
|
+
typeof options.userId !== "number"
|
|
89
|
+
) {
|
|
89
90
|
throw new Error("Chat runtime requires groupId or userId");
|
|
90
91
|
}
|
|
91
92
|
|
|
@@ -112,7 +113,9 @@ function resolveRuntimeContext(
|
|
|
112
113
|
groupId: options.groupId,
|
|
113
114
|
userId,
|
|
114
115
|
selfId: options.selfId,
|
|
115
|
-
sessionId: options.groupId
|
|
116
|
+
sessionId: options.groupId
|
|
117
|
+
? `group:${options.groupId}`
|
|
118
|
+
: `personal:${userId}`,
|
|
116
119
|
personalSessionId:
|
|
117
120
|
options.groupId && userId ? `personal:${userId}` : undefined,
|
|
118
121
|
senderName: options.groupId ? "system" : String(userId),
|
|
@@ -144,39 +147,90 @@ export async function finalizeChatTurn(
|
|
|
144
147
|
return;
|
|
145
148
|
}
|
|
146
149
|
const { ctx } = pluginCtx;
|
|
147
|
-
const {
|
|
150
|
+
const {
|
|
151
|
+
groupId,
|
|
152
|
+
groupSessionId,
|
|
153
|
+
userId,
|
|
154
|
+
selfId,
|
|
155
|
+
cfg,
|
|
156
|
+
toolCtx,
|
|
157
|
+
result,
|
|
158
|
+
event,
|
|
159
|
+
} = args;
|
|
160
|
+
|
|
161
|
+
const actingBot = (selfId ? ctx.pickBot(selfId) : undefined) ?? event?.bot;
|
|
162
|
+
const eventBotId = event?.bot ? String(event.bot.bot_id) : undefined;
|
|
163
|
+
const actingIsEventBot =
|
|
164
|
+
eventBotId == null ||
|
|
165
|
+
(actingBot != null && String(actingBot.bot_id) === eventBotId);
|
|
148
166
|
|
|
149
167
|
if (groupId) {
|
|
150
168
|
const sentMessageIds = await pluginCtx.sendAIResponse(
|
|
151
|
-
{
|
|
169
|
+
{
|
|
170
|
+
ctx,
|
|
171
|
+
groupId,
|
|
172
|
+
messages: result.messages,
|
|
173
|
+
config: cfg,
|
|
174
|
+
sentIndices: toolCtx.sentMessageIndices,
|
|
175
|
+
audioService: pluginCtx.audioService,
|
|
176
|
+
},
|
|
152
177
|
selfId,
|
|
153
178
|
);
|
|
154
|
-
await pluginCtx.sendEmoji(ctx, groupId, result.emojiPath,
|
|
179
|
+
await pluginCtx.sendEmoji(ctx, groupId, result.emojiPath, actingBot);
|
|
155
180
|
const now = Date.now();
|
|
156
|
-
pluginCtx.saveBotMessages(
|
|
181
|
+
pluginCtx.saveBotMessages(
|
|
182
|
+
groupId,
|
|
183
|
+
groupSessionId,
|
|
184
|
+
result.messages,
|
|
185
|
+
now,
|
|
186
|
+
cfg,
|
|
187
|
+
pluginCtx.db,
|
|
188
|
+
ctx,
|
|
189
|
+
actingBot,
|
|
190
|
+
sentMessageIds,
|
|
191
|
+
);
|
|
157
192
|
if (args.isLive) {
|
|
158
|
-
pluginCtx.idleCheckManager.recordBotMessages(
|
|
193
|
+
pluginCtx.idleCheckManager.recordBotMessages(
|
|
194
|
+
groupSessionId,
|
|
195
|
+
result.messages.length,
|
|
196
|
+
selfId,
|
|
197
|
+
);
|
|
159
198
|
}
|
|
160
|
-
pluginCtx.cooldownManager.startCooldownTimer(
|
|
199
|
+
pluginCtx.cooldownManager.startCooldownTimer(
|
|
200
|
+
groupSessionId,
|
|
201
|
+
groupId,
|
|
202
|
+
selfId,
|
|
203
|
+
);
|
|
161
204
|
} else {
|
|
162
205
|
const sentIndices = toolCtx.sentMessageIndices;
|
|
163
206
|
for (let i = 0; i < result.messages.length; i++) {
|
|
164
207
|
if (sentIndices?.has(i)) continue;
|
|
165
|
-
await pluginCtx.sendMessage(
|
|
208
|
+
await pluginCtx.sendMessage(
|
|
209
|
+
ctx,
|
|
210
|
+
undefined,
|
|
211
|
+
userId,
|
|
212
|
+
result.messages[i],
|
|
213
|
+
cfg,
|
|
214
|
+
selfId,
|
|
215
|
+
pluginCtx.audioService,
|
|
216
|
+
);
|
|
166
217
|
}
|
|
167
218
|
if (result.emojiPath) {
|
|
168
219
|
try {
|
|
169
220
|
const emojiSegment = ctx.segment.image(`file://${result.emojiPath}`);
|
|
170
|
-
if (args.isLive) {
|
|
221
|
+
if (args.isLive && actingIsEventBot && event?.reply) {
|
|
171
222
|
await event.reply([emojiSegment]);
|
|
172
223
|
} else {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
224
|
+
if (!actingBot) throw new Error(`bot ${selfId} not found`);
|
|
225
|
+
await actingBot.sendMessage({ type: "private", user_id: userId }, [
|
|
226
|
+
emojiSegment,
|
|
227
|
+
]);
|
|
176
228
|
}
|
|
177
229
|
} catch (err) {
|
|
178
230
|
ctx.logger.warn(
|
|
179
|
-
args.isLive
|
|
231
|
+
args.isLive
|
|
232
|
+
? `[Emoticon] Send failed: ${err}`
|
|
233
|
+
: `[chat-runtime] Send emoji failed: ${err}`,
|
|
180
234
|
);
|
|
181
235
|
}
|
|
182
236
|
}
|
|
@@ -189,12 +243,13 @@ export async function processChat(
|
|
|
189
243
|
e: any,
|
|
190
244
|
pluginCtx: ChatPluginContext,
|
|
191
245
|
runtimeState: ChatRuntimeState,
|
|
246
|
+
options: { replyBot?: Bot } = {},
|
|
192
247
|
): Promise<void> {
|
|
193
248
|
const { ctx } = pluginCtx;
|
|
194
249
|
const isGroup = e.message_type === "group";
|
|
195
250
|
const groupId: number | undefined = isGroup ? e.group_id : undefined;
|
|
196
251
|
const userId: number = e.user_id || e.sender?.user_id;
|
|
197
|
-
const selfId = e.self_id;
|
|
252
|
+
const selfId = options.replyBot ? Number(options.replyBot.bot_id) : e.self_id;
|
|
198
253
|
const cfg = await pluginCtx.getConfig(groupId);
|
|
199
254
|
|
|
200
255
|
const personalSessionId = `personal:${userId}`;
|
|
@@ -212,7 +267,11 @@ export async function processChat(
|
|
|
212
267
|
groupId ?? userId,
|
|
213
268
|
);
|
|
214
269
|
if (groupId) {
|
|
215
|
-
pluginCtx.sessionManager.getOrCreate(
|
|
270
|
+
pluginCtx.sessionManager.getOrCreate(
|
|
271
|
+
personalSessionId,
|
|
272
|
+
"personal",
|
|
273
|
+
userId,
|
|
274
|
+
);
|
|
216
275
|
}
|
|
217
276
|
|
|
218
277
|
const quotedInfo = await getQuotedContent(e, ctx);
|
|
@@ -242,7 +301,7 @@ export async function processChat(
|
|
|
242
301
|
groupId,
|
|
243
302
|
ctx,
|
|
244
303
|
cfg.historyCount,
|
|
245
|
-
|
|
304
|
+
selfId,
|
|
246
305
|
pluginCtx.db,
|
|
247
306
|
pluginCtx.buildHistoryMediaOptions(pluginCtx.aiInstance, cfg),
|
|
248
307
|
)
|
|
@@ -260,15 +319,18 @@ export async function processChat(
|
|
|
260
319
|
}));
|
|
261
320
|
|
|
262
321
|
const botNickname =
|
|
263
|
-
cfg.nicknames[0] ||
|
|
264
|
-
|
|
322
|
+
cfg.nicknames[0] ||
|
|
323
|
+
options.replyBot?.nickname ||
|
|
324
|
+
e.bot?.nickname ||
|
|
325
|
+
"Bot";
|
|
326
|
+
const botRole = groupId ? await getBotRole(groupId, ctx, selfId) : "member";
|
|
265
327
|
let groupName: string | undefined;
|
|
266
328
|
let memberCount: number | undefined;
|
|
267
329
|
if (groupId) {
|
|
268
330
|
const groupInfo = await pluginCtx.getGroupInfoData(
|
|
269
331
|
ctx,
|
|
270
332
|
groupId,
|
|
271
|
-
|
|
333
|
+
selfId,
|
|
272
334
|
e.group_name,
|
|
273
335
|
);
|
|
274
336
|
groupName = groupInfo.groupName;
|
|
@@ -311,7 +373,7 @@ export async function processChat(
|
|
|
311
373
|
pendingImageUrls: imageUrls,
|
|
312
374
|
humanize: pluginCtx.humanize,
|
|
313
375
|
targetMessage,
|
|
314
|
-
selfId
|
|
376
|
+
selfId,
|
|
315
377
|
audioService: pluginCtx.audioService,
|
|
316
378
|
});
|
|
317
379
|
|
|
@@ -351,7 +413,12 @@ export async function processChat(
|
|
|
351
413
|
}
|
|
352
414
|
: undefined,
|
|
353
415
|
),
|
|
354
|
-
{
|
|
416
|
+
{
|
|
417
|
+
userId,
|
|
418
|
+
groupId,
|
|
419
|
+
label: isGroup ? "group-chat" : "private-chat",
|
|
420
|
+
skipRetryOnRateLimit: true,
|
|
421
|
+
},
|
|
355
422
|
);
|
|
356
423
|
|
|
357
424
|
if (!result) {
|
|
@@ -366,7 +433,7 @@ export async function processChat(
|
|
|
366
433
|
groupId,
|
|
367
434
|
groupSessionId,
|
|
368
435
|
userId,
|
|
369
|
-
selfId
|
|
436
|
+
selfId,
|
|
370
437
|
toolCtx,
|
|
371
438
|
send: true,
|
|
372
439
|
isLive: true,
|
|
@@ -435,7 +502,13 @@ async function executeChatRuntimeRequestNow(
|
|
|
435
502
|
}
|
|
436
503
|
|
|
437
504
|
const rawHistory = groupId
|
|
438
|
-
? await getGroupHistory(
|
|
505
|
+
? await getGroupHistory(
|
|
506
|
+
groupId,
|
|
507
|
+
pluginCtx.ctx,
|
|
508
|
+
cfg.historyCount,
|
|
509
|
+
selfId,
|
|
510
|
+
pluginCtx.db,
|
|
511
|
+
)
|
|
439
512
|
: [];
|
|
440
513
|
const history: ChatMessage[] = rawHistory.map((msg) => ({
|
|
441
514
|
sessionId,
|
|
@@ -449,9 +522,10 @@ async function executeChatRuntimeRequestNow(
|
|
|
449
522
|
messageId: msg.messageId,
|
|
450
523
|
}));
|
|
451
524
|
|
|
452
|
-
const botRole = groupId
|
|
453
|
-
|
|
454
|
-
|
|
525
|
+
const botRole = groupId
|
|
526
|
+
? await getBotRole(groupId, pluginCtx.ctx, selfId)
|
|
527
|
+
: "member";
|
|
528
|
+
const botNickname = cfg.nicknames[0] || event?.bot?.nickname || "Bot";
|
|
455
529
|
|
|
456
530
|
let groupName: string | undefined;
|
|
457
531
|
let memberCount: number | undefined;
|
package/handlers/idle-debug.ts
CHANGED
|
@@ -11,7 +11,7 @@ export async function handleIdleCheckDebug(
|
|
|
11
11
|
cfg: ChatConfig,
|
|
12
12
|
): Promise<void> {
|
|
13
13
|
const ctx: MiokuContext = pluginCtx.ctx;
|
|
14
|
-
const isOwner = ctx.
|
|
14
|
+
const isOwner = ctx.isMaster?.(e) ?? false;
|
|
15
15
|
if (!isOwner) {
|
|
16
16
|
await e.reply("只有主人才能使用这个指令~");
|
|
17
17
|
return;
|
package/handlers/message.ts
CHANGED
|
@@ -22,7 +22,6 @@ import {
|
|
|
22
22
|
summarizeHistoryVideo,
|
|
23
23
|
} from "../core/media/history-media";
|
|
24
24
|
import { handleIdleCheckDebug } from "./idle-debug";
|
|
25
|
-
import { handleTtsCommand } from "./tts-command";
|
|
26
25
|
import { processChat } from "../core/chat-turn";
|
|
27
26
|
|
|
28
27
|
const POKE_COOLDOWN_MS = 10 * 60_000;
|
|
@@ -55,25 +54,6 @@ export function createMessageHandler(
|
|
|
55
54
|
return;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
if (text.startsWith("/tts")) {
|
|
59
|
-
const payload = text.replace(/^\/tts\s*/, "");
|
|
60
|
-
await handleTtsCommand(pluginCtx, e, payload);
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (text === "/重置会话") {
|
|
65
|
-
if (groupId) {
|
|
66
|
-
pluginCtx.sessionManager.resetBotMessages(`group:${groupId}`);
|
|
67
|
-
pluginCtx.groupStructuredHistory.clear(`group:${groupId}`);
|
|
68
|
-
await e.reply("已清除本群会话中 AI 发送的消息~");
|
|
69
|
-
} else {
|
|
70
|
-
pluginCtx.sessionManager.resetBotMessages(`personal:${userId}`);
|
|
71
|
-
pluginCtx.groupStructuredHistory.clear(`personal:${userId}`);
|
|
72
|
-
await e.reply("已清除你的个人会话中 AI 发送的消息~");
|
|
73
|
-
}
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
57
|
if (groupId && !isGroupAllowed(groupId, cfg)) return;
|
|
78
58
|
|
|
79
59
|
// 媒体分析
|
|
@@ -222,6 +202,10 @@ export function createMessageHandler(
|
|
|
222
202
|
}
|
|
223
203
|
|
|
224
204
|
const atBot = shouldTrigger(e, text, cfg, ctx);
|
|
205
|
+
const replyBot = ctx.pickReplyBot(e);
|
|
206
|
+
const actorSelfId = replyBot
|
|
207
|
+
? Number(replyBot.bot_id)
|
|
208
|
+
: Number(e.self_id || 0);
|
|
225
209
|
const quotedBot = isGroup ? await isQuotingBot(e, ctx) : null;
|
|
226
210
|
const mentionedNickname =
|
|
227
211
|
cfg.nicknames.length > 0 &&
|
|
@@ -275,14 +259,14 @@ export function createMessageHandler(
|
|
|
275
259
|
groupSessionId,
|
|
276
260
|
groupId,
|
|
277
261
|
delayInfo.delayMs,
|
|
278
|
-
|
|
262
|
+
actorSelfId,
|
|
279
263
|
);
|
|
280
264
|
return;
|
|
281
265
|
}
|
|
282
266
|
}
|
|
283
267
|
|
|
284
268
|
pluginCtx.rateLimiter.record(userId, groupId, text);
|
|
285
|
-
await processChat(e, pluginCtx, runtimeState);
|
|
269
|
+
await processChat(e, pluginCtx, runtimeState, { replyBot });
|
|
286
270
|
return;
|
|
287
271
|
}
|
|
288
272
|
|
|
@@ -294,10 +278,11 @@ export function createMessageHandler(
|
|
|
294
278
|
ctx,
|
|
295
279
|
cfg.historyCount,
|
|
296
280
|
pluginCtx.db,
|
|
297
|
-
|
|
281
|
+
actorSelfId,
|
|
298
282
|
pluginCtx.buildHistoryMediaOptions(pluginCtx.aiInstance, cfg),
|
|
299
283
|
);
|
|
300
|
-
const botNickname =
|
|
284
|
+
const botNickname =
|
|
285
|
+
cfg.nicknames[0] || replyBot?.nickname || e.bot?.nickname || "Bot";
|
|
301
286
|
const planResult = await pluginCtx.humanize.actionPlanner.plan(
|
|
302
287
|
groupSessionId,
|
|
303
288
|
botNickname,
|
|
@@ -307,7 +292,7 @@ export function createMessageHandler(
|
|
|
307
292
|
if (planResult.action !== "reply") return;
|
|
308
293
|
if (!pluginCtx.rateLimiter.canProcess(userId, groupId, text)) return;
|
|
309
294
|
pluginCtx.rateLimiter.record(userId, groupId, text);
|
|
310
|
-
await processChat(e, pluginCtx, runtimeState);
|
|
295
|
+
await processChat(e, pluginCtx, runtimeState, { replyBot });
|
|
311
296
|
}
|
|
312
297
|
};
|
|
313
298
|
|
|
@@ -319,7 +304,7 @@ export function createMessageHandler(
|
|
|
319
304
|
pluginCtx.rateLimiter.recordInteraction(groupId, userId);
|
|
320
305
|
pluginCtx.queueProcessor.scheduleQueuedMessages(
|
|
321
306
|
groupSessionId,
|
|
322
|
-
|
|
307
|
+
actorSelfId,
|
|
323
308
|
);
|
|
324
309
|
}
|
|
325
310
|
return;
|
package/handlers/tts-command.ts
CHANGED
|
@@ -15,7 +15,7 @@ export async function handleTtsCommand(
|
|
|
15
15
|
payload: string,
|
|
16
16
|
): Promise<void> {
|
|
17
17
|
const { ctx } = pluginCtx;
|
|
18
|
-
const isOwner = ctx.
|
|
18
|
+
const isOwner = ctx.isMaster?.(e) ?? false;
|
|
19
19
|
// if (!isOwner) {
|
|
20
20
|
// await e.reply("只有主人才能使用 /tts 指令~");
|
|
21
21
|
// return;
|
package/index.ts
CHANGED
|
@@ -43,6 +43,7 @@ import { RateLimitGuard } from "./manage/rate-limit-guard";
|
|
|
43
43
|
import { createChatRuntime } from "./runtime/chat-runtime";
|
|
44
44
|
import { createMessageHandler } from "./handlers/message";
|
|
45
45
|
import { createPokeHandler } from "./handlers/poke";
|
|
46
|
+
import { handleTtsCommand } from "./handlers/tts-command";
|
|
46
47
|
import { buildHistoryMediaOptions } from "./core/media/segment";
|
|
47
48
|
import type { ChatConfigProvider } from "./humanize";
|
|
48
49
|
import type { ChatPluginContext, ChatHandlerState } from "./context";
|
|
@@ -115,8 +116,6 @@ function resolveRoleInstances(aiService: AIService): {
|
|
|
115
116
|
|
|
116
117
|
export default definePlugin({
|
|
117
118
|
name: "chat",
|
|
118
|
-
version: "1.1.0",
|
|
119
|
-
description: "AI 智能聊天插件",
|
|
120
119
|
async setup(ctx: MiokuContext) {
|
|
121
120
|
ctx.logger.info("聊天插件正在初始化...");
|
|
122
121
|
|
|
@@ -511,6 +510,59 @@ roleModels = resolved.models;
|
|
|
511
510
|
const runtime = createChatRuntime(pluginCtx, getConfig);
|
|
512
511
|
aiService.registerChatRuntime(runtime);
|
|
513
512
|
|
|
513
|
+
ctx.command({
|
|
514
|
+
name: "/重置会话",
|
|
515
|
+
match: /^\/重置会话$/,
|
|
516
|
+
prefixes: false,
|
|
517
|
+
description: "重置自己的AI聊天记录",
|
|
518
|
+
handler: async ({ event }) => {
|
|
519
|
+
if (event.user_id === event.self_id) return;
|
|
520
|
+
const groupId =
|
|
521
|
+
event.message_type === "group" ? Number(event.group_id) : undefined;
|
|
522
|
+
if (groupId) {
|
|
523
|
+
pluginCtx.sessionManager.resetBotMessages(`group:${groupId}`);
|
|
524
|
+
pluginCtx.groupStructuredHistory.clear(`group:${groupId}`);
|
|
525
|
+
await event.reply("已清除本群会话中 AI 发送的消息~");
|
|
526
|
+
} else {
|
|
527
|
+
const userId = Number(event.user_id || event.sender?.user_id || 0);
|
|
528
|
+
pluginCtx.sessionManager.resetBotMessages(`personal:${userId}`);
|
|
529
|
+
pluginCtx.groupStructuredHistory.clear(`personal:${userId}`);
|
|
530
|
+
await event.reply("已清除你的个人会话中 AI 发送的消息~");
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
ctx.command({
|
|
535
|
+
name: "/重置群会话",
|
|
536
|
+
match: /^\/重置群会话$/,
|
|
537
|
+
prefixes: false,
|
|
538
|
+
permission: "admin",
|
|
539
|
+
description: "重置当前群的AI聊天记录",
|
|
540
|
+
handler: async ({ event }) => {
|
|
541
|
+
if (event.user_id === event.self_id) return;
|
|
542
|
+
const groupId =
|
|
543
|
+
event.message_type === "group" ? Number(event.group_id) : undefined;
|
|
544
|
+
if (!groupId) {
|
|
545
|
+
await event.reply("在群里使用试试看吧~", true);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
pluginCtx.sessionManager.resetBotMessages(`group:${groupId}`);
|
|
549
|
+
pluginCtx.groupStructuredHistory.clear(`group:${groupId}`);
|
|
550
|
+
await event.reply("已清除本群会话中 AI 发送的消息~");
|
|
551
|
+
},
|
|
552
|
+
});
|
|
553
|
+
ctx.command({
|
|
554
|
+
name: "/tts",
|
|
555
|
+
match: /^\/tts\s*(.*)$/,
|
|
556
|
+
prefixes: false,
|
|
557
|
+
permission: "owner",
|
|
558
|
+
description: "TTS 推理",
|
|
559
|
+
usage: "/tts <文本>",
|
|
560
|
+
handler: async ({ event, match }) => {
|
|
561
|
+
if (event.user_id === event.self_id) return;
|
|
562
|
+
await handleTtsCommand(pluginCtx, event, String(match?.[1] ?? "").trim());
|
|
563
|
+
},
|
|
564
|
+
});
|
|
565
|
+
|
|
514
566
|
ctx.handle("message", createMessageHandler(pluginCtx, handlerState));
|
|
515
567
|
ctx.handle("notice.group.poke", createPokeHandler(pluginCtx, handlerState));
|
|
516
568
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mioku-plugin-chat",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.4",
|
|
4
4
|
"description": "AI 智能聊天插件",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -17,35 +17,7 @@
|
|
|
17
17
|
"config",
|
|
18
18
|
"help",
|
|
19
19
|
"screenshot"
|
|
20
|
-
]
|
|
21
|
-
"accessHooks": [
|
|
22
|
-
{
|
|
23
|
-
"id": "戳一戳触发对话",
|
|
24
|
-
"event": "notice.group.poke",
|
|
25
|
-
"description": "群内戳一戳 bot"
|
|
26
|
-
}
|
|
27
|
-
],
|
|
28
|
-
"help": {
|
|
29
|
-
"title": "AI 聊天",
|
|
30
|
-
"description": "智能 AI 聊天插件",
|
|
31
|
-
"commands": [
|
|
32
|
-
{
|
|
33
|
-
"cmd": "/重置会话",
|
|
34
|
-
"desc": "重置自己的AI聊天记录",
|
|
35
|
-
"role": "member"
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
"cmd": "/重置群会话",
|
|
39
|
-
"desc": "重置当前群的AI聊天记录",
|
|
40
|
-
"role": "admin"
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
"cmd": "/tts <文本>",
|
|
44
|
-
"desc": "TTS 推理",
|
|
45
|
-
"role": "owner"
|
|
46
|
-
}
|
|
47
|
-
]
|
|
48
|
-
}
|
|
20
|
+
]
|
|
49
21
|
},
|
|
50
22
|
"dependencies": {
|
|
51
23
|
"openai": "^4.0.0",
|
package/utils/message.ts
CHANGED
|
@@ -27,11 +27,7 @@ export function shouldTrigger(
|
|
|
27
27
|
): boolean {
|
|
28
28
|
if (e.message_type === "private") return false;
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
if (!atSeg) return false;
|
|
32
|
-
const data = (atSeg.data ?? {}) as { qq?: unknown; target?: unknown };
|
|
33
|
-
const qq = data.qq ?? data.target;
|
|
34
|
-
return String(qq ?? "") === String(e.self_id ?? "");
|
|
30
|
+
return ctx.mentionedBots(e).length > 0;
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
/**
|
|
@@ -45,8 +41,13 @@ export async function isQuotingBot(
|
|
|
45
41
|
if (e.quote_id) {
|
|
46
42
|
try {
|
|
47
43
|
const quoteMsg = await fetchQuotedMessage(e, ctx);
|
|
48
|
-
|
|
49
|
-
|
|
44
|
+
const quotedUserId = String(quoteMsg?.sender?.user_id ?? "");
|
|
45
|
+
const quotingAnyBot =
|
|
46
|
+
quoteMsg != null &&
|
|
47
|
+
quotedUserId !== "" &&
|
|
48
|
+
ctx.bots.some((bot) => String(bot.bot_id) === quotedUserId);
|
|
49
|
+
if (quotingAnyBot) {
|
|
50
|
+
const quotedText = quoteMsg!.message
|
|
50
51
|
?.filter((s: any) => s.type === "text")
|
|
51
52
|
.map((s: any) => String(s.data?.text ?? s.text ?? ""))
|
|
52
53
|
.join("");
|
|
@@ -130,15 +131,9 @@ export function extractContent(
|
|
|
130
131
|
text = ctx.text(e) || "";
|
|
131
132
|
} catch {}
|
|
132
133
|
|
|
133
|
-
// If text is empty but
|
|
134
|
+
// If text is empty but the message @'d a connected bot, describe the action
|
|
134
135
|
if (!text.trim() && e.message) {
|
|
135
|
-
|
|
136
|
-
if (seg.type !== "at") return false;
|
|
137
|
-
const data = (seg.data ?? {}) as { qq?: unknown; target?: unknown };
|
|
138
|
-
const qq = data.qq ?? data.target;
|
|
139
|
-
return String(qq ?? "") === String(e.self_id ?? "");
|
|
140
|
-
});
|
|
141
|
-
if (hasAt) {
|
|
136
|
+
if (ctx.mentionedBots(e).length > 0) {
|
|
142
137
|
text = "[@you with no text]";
|
|
143
138
|
}
|
|
144
139
|
}
|