From 42d2e51b6005387a62ba6cd3d8cf341174257f4c Mon Sep 17 00:00:00 2001 From: WJG Date: Fri, 14 Jun 2024 09:29:01 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E4=BC=98=E5=8C=96=E8=BD=AE=E8=AF=A2?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E9=94=99=E8=AF=AF=E9=87=8D=E8=AF=95=E7=AD=96?= =?UTF-8?q?=E7=95=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/todo.md | 7 +++--- src/services/speaker/base.ts | 38 ++++++++++++++++++--------------- src/services/speaker/speaker.ts | 8 +++++++ src/utils/retry.ts | 23 ++++++++++++++++++++ 4 files changed, 56 insertions(+), 20 deletions(-) create mode 100644 src/utils/retry.ts diff --git a/docs/todo.md b/docs/todo.md index 2c27c1f..7786f84 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -4,18 +4,19 @@ ## ✨ 新功能 -- ✅ 开放自定义 System Prompt 能力 +- ✅ 新增自定义系统 Prompt 功能 - 登录凭证过期后自动刷新 token https://github.com/idootop/mi-gpt/issues/76 - 支持火山引擎 TTS 和音色切换能力(微软 TTS、OpenAI TTS 待定) ## 💪 优化 -- 优化网络请求错误重试策略(消息/播放状态轮询) +- ✅ 优化网络请求错误重试策略(消息/播放状态轮询) +- 移除 TTS 不发音字符(emoji) - 【待定】使用通知事件获取最新消息和设备播放状态 ## 📚 文档 -- ✅ 添加 System Prompt 模板字符串变量的说明 +- ✅ 添加系统 Prompt 模板字符串变量的说明 - ✅ DAN 模式,猫娘等整活 prompt 的演示示例 - ✅ Awesome prompt 征集 - ✅ 添加更新人设 Prompt 的使用说明(你是 xxx,你喜欢 xxx) diff --git a/src/services/speaker/base.ts b/src/services/speaker/base.ts index 572e755..c059ab0 100644 --- a/src/services/speaker/base.ts +++ b/src/services/speaker/base.ts @@ -9,6 +9,7 @@ import { clamp, jsonEncode, sleep } from "../../utils/base"; import { Logger } from "../../utils/log"; import { StreamResponse } from "./stream"; import { kAreYouOK } from "../../utils/string"; +import { fastRetry } from "../../utils/retry"; export type TTSProvider = "xiaoai" | "doubao"; @@ -337,24 +338,23 @@ export class BaseSpeaker { // 等待一段时间,确保本地设备状态已更新 await sleep(this.checkTTSStatusAfter * 1000); // 等待回答播放完毕 + const retry = fastRetry(this, "设备状态"); while (true) { + // 检测设备播放状态 let playing: any = { status: "idle" }; - if (this.playingCommand) { - const res = await this.MiIOT!.getProperty( - this.playingCommand[0], - this.playingCommand[1] - ); - if (this.debug) { - this.logger.debug(jsonEncode({ playState: res ?? "undefined" })); - } - if (res === this.playingCommand[2]) { - playing = { status: "playing" }; - } - } else { - const res = await this.MiNA!.getStatus(); - if (this.debug) { - this.logger.debug(jsonEncode({ playState: res ?? "undefined" })); - } + let res = this.playingCommand + ? await this.MiIOT!.getProperty( + this.playingCommand[0], + this.playingCommand[1] + ) + : await this.MiNA!.getStatus(); + if (this.debug) { + this.logger.debug(jsonEncode({ playState: res ?? "undefined" })); + } + if (this.playingCommand && res === this.playingCommand[2]) { + playing = { status: "playing" }; + } + if (!this.playingCommand) { playing = { ...playing, ...res }; } if ( @@ -365,7 +365,11 @@ export class BaseSpeaker { // 响应被中断 return "break"; } - if (playing.status !== "playing") { + const isOk = retry.onResponse(res); + if (isOk === "break") { + break; // 获取设备状态异常 + } + if (res && playing.status !== "playing") { break; } await sleep(this.checkInterval); diff --git a/src/services/speaker/speaker.ts b/src/services/speaker/speaker.ts index 8fbb371..0e23e5d 100644 --- a/src/services/speaker/speaker.ts +++ b/src/services/speaker/speaker.ts @@ -1,4 +1,5 @@ import { clamp, firstOf, lastOf, sleep } from "../../utils/base"; +import { fastRetry } from "../../utils/retry"; import { kAreYouOK } from "../../utils/string"; import { BaseSpeaker, BaseSpeakerConfig } from "./base"; import { StreamResponse } from "./stream"; @@ -76,8 +77,13 @@ export class Speaker extends BaseSpeaker { } this.logger.success("服务已启动..."); this.activeKeepAliveMode(); + const retry = fastRetry(this, "消息列表"); while (this.status === "running") { const nextMsg = await this.fetchNextMessage(); + const isOk = retry.onResponse(this._lastConversation); + if (isOk === "break") { + process.exit(1); // 退出应用 + } if (nextMsg) { this.responding = false; this.logger.log("🔥 " + nextMsg.text); @@ -275,6 +281,7 @@ export class Speaker extends BaseSpeaker { } } + private _lastConversation: any; async getMessages(options?: { limit?: number; timestamp?: number; @@ -282,6 +289,7 @@ export class Speaker extends BaseSpeaker { }): Promise { const filterTTS = options?.filterTTS ?? true; const conversation = await this.MiNA!.getConversations(options); + this._lastConversation = conversation; let records = conversation?.records ?? []; if (filterTTS) { // 过滤有小爱回答的消息 diff --git a/src/utils/retry.ts b/src/utils/retry.ts new file mode 100644 index 0000000..9d11d40 --- /dev/null +++ b/src/utils/retry.ts @@ -0,0 +1,23 @@ +import { BaseSpeaker } from "../services/speaker/base"; + +export const fastRetry = (speaker: BaseSpeaker, tag: string, maxRetry = 10) => { + let failed = 0; + return { + onResponse(resp: any) { + if (resp == null) { + failed += 1; + if (failed > maxRetry) { + speaker.logger.error(`获取${tag}异常`); + return "break"; + } + if (speaker.debug) { + speaker.logger.error(`获取${tag}失败,正在重试: ${failed}`); + } + return "retry"; + } else { + failed = 0; + } + return "continue"; + }, + }; +};