From 7ae469757485166464ee08c12110fad0180ee944 Mon Sep 17 00:00:00 2001 From: WJG Date: Sun, 26 May 2024 22:32:16 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20onAIReplied=20?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .migpt.example.js | 8 +++--- README.md | 9 ++++--- src/services/speaker/ai.ts | 55 +++++++++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/.migpt.example.js b/.migpt.example.js index 63d28ea..a0900ad 100644 --- a/.migpt.example.js +++ b/.migpt.example.js @@ -34,10 +34,10 @@ export default { // 设备唤醒指令 wakeUpCommand: [5, 3], // 当消息以下面的关键词开头时,会调用 AI 来回复消息 - callAIPrefix: ["请", "你", "傻妞"], - // 当消息中包含唤醒关键词时,会进入 AI 唤醒状态 + callAIKeywords: ["请", "你", "傻妞"], + // 当消息以下面的关键词开头时,会进入 AI 唤醒状态 wakeUpKeywords: ["打开", "进入", "召唤"], - // 当消息中包含退出关键词时,会退出 AI 唤醒状态 + // 当消息以下面的关键词开头时,会退出 AI 唤醒状态 exitKeywords: ["关闭", "退出", "再见"], // 进入 AI 模式的欢迎语 onEnterAI: ["你好,我是傻妞,很高兴认识你"], @@ -45,6 +45,8 @@ export default { onExitAI: ["傻妞已退出"], // AI 开始回答时的提示语 onAIAsking: ["让我先想想", "请稍等"], + // AI 结束回答时的提示语 + onAIReplied: ["我说完了", "还有其他问题吗"], // AI 回答异常时的提示语 onAIError: ["啊哦,出错了,请稍后再试吧!"], // 无响应一段时间后,多久自动退出唤醒模式(默认 30 秒) diff --git a/README.md b/README.md index ab835c0..d020c49 100644 --- a/README.md +++ b/README.md @@ -126,12 +126,13 @@ main(); | `ttsCommand` | 小米音箱 TTS 指令([可在此查询](https://home.miot-spec.com)) | `[5, 1]` | | `wakeUpCommand` | 小米音箱唤醒指令([可在此查询](https://home.miot-spec.com)) | `[5, 3]` | | **speaker 其他参数(可选)** | | | -| `callAIPrefix` | 当消息以召唤关键词开头时,会调用 AI 来响应用户消息 | `["请","傻妞"]` | -| `wakeUpKeywords` | 当消息中包含唤醒关键词时,会进入 AI 唤醒状态 | `["召唤傻妞","打开傻妞"]` | -| `exitKeywords` | 当消息中包含退出关键词时,会退出 AI 唤醒状态 | `["退出傻妞","关闭傻妞"]` | +| `callAIKeywords` | 当消息以关键词开头时,会调用 AI 来响应用户消息 | `["请", "傻妞"]` | +| `wakeUpKeywords` | 当消息以关键词开头时,会进入 AI 唤醒状态 | `["召唤傻妞", "打开傻妞"]` | +| `exitKeywords` | 当消息以关键词开头时,会退出 AI 唤醒状态 | `["退出傻妞", "关闭傻妞"]` | | `onEnterAI` | 进入 AI 模式的欢迎语 | `["你好,我是傻妞,很高兴认识你"]` | | `onExitAI` | 退出 AI 模式的提示语 | `["傻妞已退出"]` | -| `onAIAsking` | AI 开始回答时的提示语 | `["请稍等,让我想想"]` | +| `onAIAsking` | AI 开始回答时的提示语 | `["让我先想想", "请稍等"]` | +| `onAIReplied` | AI 结束回答时的提示语 | `["我说完了", "还有其他问题吗"]` | | `onAIError` | AI 回答异常时的提示语 | `["出错了,请稍后再试吧!"]` | | `exitKeepAliveAfter` | 无响应一段时间后,多久自动退出唤醒模式(单位秒,默认 30 秒) | `30` | diff --git a/src/services/speaker/ai.ts b/src/services/speaker/ai.ts index 4dc1d07..1d8f041 100644 --- a/src/services/speaker/ai.ts +++ b/src/services/speaker/ai.ts @@ -15,6 +15,12 @@ export type AISpeakerConfig = SpeakerConfig & { * 比如:请稍等,让我想想 */ onAIAsking?: string[]; + /** + * AI 结束回答时的提示语 + * + * 比如:我说完了,还有替他问题吗? + */ + onAIReplied?: string[]; /** * AI 回答异常时的提示语 * @@ -34,7 +40,7 @@ export type AISpeakerConfig = SpeakerConfig & { * * 比如:请,你,问问傻妞 */ - callAIPrefix?: string[]; + callAIKeywords?: string[]; /** * 切换音色前缀 * @@ -90,10 +96,11 @@ export class AISpeaker extends Speaker { switchSpeakerPrefix: string[]; onEnterAI: string[]; onExitAI: string[]; - callAIPrefix: string[]; + callAIKeywords: string[]; wakeUpKeywords: string[]; exitKeywords: string[]; onAIAsking: string[]; + onAIReplied: string[]; onAIError: string[]; audioActive?: string; audioError?: string; @@ -104,29 +111,32 @@ export class AISpeaker extends Speaker { askAI, name = "傻妞", switchSpeakerPrefix, - callAIPrefix = ["请", "你", "傻妞"], + callAIKeywords = ["请", "你", "傻妞"], wakeUpKeywords = ["打开", "进入", "召唤"], exitKeywords = ["关闭", "退出", "再见"], onEnterAI = ["你好,我是傻妞,很高兴认识你"], onExitAI = ["傻妞已退出"], onAIAsking = ["让我先想想", "请稍等"], + onAIReplied = ["我说完了", "还有其他问题吗"], onAIError = ["啊哦,出错了,请稍后再试吧!"], audioActive = process.env.AUDIO_ACTIVE, audioError = process.env.AUDIO_ERROR, } = config; this.askAI = askAI; this.name = name; - this.onAIError = onAIError; - this.onAIAsking = onAIAsking; - this.audioActive = audioActive; - this.audioError = audioError; - this.switchSpeakerPrefix = - switchSpeakerPrefix ?? getDefaultSwitchSpeakerPrefix(); + this.callAIKeywords = callAIKeywords; + this.wakeUpKeywords = wakeUpKeywords; this.exitKeywords = exitKeywords; this.onEnterAI = onEnterAI; this.onExitAI = onExitAI; - this.callAIPrefix = callAIPrefix; + this.onAIError = onAIError; + this.onAIAsking = onAIAsking; + this.onAIReplied = onAIReplied; + this.audioActive = audioActive; + this.audioError = audioError; + this.switchSpeakerPrefix = + switchSpeakerPrefix ?? getDefaultSwitchSpeakerPrefix(); } async enterKeepAlive() { @@ -184,7 +194,7 @@ export class AISpeaker extends Speaker { { match: (msg) => this.keepAlive || - this.callAIPrefix.some((e) => msg.text.startsWith(e)), + this.callAIKeywords.some((e) => msg.text.startsWith(e)), run: (msg) => this.askAIForAnswer(msg), }, ] as SpeakerCommand[]; @@ -203,16 +213,36 @@ export class AISpeaker extends Speaker { let answer = await this.askAI?.(msg); return { data: { answer } }; }, + async (msg, data) => { + // 开始回复 + if (data.answer) { + const res = await this.response({ ...data.answer }); + return { data: { ...data, res } }; + } + }, + async (msg, data) => { + if (data.answer && data.res !== "break") { + // 回复完毕 + await this.response({ + text: pickOne(this.onAIReplied)!, + }); + } + }, async (msg, data) => { if (!data.answer) { // 回答异常 await this.response({ audio: this.audioError, text: pickOne(this.onAIError)!, - keepAlive: this.keepAlive, }); } }, + async (msg, data) => { + if (this.keepAlive) { + // 重新唤醒 + await this.wakeUp(); + } + }, ]; async askAIForAnswer(msg: QueryMessage) { @@ -231,7 +261,6 @@ export class AISpeaker extends Speaker { break; } } - return data.answer; } }