| 
					
				 | 
			
			
				@@ -71,7 +71,7 @@ let lastStrIndex = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 将字符串根据标点符号断句分割,并添加到messageQueue中 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const splitMessage = async (str) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const punctuation = ["。","," ,"!", "?", ";", ":"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const punctuation = ["。", ",", "!", "?", ";", ":"]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   for (let i = lastStrIndex; i < str.length; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (punctuation.includes(str[i])) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -143,14 +143,14 @@ const playTTS = async (ttsMessage) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         `/openapi-prd/ai/ttt/synthesize?text=${ttsMessage}&sessionId=${sessionId.value}`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         { responseType: "arraybuffer" } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       // 即使请求失败也要保持队列连续性(新增部分) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       const audioItem = { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         orderId: currentOrderId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         audioData: res.data || null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         status: res.data ? 'valid' : 'invalid' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       audioQueue.push(audioItem); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       audioQueue.sort((a, b) => a.orderId - b.orderId);  // 保持队列有序 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -158,7 +158,7 @@ const playTTS = async (ttsMessage) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       console.error("调用 TTS API 时出错:", error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       // 请求失败时插入占位符保持顺序(关键修复) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      audioQueue.push({  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      audioQueue.push({ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         orderId: currentOrderId, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         audioData: null, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         status: 'invalid' 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -177,18 +177,18 @@ const playNextAudio = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   //   return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (audioQueue.length === 0 && playingQueue.length > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const maxPlayed = Math.max(...playingQueue); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (orderId > maxPlayed + 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    console.log("仍有未完成请求,暂不重置"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    isPlaying = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    // 新增:当队列完全播放完毕时重置所有状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    audioQueue = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    playingQueue = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    orderId = 0;  // 可选:如果需要重置顺序号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    console.log("所有音频播放完毕,已重置播放队列."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const maxPlayed = Math.max(...playingQueue); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (orderId > maxPlayed + 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log("仍有未完成请求,暂不重置"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      isPlaying = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // 新增:当队列完全播放完毕时重置所有状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      audioQueue = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      playingQueue = []; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      orderId = 0;  // 可选:如果需要重置顺序号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      console.log("所有音频播放完毕,已重置播放队列."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const nextAudio = getNextAudioToPlay(); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -225,22 +225,22 @@ const playNextAudio = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 获取下一个应该播放的音频(修改后) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const getNextAudioToPlay = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // 获取当前应该播放的最小序号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const expectedOrderId = playingQueue.length > 0  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ? Math.max(...playingQueue) + 1  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const expectedOrderId = playingQueue.length > 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ? Math.max(...playingQueue) + 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     : 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // 查找第一个匹配的有效音频(新增有效性检查) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const nextAudio = audioQueue.find(audio =>  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const nextAudio = audioQueue.find(audio => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     audio.orderId === expectedOrderId && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     audio.status === 'valid' 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   // 如果找不到有效音频但有序号匹配的无效项,跳过该序号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (!nextAudio) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    const invalidAudio = audioQueue.find(audio =>  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const invalidAudio = audioQueue.find(audio => 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       audio.orderId === expectedOrderId 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (invalidAudio) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       console.warn(`检测到无效音频,自动跳过序号:${expectedOrderId}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       playingQueue.push(expectedOrderId); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -250,108 +250,7 @@ const getNextAudioToPlay = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   return nextAudio || null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// 1. 发起 TTS 请求 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// const playTTS = async (ttsMessage) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   queue.add(async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     const currentOrderId = orderId++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       const res = await axios.get( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//         `/openapi-prd/ai/ttt/synthesize?text=${ttsMessage}&sessionId=${sessionId.value}`, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//         { responseType: "arraybuffer" } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       if (!res.data || res.data.byteLength === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//         console.error("音频数据无效,无法播放."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//         return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       // 按顺序存入音频队列 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       audioQueue.push({ orderId: currentOrderId, audioData: res.data }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       // 仅在没有播放时启动播放 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       if (!isPlaying) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//         await playNextAudio(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       console.error("调用 TTS API 时出错:", error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// 2. 播放下一个音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// const playNextAudio = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   // 如果播放队列为空,停止播放 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   if (audioQueue.length === 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     isPlaying = false;  // 播放完所有音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // audioQueue = []; // 确保列表为空 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     console.log("所有音频播放完毕."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   // 找到队列中最小序号的音频,确保顺序播放 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   const nextAudio = getNextAudioToPlay(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   console.log(nextAudio,"没有找到下一个应该播放的音频,队列尚未按顺序准备好."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   // 如果找不到下一个应该播放的音频,表示队列还没有按顺序准备好 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   if (!nextAudio) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     console.log("没有找到下一个应该播放的音频,队列尚未按顺序准备好."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     console.log("当前音频队列:", audioQueue);  // 打印当前音频队列 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     console.log("当前已播放的序列:", playingQueue);  // 打印已经播放的音频序列 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   // 打印正在播放的音频序号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   console.log(`正在播放音频,序号:${nextAudio.orderId}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     isPlaying = true;  // 标记当前正在播放 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     playingLock = true;  // 锁定播放,避免新的音频插入 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 播放当前音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     await playAudio(nextAudio.audioData); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 播放完成后,移除已播放的音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     playingQueue.push(nextAudio.orderId);  // 将已播放的序号添加到播放记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 输出音频播放完成的日志 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     console.log(`音频序号 ${nextAudio.orderId} 播放完成,等待播放下一个包...`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 解除锁定,等待下一个音频播放 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     playingLock = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 使用定时器周期性检查是否可以播放下一个音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     const checkNextAudioTimer = setInterval(async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       if (!playingLock) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//         await playNextAudio(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//         clearInterval(checkNextAudioTimer);  // 清除定时器 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     }, 300); // 每秒检查一次 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     console.error(`播放音频序号 ${nextAudio.orderId} 时出错:`, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 如果某个音频播放失败,跳过这个音频,继续播放下一个 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     audioQueue = audioQueue.filter(audio => audio.orderId !== nextAudio.orderId);  // 移除报错的音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     playingQueue.push(nextAudio.orderId);  // 将已播放的序号添加到播放记录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     playingLock = false;  // 解除锁定 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 继续播放下一个音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     await playNextAudio(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// 获取下一个应该播放的音频(保证顺序) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// const getNextAudioToPlay = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   // 检查音频队列中是否有下一个应该播放的音频 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   console.log("检查下一个播放的音频..."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   for (let i = 0; i < audioQueue.length; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     const audio = audioQueue[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     // 找到最小的序号,即请求的顺序号 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     if (audio.orderId === playingQueue.length) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       console.log(`找到了下一个应该播放的音频,序号:${audio.orderId}`); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//       return audio; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   console.log("没有找到下一个应该播放的音频,返回 null"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-//   return null;  // 如果没有找到匹配的音频,返回 null 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-// }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 播放音频的方法 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const playAudio = (audioData) => { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -362,37 +261,37 @@ const playAudio = (audioData) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     const audioBufferSourceNode = audioContext.createBufferSource(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     fetch(url) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        .then((response) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          if (!response.ok) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            console.error("音频文件请求失败: ", response.statusText); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reject(new Error("音频文件请求失败")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          return response.arrayBuffer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        .then((audioBuffer) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          audioBufferSourceNode.buffer = audioBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          audioBufferSourceNode.connect(audioContext.destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          audioBufferSourceNode.start(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          // 当音频播放完毕时,调用 resolve 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          audioBufferSourceNode.onended = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            URL.revokeObjectURL(url); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            resolve();  // 播放完成后,继续播放下一个 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          audioBufferSourceNode.onerror = (error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            console.error("音频播放错误:", error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            URL.revokeObjectURL(url); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            reject(error);  // 播放失败时,返回错误 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        .catch((error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          console.error("音频加载或解码时出错:", error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          reject(error);  // 如果解码或播放出错,reject 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .then((response) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!response.ok) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.error("音频文件请求失败: ", response.statusText); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          reject(new Error("音频文件请求失败")); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return response.arrayBuffer(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer)) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .then((audioBuffer) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        audioBufferSourceNode.buffer = audioBuffer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        audioBufferSourceNode.connect(audioContext.destination); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        audioBufferSourceNode.start(0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 当音频播放完毕时,调用 resolve 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        audioBufferSourceNode.onended = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          URL.revokeObjectURL(url); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          resolve();  // 播放完成后,继续播放下一个 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        audioBufferSourceNode.onerror = (error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          console.error("音频播放错误:", error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          URL.revokeObjectURL(url); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          reject(error);  // 播放失败时,返回错误 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      .catch((error) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        console.error("音频加载或解码时出错:", error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        reject(error);  // 如果解码或播放出错,reject 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // const playTTS1 = async (ttsMessage) => { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -480,17 +379,17 @@ const chatGpt = async (userMessage) => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             queue.add(async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               await splitMessage(responseText); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             queue2.add(async () => await updateChatList(responseText)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-             
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             //updateChatList(responseText); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         }, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     setTimeout(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-         handleTaskStatus() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     },3000) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      handleTaskStatus() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    }, 3000) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     //queue2.add(async () => await updateChatList("", false)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } catch (error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     //updateChatList("", false); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -574,7 +473,7 @@ const next = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const loadChatHistory = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const chatHistory = localStorage.getItem("chatHistory"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const chatStatus = localStorage.getItem("status"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (chatHistory) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -583,7 +482,7 @@ const loadChatHistory = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       chatList.value.push(item); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if(chatStatus){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (chatStatus) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     taskStatus.value = JSON.parse(chatStatus) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -591,8 +490,8 @@ const loadChatHistory = () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // 查询任务结束状态 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const handleTaskStatus = async () => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  const res =  await fetchTaskStatus(conversationId.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if(res.code == 200){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const res = await fetchTaskStatus(conversationId.value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (res.code == 200) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     taskStatus.value = res.body 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     localStorage.setItem("status", res.body); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -612,39 +511,43 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   <div class="main"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     <nav-bar-page title="考试" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     <div class="rate-circle"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <van-circle 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        :stroke-width="80" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        size="70px" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        v-model:current-rate="currentRate" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        :rate="rate" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        :text="text" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <van-circle :stroke-width="80" size="70px" v-model:current-rate="currentRate" :rate="rate" :text="text" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <div class="content"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <div class="tooltip"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <p>车辆信息:2024年10月起租,起租金额14万元,租期36月</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <p>还款情况:已还9期(截至2025年7月)</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <p>提前结清金额:121,021.62元</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <p>全额打款金额:137,362.73元 </p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <p>预期利益损失:6,535.05元</p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        <p>下一期租金:5,068.99元(本金3,421元,利息1,647.99元) </p> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     <BG /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     <div class="loading" v-show="loading"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       <van-loading color="#0094ff" size="26px" vertical>加载中...</van-loading> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     <ChatList :chatList="chatList" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    <BottomArea 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      @startRecord="handleStartRecord" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      @stopRecord="handleStopRecord" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      v-show="rate < 100 || taskStatus" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    <BottomArea @startRecord="handleStartRecord" @stopRecord="handleStopRecord" v-show="rate < 100 || taskStatus" /> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     <div v-show="rate >= 100 || taskStatus" class="next-btn"> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      <van-button style="width: 100%" @click="next" type="primary" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        >已完成对话,下一步</van-button 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      > 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      <van-button style="width: 100%" @click="next" type="primary">已完成对话,下一步</van-button> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   </div> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </template> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 <style> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 * { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  -webkit-touch-callout: none; /*系统默认菜单被禁用*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  -webkit-user-select: none; /*webkit浏览器*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  -khtml-user-select: none; /*早期浏览器*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  -moz-user-select: none; /*火狐*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  -ms-user-select: none; /*IE10*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  -webkit-touch-callout: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /*系统默认菜单被禁用*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  -webkit-user-select: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /*webkit浏览器*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  -khtml-user-select: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /*早期浏览器*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  -moz-user-select: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /*火狐*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  -ms-user-select: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /*IE10*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   user-select: none; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 </style> 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -655,12 +558,28 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   height: 100vh; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   overflow: hidden; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 .rate-circle { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   position: fixed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   right: 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   top: 70px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   z-index: 9999; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/* .content{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 0 40px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+.tooltip { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  position: fixed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  top: 152px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  z-index: 9999; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  font-size: 12px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  padding: 8px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  background-color: rgba(0, 0, 0, 0.5); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  color: #fff; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  margin: 0 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 .next-btn { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   position: fixed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   bottom: calc(20px + env(safe-area-inset-bottom)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -668,6 +587,7 @@ onMounted(() => { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   box-sizing: border-box; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   padding: 0 20px; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 .loading { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   position: fixed; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   top: 0; 
			 |