zlwu 10 月之前
父節點
當前提交
9be735291b
共有 2 個文件被更改,包括 53 次插入 和 12 次删除
  1. 36 11
      frontend/src/pages/ChatBotPage.tsx
  2. 17 1
      frontend/src/utils/websocket.ts

+ 36 - 11
frontend/src/pages/ChatBotPage.tsx

@@ -2027,16 +2027,28 @@ export const ChatBotPage = () => {
       return;
       return;
     }
     }
     
     
-    if (!isConnected) {
-      antMessage.warning('语音服务正在重连,请稍后再试');
+    // 🔥 改进:允许在连接建立过程中开始录音
+    // 1. 如果 WebSocket 不存在,说明还未初始化,提示等待
+    // 2. 如果 WebSocket 存在,检查是否正在连接中或已就绪
+    // 3. 如果正在连接中(CONNECTING)或已就绪(OPEN),允许开始录音,消息会被缓冲
+    // 4. 这样用户无感知,业务也能正常运行
+    if (!wsRef.current) {
+      antMessage.warning('语音服务初始化中,请稍后重试');
       return;
       return;
     }
     }
 
 
-    if (!wsRef.current?.isReady()) {
-      antMessage.warning('语音服务正在恢复,请稍后重试');
+    // 检查 WebSocket 状态:如果正在连接中或已就绪,允许开始录音
+    const isConnecting = wsRef.current.isConnecting();
+    const isReady = wsRef.current.isReady();
+    
+    // 如果既不在连接中,也不已就绪,且 isConnected 为 false,说明连接失败
+    if (!isConnecting && !isReady && !isConnected) {
+      antMessage.warning('语音服务正在重连,请稍后再试');
       return;
       return;
     }
     }
     
     
+    // 如果正在连接中或已就绪,允许开始录音(消息会被缓冲)
+    
     // 保存旧请求ID(用于取消和过滤旧消息)
     // 保存旧请求ID(用于取消和过滤旧消息)
     const oldRequestId = currentRequestId;
     const oldRequestId = currentRequestId;
     const wasPlaying = currentState === 'playing' || currentState === 'sending';
     const wasPlaying = currentState === 'playing' || currentState === 'sending';
@@ -2109,13 +2121,14 @@ export const ChatBotPage = () => {
     setRecognizedText('');
     setRecognizedText('');
     
     
     // 准备移动端音频(在设置状态之后,避免阻塞状态更新)
     // 准备移动端音频(在设置状态之后,避免阻塞状态更新)
+    // 🔥 改进:静默准备音频环境,不显示提示,用户无感知
     if (isMobileDevice() && !mobileAudioPreparedRef.current) {
     if (isMobileDevice() && !mobileAudioPreparedRef.current) {
       // 异步准备,不阻塞录音开始
       // 异步准备,不阻塞录音开始
       prepareMobileAudio()
       prepareMobileAudio()
         .then(() => {
         .then(() => {
           requestVolumeControl();
           requestVolumeControl();
           mobileAudioPreparedRef.current = true;
           mobileAudioPreparedRef.current = true;
-          antMessage.info('请确保设备音量已调高');
+          // 移除提示,让用户无感知,业务功能正常(prepareMobileAudio 和 requestVolumeControl 仍会执行)
         })
         })
         .catch(() => {
         .catch(() => {
           // 准备移动端音频失败,静默处理
           // 准备移动端音频失败,静默处理
@@ -2175,8 +2188,13 @@ export const ChatBotPage = () => {
 
 
     stopRecordingTimer();
     stopRecordingTimer();
     
     
-    if (!isConnected) {
-      antMessage.error('语音服务未连接,请重新录音发送');
+    // 🔥 改进:允许在连接建立过程中发送录音
+    // 1. 如果 WebSocket 不存在,说明还未初始化,提示错误
+    // 2. 如果 WebSocket 存在,检查是否正在连接中或已就绪
+    // 3. 如果正在连接中(CONNECTING)或已就绪(OPEN),允许发送,消息会被缓冲
+    // 4. 这样用户无感知,业务也能正常运行
+    if (!wsRef.current) {
+      antMessage.error('语音服务初始化中,请重新录音发送');
       recorderRef.current?.stop();
       recorderRef.current?.stop();
       resetFrequencyVisualization();
       resetFrequencyVisualization();
       // 清理情绪 GIF 切换定时器
       // 清理情绪 GIF 切换定时器
@@ -2186,13 +2204,18 @@ export const ChatBotPage = () => {
       }
       }
       // 恢复默认头像 GIF
       // 恢复默认头像 GIF
       showDefaultGif();
       showDefaultGif();
-      performanceLogger.clearRequest(currentRequestId, 'websocket_disconnected_before_send');
+      performanceLogger.clearRequest(currentRequestId, 'websocket_unready_before_send');
       reset();
       reset();
       return;
       return;
     }
     }
 
 
-    if (!wsRef.current?.isReady()) {
-      antMessage.error('语音服务尚未准备完成,请重新录音发送');
+    // 检查 WebSocket 状态:如果正在连接中或已就绪,允许发送
+    const isConnecting = wsRef.current.isConnecting();
+    const isReady = wsRef.current.isReady();
+    
+    // 如果既不在连接中,也不已就绪,且 isConnected 为 false,说明连接失败
+    if (!isConnecting && !isReady && !isConnected) {
+      antMessage.error('语音服务未连接,请重新录音发送');
       recorderRef.current?.stop();
       recorderRef.current?.stop();
       resetFrequencyVisualization();
       resetFrequencyVisualization();
       // 清理情绪 GIF 切换定时器
       // 清理情绪 GIF 切换定时器
@@ -2202,10 +2225,12 @@ export const ChatBotPage = () => {
       }
       }
       // 恢复默认头像 GIF
       // 恢复默认头像 GIF
       showDefaultGif();
       showDefaultGif();
-      performanceLogger.clearRequest(currentRequestId, 'websocket_unready_before_send');
+      performanceLogger.clearRequest(currentRequestId, 'websocket_disconnected_before_send');
       reset();
       reset();
       return;
       return;
     }
     }
+    
+    // 如果正在连接中或已就绪,允许发送(消息会被缓冲)
 
 
     timingRef.current.recordEnd = Date.now();
     timingRef.current.recordEnd = Date.now();
     sendTimeRef.current = Date.now();
     sendTimeRef.current = Date.now();

+ 17 - 1
frontend/src/utils/websocket.ts

@@ -80,8 +80,24 @@ export class WebSocketManager {
     return !!this.ws && this.ws.readyState === WebSocket.OPEN;
     return !!this.ws && this.ws.readyState === WebSocket.OPEN;
   }
   }
 
 
+  /**
+   * 检查 WebSocket 是否就绪
+   * 如果正在连接中(CONNECTING),也认为"准备中",因为消息会被缓冲
+   */
   isReady(): boolean {
   isReady(): boolean {
-    return this.isOpen();
+    if (!this.ws) {
+      return false;
+    }
+    // OPEN: 已连接,可以发送
+    // CONNECTING: 正在连接中,消息会被缓冲,也算"准备中"
+    return this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING;
+  }
+
+  /**
+   * 检查 WebSocket 是否正在连接中
+   */
+  isConnecting(): boolean {
+    return !!this.ws && this.ws.readyState === WebSocket.CONNECTING;
   }
   }
 
 
   private doSend(message: Partial<Message>): void {
   private doSend(message: Partial<Message>): void {