From 4f3a0b4c8e5485b733a233a4a442199d51a5f761 Mon Sep 17 00:00:00 2001 From: baiyu-yu <135424680+baiyu-yu@users.noreply.github.com> Date: Tue, 17 Feb 2026 23:25:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=9D=9E=E6=B5=81?= =?UTF-8?q?=E5=BC=8F=E6=B6=88=E6=81=AF=E5=88=86=E6=AE=B5=E7=9A=84=E5=8F=91?= =?UTF-8?q?=E9=80=81=E5=BB=B6=E8=BF=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/AI/AI.ts | 25 ++++++++++++++++++++----- src/config/config_reply.ts | 8 +++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/AI/AI.ts b/src/AI/AI.ts index b9e3ae1..c3661c1 100644 --- a/src/AI/AI.ts +++ b/src/AI/AI.ts @@ -103,10 +103,25 @@ export class AI { await ai.context.addMessage(ctx, msg, ai, content, images, 'user', transformMsgId(msg.rawId)); } - async reply(ctx: seal.MsgContext, msg: seal.Message, contextArray: string[], replyArray: string[], images: Image[]) { + async reply(ctx: seal.MsgContext, msg: seal.Message, contextArray: string[], replyArray: string[], images: Image[], options: { withNonStreamDelay?: boolean } = {}) { + const { withNonStreamDelay = false } = options; + const { nonStreamSegmentDelayEnabled, nonStreamSegmentDelayMs, nonStreamSegmentImageExtraDelayMs } = ConfigManager.reply; + for (let i = 0; i < contextArray.length; i++) { const content = contextArray[i]; const reply = replyArray[i]; + + // 非流式延迟 + if (withNonStreamDelay && nonStreamSegmentDelayEnabled && i > 0) { + let delayMs = Math.max(0, nonStreamSegmentDelayMs); + if (/\[CQ:image(?:,[^\]]*)?\]/.test(reply)) { + delayMs += Math.max(0, nonStreamSegmentImageExtraDelayMs); + } + if (delayMs > 0) { + await new Promise(resolve => setTimeout(resolve, delayMs)); + } + } + const msgId = await replyToSender(ctx, msg, this, reply); await this.context.addMessage(ctx, msg, this, content, images, 'assistant', msgId); } @@ -186,7 +201,7 @@ export class AI { logger.info(`触发工具调用`); // 先给他回复了再说 const { contextArray, replyArray, images } = result; - await this.reply(ctx, msg, contextArray, replyArray, images); + await this.reply(ctx, msg, contextArray, replyArray, images, { withNonStreamDelay: true }); await this.context.addMessage(ctx, msg, this, match[0], [], "assistant", ''); try { @@ -202,7 +217,7 @@ export class AI { logger.info(`触发工具调用`); // 先给他回复了再说 const { contextArray, replyArray, images } = result; - await this.reply(ctx, msg, contextArray, replyArray, images); + await this.reply(ctx, msg, contextArray, replyArray, images, { withNonStreamDelay: true }); this.context.addToolCallsMessage(tool_calls); try { @@ -233,7 +248,7 @@ export class AI { } const { contextArray, replyArray, images } = result; - await this.reply(ctx, msg, contextArray, replyArray, images); + await this.reply(ctx, msg, contextArray, replyArray, images, { withNonStreamDelay: true }); AIManager.saveAI(this.id); } @@ -584,4 +599,4 @@ export class AIManager { return usage; } -} \ No newline at end of file +} diff --git a/src/config/config_reply.ts b/src/config/config_reply.ts index 4e37eb8..54a4139 100644 --- a/src/config/config_reply.ts +++ b/src/config/config_reply.ts @@ -38,6 +38,9 @@ export class ReplyConfig { "\n{{{match.[1]}}}" ], "替换匹配到的文本,与上面正则表达式序号对应"); seal.ext.registerBoolConfig(ReplyConfig.ext, "回复文本是否去除首尾空白字符", true, ""); + seal.ext.registerBoolConfig(ReplyConfig.ext, "非流式分段发送延时", true, "仅非流式生效,消息间隔是否开启延时防止乱序"); + seal.ext.registerIntConfig(ReplyConfig.ext, "非流式分段发送基础延时/ms", 350, "仅非流式生效,从第二条消息开始每条发送前等待的毫秒数"); + seal.ext.registerIntConfig(ReplyConfig.ext, "非流式分段发送含图额外延时/ms", 250, "仅非流式生效,当消息包含图片时额外增加的等待毫秒数"); } static get() { @@ -50,7 +53,10 @@ export class ReplyConfig { filterRegexes: ConfigManager.getRegexesConfig(ReplyConfig.ext, "回复消息过滤正则表达式"), contextTemplates: ConfigManager.getHandlebarsTemplatesConfig(ReplyConfig.ext, "正则处理上下文消息模板"), replyTemplates: ConfigManager.getHandlebarsTemplatesConfig(ReplyConfig.ext, "正则处理回复消息模板"), - isTrim: seal.ext.getBoolConfig(ReplyConfig.ext, "回复文本是否去除首尾空白字符") + isTrim: seal.ext.getBoolConfig(ReplyConfig.ext, "回复文本是否去除首尾空白字符"), + nonStreamSegmentDelayEnabled: seal.ext.getBoolConfig(ReplyConfig.ext, "非流式分段发送延时"), + nonStreamSegmentDelayMs: seal.ext.getIntConfig(ReplyConfig.ext, "非流式分段发送基础延时/ms"), + nonStreamSegmentImageExtraDelayMs: seal.ext.getIntConfig(ReplyConfig.ext, "非流式分段发送含图额外延时/ms") } } } \ No newline at end of file