From 1cbb2653a688091f0c3ef5891051d2fbef5a09b6 Mon Sep 17 00:00:00 2001 From: fsy Date: Sat, 22 Mar 2025 15:04:59 +0800 Subject: [PATCH] =?UTF-8?q?3s=E6=B2=A1=E6=9C=89=E6=8E=A5=E5=8F=97=E5=88=B0?= =?UTF-8?q?=E6=96=B0=E6=B6=88=E6=81=AF=E6=89=8D=E4=BC=9A=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=96=B0=E8=81=8A=E5=A4=A9=E6=A1=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/services/agora.js | 88 ++++++++++++++++++++++++++++--------------- src/stores/chat.js | 65 +++++++++++++++++++++++++++----- 2 files changed, 114 insertions(+), 39 deletions(-) diff --git a/src/services/agora.js b/src/services/agora.js index f6c971f..cd799d2 100644 --- a/src/services/agora.js +++ b/src/services/agora.js @@ -20,6 +20,7 @@ class AgoraService { this.inConversation = false; // 是否在对话状态中 this.speechSegmentCallback = null; // 语音段落回调函数 this.readableTextCallback = null; // 可读文本回调函数 + this.lastMessageTime = null; // 最后一次消息接收时间,用于判断是否需要创建新消息 } /** @@ -40,45 +41,71 @@ class AgoraService { this.client.on('stream-message', (uid, message) => { try { - // 确认接收到的是字节流(Uint8Array) - if (message instanceof Uint8Array) { - const decodedMessage = new TextDecoder().decode(message); - // console.log('Decoded message (Raw String):', decodedMessage); - - const parts = decodedMessage.split('|'); - const base64Data = parts[parts.length - 1]; - // console.log('Extracted Base64 data:', base64Data); - - const jsonString = atob(base64Data); - console.log('Decoded JSON string:', jsonString); - - jsonBuffer += jsonString; - if (isCompleteJson(jsonBuffer)) { - const jsonData = JSON.parse(jsonString); // 将字符串解析为 JSON 对象 - console.log('Parsed JSON object:', jsonData); + // 确认接收到的是字节流(Uint8Array) + if (message instanceof Uint8Array) { + const decodedMessage = new TextDecoder().decode(message); + const parts = decodedMessage.split('|'); + const base64Data = parts[parts.length - 1]; - if (this.readableTextCallback && typeof this.readableTextCallback === 'function') { - this.readableTextCallback(jsonData.text); // 传递解码后的文本到回调 + const jsonString = atob(base64Data); + console.log('Decoded JSON string:', jsonString); + + // 如果新的JSON字符串以 { 开头,说明是一个新的JSON对象的开始 + // 丢弃之前已经累积的数据 + if (jsonString.trim().startsWith('{')) { + console.log('检测到新的JSON对象开始,重置缓冲区'); + jsonBuffer = ''; } - jsonBuffer = ''; - - return jsonData.text; + + // 累积JSON字符串 + jsonBuffer += jsonString; + + // 检查是否是完整的JSON + if (isCompleteJson(jsonBuffer)) { + const jsonData = JSON.parse(jsonBuffer); // 将字符串解析为 JSON 对象 + console.log('成功解析完整JSON对象:', jsonData); + + // 记录最后一次消息接收时间,用于判断是否需要创建新消息 + const currentTime = new Date(); + if (!this.lastMessageTime) { + this.lastMessageTime = currentTime; + } + + // 计算时间差(毫秒) + const timeDiff = currentTime - this.lastMessageTime; + + // 更新最后一次消息时间 + this.lastMessageTime = currentTime; + + if (this.readableTextCallback && typeof this.readableTextCallback === 'function') { + this.readableTextCallback(jsonData.text); // 传递解码后的文本到回调 + } + + jsonBuffer = ''; + return jsonData.text; + } else { + console.log('JSON不完整,当前累积长度:', jsonBuffer.length); + } + } else { + console.log('接收的消息不是Uint8Array:', message); } - - } else { - console.log('Received message is not Uint8Array:', message); + } catch (error) { + console.error('处理stream-message时出错:', error); } - } catch (error) { - console.error('Error processing stream-message:', error); - } }); function isCompleteJson(jsonString) { + const openBraces = (jsonString.match(/{/g) || []).length; + const closeBraces = (jsonString.match(/}/g) || []).length; + if (openBraces === 0 || openBraces !== closeBraces) { + return false; + } + try { - JSON.parse(jsonString); // 解析测试是否为合法 JSON - return true; // 如果能被解析,说明是完整的 JSON + JSON.parse(jsonString); + return true; } catch (error) { - return false; // 捕获解析错误,说明 JSON 不完整 + return false; } } @@ -218,6 +245,7 @@ class AgoraService { this.inConversation = true; this.speechSegmentCallback = speechCallback; this.readableTextCallback = textCallback; + this.lastMessageTime = new Date(); // 重置最后一次消息时间 } /** diff --git a/src/stores/chat.js b/src/stores/chat.js index 716e886..1f0803a 100644 --- a/src/stores/chat.js +++ b/src/stores/chat.js @@ -104,12 +104,33 @@ export const useChatStore = defineStore('chat', { handleReadableText(text) { if (!text || !text.trim()) return; const isFromAI = text.includes('\n\n') || text.includes('\n'); - + const currentTime = new Date(); + const sender = isFromAI ? 'ai' : 'user'; + + // 获取最后一条消息 + const lastMessage = this.lastMessage; + + // 检查是否需要创建新消息或更新现有消息 + if (lastMessage && lastMessage.sender === sender) { + // 计算时间差(毫秒) + const timeDiff = currentTime - new Date(lastMessage.timestamp); + + // 如果时间差小于3秒,更新最后一条消息 + if (timeDiff < 3000) { + // 更新最后一条消息的内容 + lastMessage.content = text; + // 更新时间戳 + lastMessage.timestamp = currentTime.toISOString(); + return; + } + } + + // 如果时间差大于3秒或者是不同发送者,添加新消息 this.addMessage({ id: Date.now(), content: text, - sender: isFromAI ? 'ai' : 'user', - timestamp: new Date().toISOString(), + sender: sender, + timestamp: currentTime.toISOString(), }); }, @@ -176,15 +197,41 @@ export const useChatStore = defineStore('chat', { * @param {string} text - 语音段落文本 */ handleSpeechSegment(text) { - - console.log("我在这里!"); + console.log("处理语音段落:", text); if (!text || !text.trim()) return; // 更新当前转写 this.updateTranscript(text); - // 发送消息 - this.sendMessage(text); + // 使用与handleReadableText相同的逻辑处理消息 + const currentTime = new Date(); + const sender = 'user'; // 语音段落总是来自用户 + + // 获取最后一条消息 + const lastMessage = this.lastMessage; + + // 检查是否需要创建新消息或更新现有消息 + if (lastMessage && lastMessage.sender === sender) { + // 计算时间差(毫秒) + const timeDiff = currentTime - new Date(lastMessage.timestamp); + + // 如果时间差小于3秒,更新最后一条消息 + if (timeDiff < 3000) { + // 更新最后一条消息的内容 + lastMessage.content = text; + // 更新时间戳 + lastMessage.timestamp = currentTime.toISOString(); + return; + } + } + + // 如果时间差大于3秒或者是不同发送者,添加新消息 + this.addMessage({ + id: Date.now(), + content: text, + sender: sender, + timestamp: currentTime.toISOString(), + }); }, /** @@ -201,9 +248,9 @@ export const useChatStore = defineStore('chat', { stopListening() { if (!this.inConversation) return; - // 如果有转写内容,发送消息 + // 如果有转写内容,使用handleSpeechSegment处理消息 if (this.currentTranscript.trim()) { - this.sendMessage(this.currentTranscript.trim()); + this.handleSpeechSegment(this.currentTranscript.trim()); } this.endConversation();