mioku-plugin-chat 2.9.0 → 2.9.10

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.
@@ -68,12 +68,7 @@ export async function runChat(
68
68
  return isSkillAllowedForRole(skill, toolCtx.triggerSkillRole);
69
69
  },
70
70
  );
71
- const emotionState = await humanize.emotionAgent.refreshIfNeeded({
72
- sessionId: toolCtx.sessionId,
73
- botNickname: promptCtx.botNickname,
74
- chatHistory: history,
75
- targetMessage,
76
- });
71
+ const emotionState = humanize.emotionAgent.getCurrent(toolCtx.sessionId);
77
72
 
78
73
  const staticCtx: StaticPromptContext = {
79
74
  config: promptCtx.config,
@@ -249,6 +244,17 @@ export async function runChat(
249
244
  ? await ai.withUsageContext(usageContext, runComplete)
250
245
  : await runComplete();
251
246
 
247
+ humanize.emotionAgent
248
+ .refreshIfNeeded({
249
+ sessionId: toolCtx.sessionId,
250
+ botNickname: promptCtx.botNickname,
251
+ chatHistory: history,
252
+ targetMessage,
253
+ })
254
+ .catch((err) =>
255
+ logger.warn(`[chat-engine] background emotion refresh failed: ${err}`),
256
+ );
257
+
252
258
  if (streamEnabled) {
253
259
  streamBuffer += streamThinkFilter.push("", true);
254
260
  await flushStreamBuffer(true);
package/core/chat-turn.ts CHANGED
@@ -312,6 +312,7 @@ export async function processChat(
312
312
  humanize: pluginCtx.humanize,
313
313
  targetMessage,
314
314
  selfId: e.self_id,
315
+ audioService: pluginCtx.audioService,
315
316
  });
316
317
 
317
318
  const result = await pluginCtx.runWithRateLimitGuard(
@@ -497,6 +498,7 @@ async function executeChatRuntimeRequestNow(
497
498
  humanize: pluginCtx.humanize,
498
499
  targetMessage,
499
500
  selfId,
501
+ audioService: pluginCtx.audioService,
500
502
  });
501
503
 
502
504
  if (options.send === false) {
@@ -1,5 +1,6 @@
1
1
  import { logger } from "mioki";
2
2
  import sharp from "sharp";
3
+ import { QQ_IMAGE_FETCH_HEADERS } from "./image-compress";
3
4
 
4
5
  /**
5
6
  * GIF 帧提取结果
@@ -19,7 +20,7 @@ export async function extractGifFrames(
19
20
  ): Promise<GifFramesResult | null> {
20
21
  try {
21
22
  // 下载 GIF
22
- const response = await fetch(gifUrl);
23
+ const response = await fetch(gifUrl, { headers: QQ_IMAGE_FETCH_HEADERS });
23
24
  if (!response.ok) {
24
25
  logger.error(
25
26
  `[gif-extractor] Failed to fetch GIF: ${response.statusText}`,
@@ -102,11 +103,7 @@ export async function isGifUrl(url: string): Promise<boolean> {
102
103
  try {
103
104
  const response = await fetch(url, {
104
105
  method: "GET",
105
- headers: {
106
- "User-Agent":
107
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
108
- Referer: "https://qq.com/",
109
- },
106
+ headers: QQ_IMAGE_FETCH_HEADERS,
110
107
  });
111
108
  const contentType = response.headers.get("content-type");
112
109
  if (contentType && contentType.includes("image/gif")) {
@@ -3,7 +3,10 @@ import type { AIInstance } from "mioku";
3
3
  import { logger } from "mioki";
4
4
  import type { ChatDatabase } from "../../db";
5
5
  import type { ImageRecord } from "../../types";
6
- import { prepareImageUrlsForModel } from "./image-compress";
6
+ import {
7
+ prepareImageUrlsForModel,
8
+ QQ_IMAGE_FETCH_HEADERS,
9
+ } from "./image-compress";
7
10
 
8
11
  export interface ImageAnalysisResult {
9
12
  success: boolean;
@@ -17,7 +20,7 @@ export interface ImageAnalysisOptions {
17
20
 
18
21
  export async function calculateImageHash(url: string): Promise<string | null> {
19
22
  try {
20
- const response = await fetch(url);
23
+ const response = await fetch(url, { headers: QQ_IMAGE_FETCH_HEADERS });
21
24
  if (!response.ok) {
22
25
  logger.warn(
23
26
  `[image-analyzer] Failed to download image for hashing: ${response.status} ${response.statusText}`,
@@ -25,6 +28,14 @@ export async function calculateImageHash(url: string): Promise<string | null> {
25
28
  return null;
26
29
  }
27
30
 
31
+ const contentType = response.headers.get("content-type");
32
+ if (contentType && contentType.startsWith("text/")) {
33
+ logger.warn(
34
+ `[image-analyzer] Non-image content for hashing (${contentType}): ${url}`,
35
+ );
36
+ return null;
37
+ }
38
+
28
39
  const buffer = Buffer.from(await response.arrayBuffer());
29
40
  return crypto.createHash("md5").update(buffer).digest("hex");
30
41
  } catch (err) {
@@ -5,12 +5,14 @@ const IMAGE_MAX_BYTES = 1 * 1024 * 1024;
5
5
  const COMPRESS_MAX_WIDTH = 1280;
6
6
  const COMPRESS_JPEG_QUALITY = 80;
7
7
 
8
- const FETCH_HEADERS = {
8
+ export const QQ_IMAGE_FETCH_HEADERS = {
9
9
  "User-Agent":
10
10
  "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
11
11
  Referer: "https://qq.com/",
12
12
  };
13
13
 
14
+ const FETCH_HEADERS = QQ_IMAGE_FETCH_HEADERS;
15
+
14
16
  /**
15
17
  * 准备发给模型的图片 URL:体积超过 1MB 时压缩为 JPEG data URL,否则原样返回。
16
18
  * data URL(如 GIF 抽帧结果)与非 http(s) 链接直接放行。
@@ -81,6 +81,7 @@ export async function handleIdleCheckDebug(
81
81
  humanize: pluginCtx.humanize,
82
82
  targetMessage,
83
83
  selfId: e.self_id,
84
+ audioService: pluginCtx.audioService,
84
85
  });
85
86
 
86
87
  const result = await pluginCtx.runWithRateLimitGuard(
package/handlers/poke.ts CHANGED
@@ -86,6 +86,7 @@ export function createPokeHandler(
86
86
  humanize: pluginCtx.humanize,
87
87
  targetMessage,
88
88
  selfId: e.self_id,
89
+ audioService: pluginCtx.audioService,
89
90
  });
90
91
 
91
92
  const result = await pluginCtx.runWithRateLimitGuard(
@@ -16,10 +16,10 @@ export async function handleTtsCommand(
16
16
  ): Promise<void> {
17
17
  const { ctx } = pluginCtx;
18
18
  const isOwner = ctx.isOwner?.(e) ?? false;
19
- if (!isOwner) {
20
- await e.reply("只有主人才能使用 /tts 指令~");
21
- return;
22
- }
19
+ // if (!isOwner) {
20
+ // await e.reply("只有主人才能使用 /tts 指令~");
21
+ // return;
22
+ // }
23
23
 
24
24
  const text = String(payload || "").trim();
25
25
  if (!text) {
@@ -42,7 +42,9 @@ export async function handleTtsCommand(
42
42
  return;
43
43
  }
44
44
 
45
- ctx.logger.info(`[tts-cmd] 推理: "${text.slice(0, 40)}" lang=${detectLang(text)}`);
45
+ ctx.logger.info(
46
+ `[tts-cmd] 推理: "${text.slice(0, 40)}" lang=${detectLang(text)}`,
47
+ );
46
48
 
47
49
  let result;
48
50
  try {
@@ -227,6 +227,7 @@ export class CooldownManager {
227
227
  humanize: this.humanize,
228
228
  targetMessage,
229
229
  selfId,
230
+ audioService: this.pluginCtx.audioService,
230
231
  });
231
232
 
232
233
  const contexts = await this.getHumanizeContexts(
@@ -353,6 +354,7 @@ export class CooldownManager {
353
354
  humanize: this.humanize,
354
355
  targetMessage,
355
356
  selfId,
357
+ audioService: this.pluginCtx.audioService,
356
358
  });
357
359
  const { groupName, memberCount } = await this.getGroupInfoData(
358
360
  this.ctx,
@@ -254,6 +254,7 @@ export class IdleCheckManager {
254
254
  humanize: this.humanize,
255
255
  targetMessage,
256
256
  selfId,
257
+ audioService: this.pluginCtx.audioService,
257
258
  });
258
259
 
259
260
  const result = await this.runWithRateLimitGuard(
@@ -184,6 +184,7 @@ export class QueueProcessor {
184
184
  const toolCtx = this.buildToolContext({
185
185
  ctx: this.ctx, event: firstMsg.event, groupSessionId, groupId, userId: firstMsg.userId,
186
186
  config: cfg, aiService: this.aiService, db: this.db, botRole, humanize: this.humanize, targetMessage, selfId,
187
+ audioService: this.pluginCtx.audioService,
187
188
  });
188
189
 
189
190
  this.sessionManager.getOrCreate(groupSessionId, "group", groupId);
@@ -264,6 +265,7 @@ export class QueueProcessor {
264
265
  const toolCtx = this.buildToolContext({
265
266
  ctx: this.ctx, event: null, groupSessionId, groupId, userId: targetMessage.userId,
266
267
  config: cfg, aiService: this.aiService, db: this.db, botRole, humanize: this.humanize, targetMessage, selfId,
268
+ audioService: this.pluginCtx.audioService,
267
269
  });
268
270
 
269
271
  const { history } = await this.getGroupHistoryMessages(groupId, groupSessionId, this.ctx, cfg.historyCount, this.db, selfId, this.buildHistoryMediaOptions(this.aiInstance, cfg));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mioku-plugin-chat",
3
- "version": "2.9.0",
3
+ "version": "2.9.10",
4
4
  "description": "AI 智能聊天插件",
5
5
  "main": "index.ts",
6
6
  "type": "module",