Browse Source

新增提示

dangdang 1 month ago
parent
commit
7742d111d0
3 changed files with 111 additions and 191 deletions
  1. 102 182
      src/views/ChatTts.vue
  2. 1 1
      src/views/DetailView.vue
  3. 8 8
      src/views/HomeView.vue

+ 102 - 182
src/views/ChatTts.vue

@@ -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;

+ 1 - 1
src/views/DetailView.vue

@@ -77,7 +77,7 @@ onMounted(() => {
         <img src="../assets/role3.jpg" alt="" />
       </div>
       <div class="produce">
-        <p>电话销售</p>
+        <p>结清挽留</p>
         <div class="p_content">
           <span class="bg">背景:</span>
           <span>

+ 8 - 8
src/views/HomeView.vue

@@ -54,23 +54,23 @@ onMounted(() => {
         <div class="card_content">
           <div class="card_item" @click="handleDetail()">
             <img src="../assets/role3.jpg" alt="" />
-            <p>电话销售</p>
-            <span>电话销售场景</span>
+            <p>结清挽留</p>
+            <span>“有闲钱”提前结清场景</span>
           </div>
           <div class="card_item">
             <img src="../assets/role2.jpg" alt="" />
-            <p>电话销售(未开启)</p>
-            <span>电话销售场景</span>
+            <p>结清挽留(未开启)</p>
+            <span>“有闲钱”提前结清场景</span>
           </div>
           <div class="card_item">
             <img src="../assets/role1.jpg" alt="" />
-            <p>电话销售(未开启)</p>
-            <span>电话销售场景</span>
+            <p>结清挽留(未开启)</p>
+            <span>“有闲钱”提前结清场景</span>
           </div>
           <div class="card_item">
             <img src="../assets/role.jpg" alt="" />
-            <p>电话销售(未开启)</p>
-            <span>电话销售场景</span>
+            <p>结清挽留(未开启)</p>
+            <span>“有闲钱”提前结清场景</span>
           </div>
         </div>
       </div>