From 220af8068e38d5919123f1f24bf360c57b2db30c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=81=A5=E8=B1=AA?= Date: Fri, 21 Mar 2025 14:59:01 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9F=B3=E4=B9=90?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E6=96=AD=E5=BC=80bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复音乐播放速度太快导致设备内存溢出断开连接的问题 --- .../core/handle/sendAudioHandle.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/main/xiaozhi-server/core/handle/sendAudioHandle.py b/main/xiaozhi-server/core/handle/sendAudioHandle.py index 8999bf08..a6fed97b 100644 --- a/main/xiaozhi-server/core/handle/sendAudioHandle.py +++ b/main/xiaozhi-server/core/handle/sendAudioHandle.py @@ -14,33 +14,37 @@ async def sendAudioMessage(conn, audios, text, text_index=0): await send_tts_message(conn, "sentence_start", text) # 流控参数优化 - original_frame_duration = 60 # 原始帧时长(毫秒) - adjusted_frame_duration = int(original_frame_duration * 0.8) # 缩短20% - total_frames = len(audios) # 获取总帧数 - compensation = total_frames * (original_frame_duration - adjusted_frame_duration) / 1000 # 补偿时间(秒) - + frame_duration = 62 # 帧时长(毫秒),增加余量 start_time = time.perf_counter() play_position = 0 # 已播放时长(毫秒) - for opus_packet in audios: + # 预发送前 n 帧 + pre_buffer = min(5, len(audios)) + for i in range(pre_buffer): + await conn.websocket.send(audios[i]) + conn.logger.bind(tag=TAG).debug(f"预缓冲帧 {i}") + + # 正常播放剩余帧 + for opus_packet in audios[pre_buffer:]: if conn.client_abort: return - - # 计算带加速因子的预期时间 + + # 计算预期发送时间 expected_time = start_time + (play_position / 1000) current_time = time.perf_counter() - - # 流控等待(使用加速后的帧时长) delay = expected_time - current_time if delay > 0: await asyncio.sleep(delay) - await conn.websocket.send(opus_packet) - play_position += adjusted_frame_duration # 使用调整后的帧时长 + send_start = time.perf_counter() - # 补偿因加速损失的时长 - if compensation > 0: - await asyncio.sleep(compensation) + await conn.websocket.send(opus_packet) + + send_duration = (time.perf_counter() - send_start) * 1000 + logger.bind(tag=TAG).debug(f"发送帧,位置: {play_position}ms, 实际间隔: {(time.perf_counter() - current_time) * 1000:.2f}ms, 发送耗时: {send_duration:.2f}ms") + + # 动态调整下次延迟,补偿发送耗时 + play_position += frame_duration # 更新播放位置 await send_tts_message(conn, "sentence_end", text) From 49cb98a60654871f6a645d2867079501b851366d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=81=A5=E8=B1=AA?= Date: Mon, 24 Mar 2025 09:28:01 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=9F=B3=E4=B9=90?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E5=8D=A1=E9=A1=BF=E5=92=8C=E6=96=AD=E8=BF=9E?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/handle/sendAudioHandle.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/main/xiaozhi-server/core/handle/sendAudioHandle.py b/main/xiaozhi-server/core/handle/sendAudioHandle.py index ffb36398..c0a664eb 100644 --- a/main/xiaozhi-server/core/handle/sendAudioHandle.py +++ b/main/xiaozhi-server/core/handle/sendAudioHandle.py @@ -28,15 +28,15 @@ async def sendAudioMessage(conn, audios, text, text_index=0): # 播放音频 async def sendAudio(conn, audios): # 流控参数优化 - frame_duration = 62 # 帧时长(毫秒),增加余量 + frame_duration = 60 # 帧时长(毫秒),匹配 Opus 编码 start_time = time.perf_counter() - play_position = 0 # 已播放时长(毫秒) + play_position = 0 - # 预发送前 n 帧 - pre_buffer = min(5, len(audios)) + # 预缓冲:发送前 3 帧 + pre_buffer = min(3, len(audios)) for i in range(pre_buffer): await conn.websocket.send(audios[i]) - conn.logger.bind(tag=TAG).debug(f"预缓冲帧 {i}") + conn.logger.bind(tag=TAG).debug(f"预缓冲帧 {i}, 时间: {(time.perf_counter() - start_time) * 1000:.2f}ms") # 正常播放剩余帧 for opus_packet in audios[pre_buffer:]: @@ -50,15 +50,11 @@ async def sendAudio(conn, audios): if delay > 0: await asyncio.sleep(delay) - send_start = time.perf_counter() - await conn.websocket.send(opus_packet) + conn.logger.bind(tag=TAG).debug(f"发送帧,位置: {play_position}ms, 实际间隔: {(time.perf_counter() - current_time) * 1000:.2f}ms") - send_duration = (time.perf_counter() - send_start) * 1000 - logger.bind(tag=TAG).debug(f"发送帧,位置: {play_position}ms, 实际间隔: {(time.perf_counter() - current_time) * 1000:.2f}ms, 发送耗时: {send_duration:.2f}ms") + play_position += frame_duration - # 动态调整下次延迟,补偿发送耗时 - play_position += frame_duration # 更新播放位置 async def send_tts_message(conn, state, text=None): From 52a66ea304b9c81836f86dfcc73419b593b8f8e3 Mon Sep 17 00:00:00 2001 From: CGD <3030332422@qq.com> Date: Mon, 24 Mar 2025 17:27:08 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E5=AE=8C=E6=88=90=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E6=99=BA=E8=83=BD=E4=BD=93=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/apis/module/user.js | 32 +-- .../manager-web/src/components/DeviceItem.vue | 5 +- main/manager-web/src/components/HeaderBar.vue | 29 +- main/manager-web/src/views/ModelConfig.vue | 247 +++++++++++------- main/manager-web/src/views/roleConfig.vue | 105 +++++--- 5 files changed, 256 insertions(+), 162 deletions(-) diff --git a/main/manager-web/src/apis/module/user.js b/main/manager-web/src/apis/module/user.js index 2e9bc6e2..b0db55b8 100755 --- a/main/manager-web/src/apis/module/user.js +++ b/main/manager-web/src/apis/module/user.js @@ -112,22 +112,6 @@ export default { }); }).send(); }, - // 获取设备配置 - getDeviceConfig(device_id, callback) { - RequestService.sendRequest() - .url(`${getServiceUrl()}/api/v1/user/configDevice/${device_id}`) - .method('GET') - .success((res) => { - RequestService.clearRequestTime(); - callback(res); - }) - .fail((err) => { - console.error('获取配置失败:', err); - RequestService.reAjaxFun(() => { - this.getDeviceConfig(device_id, callback); - }); - }).send(); - }, // 获取所有模型名称 getModelNames(callback) { RequestService.sendRequest() @@ -221,5 +205,21 @@ export default { }); }).send(); }, + // 获取智能体配置 + getDeviceConfig(deviceId, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/api/v1/user/agent/${deviceId}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('获取配置失败:', err); + RequestService.reAjaxFun(() => { + this.getDeviceConfig(deviceId, callback); + }); + }).send(); + }, } diff --git a/main/manager-web/src/components/DeviceItem.vue b/main/manager-web/src/components/DeviceItem.vue index cb878388..4f651482 100644 --- a/main/manager-web/src/components/DeviceItem.vue +++ b/main/manager-web/src/components/DeviceItem.vue @@ -17,7 +17,7 @@ 音色模型:{{ device.ttsVoiceName }}
-
+
配置角色
@@ -48,6 +48,9 @@ export default { methods: { handleDelete() { this.$emit('delete', this.device.agentId) + }, + handleConfigure() { + this.$router.push({ path: '/role-config', query: { agentId: this.device.agentId } }); } } } diff --git a/main/manager-web/src/components/HeaderBar.vue b/main/manager-web/src/components/HeaderBar.vue index a8dff30c..2d349e7f 100644 --- a/main/manager-web/src/components/HeaderBar.vue +++ b/main/manager-web/src/components/HeaderBar.vue @@ -4,14 +4,14 @@
-
+
智能体管理
-
+
用户管理
-
+
模型配置
@@ -104,26 +104,7 @@ export default { diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index d0f0000e..d4fd94db 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -17,7 +17,7 @@
- +
@@ -30,7 +30,7 @@
- + @@ -45,13 +45,13 @@
+ v-model="form.systemPrompt" maxlength="2000" show-word-limit/>
+ v-model="form.memModelld" maxlength="1000"/>
当前记忆(每次对话后重新生成)
@@ -60,7 +60,7 @@ 清除
-
{{ form.prompt.length }}/1000
+
{{ form.systemPrompt.length }}/1000
@@ -106,33 +106,35 @@ export default { return { deviceMac: 'CC:ba:97:11:a6:ac', form: { - name: "", - timbre: "", - introduction: "", - prompt: "", + agentCode:"", + agentName: "", + ttsVoiceId: "", + systemPrompt: "", + langCode:"", + language:"", + sort:"", model: { - tts: "", - vad: "", - asr: "", - llm: "", - memory:"", - intent:"" + ttsModelId: "", + vadModelId: "", + asrModelId:"", + llmModelId: "", + memModelId: "", + intentModelId: "", } }, - options: [ - { value: '选项1', label: '黄金糕' }, - { value: '选项2', label: '双皮奶' } - ], + options: [ + { value: '选项1', label: '黄金糕' }, + { value: '选项2', label: '双皮奶' } + ], models: [ - { label: '大语言模型(LLM)', key: 'llm' }, - { label: '语音识别(ASR)', key: 'asr' }, - { label: '语音活动检测模型(VAD)', key: 'vad' }, - { label: '语音合成模型(TTS)', key: 'tts' }, - { label: '意图识别模型(Intent)', key: 'intent' }, - { label: '记忆模型(Memory)', key: 'memory' } - ], + { label: '大语言模型(LLM)', key: 'llm' }, + { label: '语音识别(ASR)', key: 'asr' }, + { label: '语音活动检测模型(VAD)', key: 'vad' }, + { label: '语音合成模型(TTS)', key: 'tts' }, + { label: '意图识别模型(Intent)', key: 'intent' }, + { label: '记忆模型(Memory)', key: 'memory' } + ], templates: ['台湾女友', '土豆子', '英语老师', '好奇小男孩', '汪汪队队长'] - } }, methods: { @@ -148,20 +150,57 @@ export default { }).then(() => { // 重置表单 this.form = { - name: "", - timbre: "", - introduction: "", - prompt: "", - model: "" + agentCode:"", + agentName: "", + ttsVoiceId: "", + systemPrompt: "", + langCode:"", + language:"", + sort:"", + model: { + ttsModelId: "", + vadModelId: "", + asrModelId:"", + llmModelId: "", + memModelId: "", + intentModelId: "", + } } this.$message.success('配置已重置') }).catch(() => { }) }, - // 处理选择模板的逻辑 selectTemplate(template) { this.form.name = template; this.$message.success(`已选择模板:${template}`); + }, + fetchAgentConfig(agentId) { + import('@/apis/module/user').then(({ default: userApi }) => { + userApi.getDeviceConfig(agentId, ({ data }) => { + if (data.code === 0) { + this.form = { + ...this.form, + ...data.data, + model: { + ttsModelId: data.data.ttsModelId, + vadModelId: data.data.vadModelId, + asrModelId: data.data.asrModelId, + llmModelId: data.data.llmModelId, + memModelId: data.data.memModelId, + intentModelId: data.data.intentModelId + } + }; + } else { + this.$message.error(data.msg || '获取配置失败'); + } + }); + }); + } +}, + mounted() { + const agentId = this.$route.query.agentId; + if (agentId) { + this.fetchAgentConfig(agentId); } } } From a3b3079b63f0924905163ff655859a14b2999752 Mon Sep 17 00:00:00 2001 From: CGD <3030332422@qq.com> Date: Mon, 24 Mar 2025 22:41:32 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E5=AE=8C=E6=88=90=E2=80=9C=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=99=BA=E8=83=BD=E4=BD=93=E2=80=9C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-web/src/apis/module/user.js | 17 +++++ main/manager-web/src/views/roleConfig.vue | 92 +++++++++++++++-------- 2 files changed, 76 insertions(+), 33 deletions(-) diff --git a/main/manager-web/src/apis/module/user.js b/main/manager-web/src/apis/module/user.js index b0db55b8..ddec6f04 100755 --- a/main/manager-web/src/apis/module/user.js +++ b/main/manager-web/src/apis/module/user.js @@ -221,5 +221,22 @@ export default { }); }).send(); }, + // 智能体配置 + updateAgentConfig(agentId, configData, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/api/v1/user/agent/${agentId}`) + .method('PUT') + .data(configData) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .fail((err) => { + console.error('保存配置失败:', err); + RequestService.reAjaxFun(() => { + this.updateAgentConfig(agentId, configData, callback); + }); + }).send(); + }, } diff --git a/main/manager-web/src/views/roleConfig.vue b/main/manager-web/src/views/roleConfig.vue index d4fd94db..e8fd0ade 100644 --- a/main/manager-web/src/views/roleConfig.vue +++ b/main/manager-web/src/views/roleConfig.vue @@ -1,6 +1,5 @@