From 3df916077185e525f1b8b68694b6f7e0a29f4cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=8B=E6=9D=B0?= Date: Fri, 4 Jul 2025 13:14:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=B7=A5=E4=BD=9C=E6=B5=81be?= =?UTF-8?q?arer=EF=BC=9B=E8=A7=A3=E5=86=B3=E5=A4=BA=E5=AE=9D=E5=A5=87?= =?UTF-8?q?=E5=85=B5=E5=A4=A7=E6=A8=A1=E5=9E=8B=E9=9F=B3=E9=A2=91=E6=92=AD?= =?UTF-8?q?=E6=94=BE=E8=B7=B3=E8=BF=87=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/AiEmotionApi.js | 4 +- src/views/AIchat.vue | 225 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 193 insertions(+), 36 deletions(-) diff --git a/src/api/AiEmotionApi.js b/src/api/AiEmotionApi.js index d49e302..31bcc38 100644 --- a/src/api/AiEmotionApi.js +++ b/src/api/AiEmotionApi.js @@ -15,7 +15,7 @@ export const getReplyAPI = function (params) { headers: { "Content-Type": "application/json", Authorization: - "Bearer pat_lK1fvhLn9LnWCRETP7yFeR6xQ0niwQdcHJ5ZqpnUk8BdiUWCraPLSzWhiQNp2zOl", + "Bearer pat_cOhJRgrEpjXwJJLW1N3YNjCxy19HYTpMFY6XlNCLi4ogm5tdfV266gWIB7MeaRIU", }, }); }; @@ -31,7 +31,7 @@ export const getConclusionAPI = function (params) { headers: { "Content-Type": "application/json", Authorization: - "Bearer pat_lK1fvhLn9LnWCRETP7yFeR6xQ0niwQdcHJ5ZqpnUk8BdiUWCraPLSzWhiQNp2zOl", + "Bearer pat_cOhJRgrEpjXwJJLW1N3YNjCxy19HYTpMFY6XlNCLi4ogm5tdfV266gWIB7MeaRIU", }, }); }; diff --git a/src/views/AIchat.vue b/src/views/AIchat.vue index 9c5fa74..aca0296 100644 --- a/src/views/AIchat.vue +++ b/src/views/AIchat.vue @@ -173,6 +173,28 @@ const playAudioSequence = (audioUrls) => { "长度:", currentUrl?.length ); + + // 增强URL验证 + if (!currentUrl || typeof currentUrl !== 'string' || currentUrl.trim() === '') { + console.error(`音频 ${currentIndex + 1} URL无效,跳过该音频`); + currentIndex++; + setTimeout(() => { + playNext(); + }, 100); + return; + } + + // 检查URL格式 + try { + new URL(currentUrl); + } catch (e) { + console.error(`音频 ${currentIndex + 1} URL格式错误:`, currentUrl); + currentIndex++; + setTimeout(() => { + playNext(); + }, 100); + return; + } // 设置当前音频URL audioStore.setCurrentAudioUrl(currentUrl); @@ -191,6 +213,11 @@ const playAudioSequence = (audioUrls) => { audioStore.isPlaying = true; audioStore.isPaused = false; console.log(`开始播放音频 ${currentIndex + 1}`); + console.log('音频播放状态:', { + duration: sound.duration(), + state: sound.state(), + playing: sound.playing() + }); }, onpause: () => { audioStore.isPlaying = false; @@ -204,6 +231,13 @@ const playAudioSequence = (audioUrls) => { audioStore.playbackPosition = 0; console.log(`音频 ${currentIndex + 1} 播放完成`); currentIndex++; + // 如果是最后一个音频播放完成,立即清除实例 + if (currentIndex >= audioSequence.length) { + console.log('最后一个音频播放完成,清除音频实例'); + audioStore.soundInstance = null; + audioStore.nowSound = null; + currentIndex = 0; // 立即重置索引 + } // 播放下一个音频 setTimeout(() => { playNext(); @@ -217,16 +251,50 @@ const playAudioSequence = (audioUrls) => { }, onloaderror: (id, err) => { console.error(`音频 ${currentIndex + 1} 加载失败:`, err); - currentIndex++; - // 跳过失败的音频,播放下一个 - setTimeout(() => { - playNext(); - }, 100); + console.error('失败的音频URL:', currentUrl); + console.error('错误详情:', { id, err }); + + // 增加重试机制 + if (!sound.retryCount) { + sound.retryCount = 0; + } + + if (sound.retryCount < 2) { + sound.retryCount++; + console.log(`音频 ${currentIndex + 1} 第${sound.retryCount}次重试加载`); + setTimeout(() => { + sound.load(); + }, 1000 * sound.retryCount); // 递增延时重试 + } else { + console.warn(`音频 ${currentIndex + 1} 重试失败,跳过该音频`); + currentIndex++; + // 跳过失败的音频,播放下一个 + setTimeout(() => { + playNext(); + }, 100); + } }, }); audioStore.nowSound = sound; audioStore.setAudioInstance(sound); + + // 添加播放超时检测 + const playTimeout = setTimeout(() => { + if (!audioStore.isPlaying && sound.state() === 'loading') { + console.warn(`音频 ${currentIndex + 1} 播放超时,可能网络问题`); + sound.stop(); + currentIndex++; + playNext(); + } + }, 10000); // 10秒超时 + + // 播放成功后清除超时 + sound.once('play', () => { + clearTimeout(playTimeout); + }); + + console.log(`尝试播放音频 ${currentIndex + 1},URL: ${currentUrl}`); sound.play(); }; @@ -299,7 +367,7 @@ const typeWriter = (text, callback) => { // 自动滚动到底部 nextTick(() => { const container = document.querySelector(".message-area"); - if (container) container.scrollTop = container.scrollHeight; + if (container) container.scrollTop = container.scrollHeight; }); } else { clearInterval(typingInterval); @@ -647,17 +715,24 @@ watch( const isPlayingAudio = ref(false); // 播放音频队列 + // 防止重复调用的标志 + let isCallingPlayNext = false; + const playNextAudio = () => { - if (audioQueue.value.length === 0 || isPlayingAudio.value) { + if (audioQueue.value.length === 0 || isPlayingAudio.value || isCallingPlayNext) { + console.log('播放条件不满足 - 队列长度:', audioQueue.value.length, '正在播放:', isPlayingAudio.value, '正在调用:', isCallingPlayNext); return; } + isCallingPlayNext = true; isPlayingAudio.value = true; const audioInfo = audioQueue.value.shift(); - console.log(`开始播放${audioInfo.name}音频`); + console.log(`开始播放${audioInfo.name}音频,剩余队列:`, audioQueue.value.length); - if (audioStore.nowSound) { + // 只有在确实需要停止时才停止之前的音频 + if (audioStore.nowSound && (audioStore.nowSound.playing() || audioStore.nowSound.state() === 'loading')) { + console.log('停止之前的音频实例'); audioStore.nowSound.stop(); } @@ -669,7 +744,9 @@ watch( onplay: () => { audioStore.isPlaying = true; audioStore.isPaused = false; - console.log(`${audioInfo.name}音频开始播放`); + isCallingPlayNext = false; // 重置调用标志 + console.log(`${audioInfo.name}音频开始播放,时长:`, audio.duration()); + console.log('音频播放状态确认 - isPlayingAudio:', isPlayingAudio.value, 'audioStore.isPlaying:', audioStore.isPlaying); }, onpause: () => { audioStore.isPlaying = false; @@ -683,26 +760,36 @@ watch( console.log(`${audioInfo.name}音频继续播放`); }, onend: () => { + console.log(`${audioInfo.name}音频播放完成,准备播放下一个`); + console.log('播放完成时的状态 - 队列长度:', audioQueue.value.length, 'isPlayingAudio:', isPlayingAudio.value); audioStore.isPlaying = false; audioStore.isPaused = false; audioStore.playbackPosition = 0; isPlayingAudio.value = false; - console.log(`${audioInfo.name}音频播放完成`); - // 播放下一个音频 - setTimeout(() => { - playNextAudio(); - }, 100); + + // 确保只有在音频真正播放完成时才播放下一个 + if (audioQueue.value.length > 0) { + console.log('队列中还有音频,500ms后播放下一个,当前队列:', audioQueue.value.map(item => item.name)); + setTimeout(() => { + isCallingPlayNext = false; // 在调用前重置标志 + playNextAudio(); + }, 500); + } else { + console.log('所有音频播放完成'); + isCallingPlayNext = false; // 重置调用标志 + } }, onstop: () => { + console.log(`${audioInfo.name}音频被停止`); audioStore.isPlaying = false; audioStore.isPaused = false; audioStore.playbackPosition = 0; - isPlayingAudio.value = false; - console.log(`${audioInfo.name}音频已停止`); + // 注意:不要在onstop中设置isPlayingAudio.value = false,因为这可能是正常的音频切换 }, onloaderror: (id, err) => { console.error(`${audioInfo.name}音频播放失败:`, err); isPlayingAudio.value = false; + isCallingPlayNext = false; // 重置调用标志 // 播放下一个音频 setTimeout(() => { playNextAudio(); @@ -714,19 +801,61 @@ watch( audioStore.setCurrentAudioUrl(audioInfo.url); audioStore.nowSound = audio; audioStore.setAudioInstance(audio); + + console.log(`尝试播放${audioInfo.name}音频`); audio.play(); }; - // 添加音频到播放队列 + // 音频队列顺序管理 + const audioQueueOrder = { + 'API1-第一个': 1, + 'API2-第二个': 2, + 'API3-第三个': 3, + 'API4-第四个': 4 + }; + + // 添加音频到播放队列(确保顺序) const addToAudioQueue = (url, name) => { + console.log(`=== 添加音频到队列 ===`); + console.log('URL:', url); + console.log('Name:', name); + console.log('音频启用状态:', audioStore.isVoiceEnabled); + if (url && audioStore.isVoiceEnabled) { - audioQueue.value.push({ url, name }); - console.log(`音频${name}已添加到播放队列`); - // 如果当前没有播放音频,立即开始播放 - if (!isPlayingAudio.value) { + const audioItem = { url, name, order: audioQueueOrder[name] || 999 }; + audioQueue.value.push(audioItem); + + // 按顺序排序队列 + audioQueue.value.sort((a, b) => a.order - b.order); + + console.log(`音频${name}已添加到播放队列,顺序:${audioItem.order}`); + console.log('当前队列顺序:', audioQueue.value.map(item => `${item.name}(${item.order})`)); + console.log('当前播放状态详情:'); + console.log(' - isPlayingAudio:', isPlayingAudio.value); + console.log(' - audioStore.isPlaying:', audioStore.isPlaying); + console.log(' - audioStore.nowSound:', audioStore.nowSound); + console.log(' - isCallingPlayNext:', isCallingPlayNext); + console.log(' - 队列长度:', audioQueue.value.length); + + // 只有在确实没有音频在播放且这是第一个音频时才开始播放 + if (!isPlayingAudio.value && !audioStore.isPlaying && audioQueue.value.length === 1) { + console.log('✅ 条件满足:没有音频在播放且这是第一个音频,立即开始播放'); playNextAudio(); + } else { + console.log('⏳ 等待条件:', { + isPlayingAudio: isPlayingAudio.value, + audioStoreIsPlaying: audioStore.isPlaying, + queueLength: audioQueue.value.length, + reason: audioQueue.value.length > 1 ? '队列中已有其他音频' : '有音频正在播放' + }); } + } else { + console.log('❌ 跳过添加音频:', { + hasUrl: !!url, + voiceEnabled: audioStore.isVoiceEnabled + }); } + console.log(`=== 添加音频完成 ===`); }; // 重写audioStore的togglePlayPause方法以支持队列播放控制 @@ -735,6 +864,7 @@ watch( console.log('主页音频控制按钮被点击'); console.log('当前音频状态 - isPlaying:', audioStore.isPlaying, 'isPaused:', audioStore.isPaused); console.log('当前音频实例:', audioStore.soundInstance); + console.log('队列播放状态 - isPlayingAudio:', isPlayingAudio.value, '队列长度:', audioQueue.value.length); if (audioStore.soundInstance) { if (audioStore.isPlaying) { @@ -752,10 +882,29 @@ watch( audioStore.soundInstance.play(); } } else { - console.log('没有音频实例,尝试播放队列中的音频'); - // 没有音频实例时,尝试播放队列中的音频 - if (!isPlayingAudio.value && audioQueue.value.length > 0) { + console.log('没有音频实例,检查是否需要重新播放队列'); + // 没有音频实例时,检查是否所有音频都播放完成 + if (!isPlayingAudio.value && audioQueue.value.length === 0) { + console.log('所有音频播放完成,重新构建队列从第一个开始播放'); + // 重新构建音频队列,按顺序添加所有音频 + if (audioPreloadStatus.one.url) { + addToAudioQueue(audioPreloadStatus.one.url, "API1-第一个"); + } + if (audioPreloadStatus.two.url) { + addToAudioQueue(audioPreloadStatus.two.url, "API2-第二个"); + } + if (audioPreloadStatus.three.url) { + addToAudioQueue(audioPreloadStatus.three.url, "API3-第三个"); + } + if (audioPreloadStatus.four.url) { + addToAudioQueue(audioPreloadStatus.four.url, "API4-第四个"); + } + console.log('队列重建完成,开始从第一个音频播放'); + } else if (!isPlayingAudio.value && audioQueue.value.length > 0) { + console.log('队列中还有音频,继续播放'); playNextAudio(); + } else { + console.log('无法播放 - isPlayingAudio:', isPlayingAudio.value, '队列长度:', audioQueue.value.length); } } }; @@ -767,6 +916,10 @@ watch( return Promise.resolve(); } + // 立即设置URL,确保即使预加载失败也能使用 + audioPreloadStatus[apiKey].url = url; + console.log(`设置音频${apiKey}的URL:`, url); + return new Promise((resolve) => { const audio = new Howl({ src: [url], @@ -777,12 +930,12 @@ watch( onload: () => { console.log(`音频${apiKey}预加载完成:`, url); audioPreloadStatus[apiKey].loaded = true; - audioPreloadStatus[apiKey].url = url; resolve(); }, onloaderror: (id, err) => { console.error(`音频${apiKey}预加载失败:`, err); audioPreloadStatus[apiKey].loaded = true; // 标记为已处理,避免阻塞 + // URL已经在上面设置了,即使预加载失败也保留URL resolve(); } }); @@ -802,9 +955,10 @@ watch( if (apiStatus.one.result) { console.log("执行OneAPI代码(文本和音频同步开始):", apiStatus.one.result); - // 将第一个音频添加到播放队列 + // 将第一个音频添加到播放队列(确保顺序:API1) if (audioPreloadStatus.one.url) { - addToAudioQueue(audioPreloadStatus.one.url, "第一个"); + addToAudioQueue(audioPreloadStatus.one.url, "API1-第一个"); + console.log("音频队列:添加API1音频,当前队列长度:", audioQueue.value.length); } // 在这里添加OneAPI成功后需要执行的代码 @@ -1047,9 +1201,10 @@ watch( if (apiStatus.two.result) { console.log("执行TwoAPI代码:", apiStatus.two.result); - // 将第二个音频添加到播放队列 + // 将第二个音频添加到播放队列(确保顺序:API2) if (audioPreloadStatus.two.url) { - addToAudioQueue(audioPreloadStatus.two.url, "第二个"); + addToAudioQueue(audioPreloadStatus.two.url, "API2-第二个"); + console.log("音频队列:添加API2音频,当前队列长度:", audioQueue.value.length); } // 在这里添加TwoAPI成功后需要执行的代码 @@ -1125,9 +1280,10 @@ watch( if (apiStatus.three.result) { console.log("执行ThreeAPI代码:", apiStatus.three.result); - // 将第三个音频添加到播放队列 + // 将第三个音频添加到播放队列(确保顺序:API3) if (audioPreloadStatus.three.url) { - addToAudioQueue(audioPreloadStatus.three.url, "第三个"); + addToAudioQueue(audioPreloadStatus.three.url, "API3-第三个"); + console.log("音频队列:添加API3音频,当前队列长度:", audioQueue.value.length); } // 在这里添加ThreeAPI成功后需要执行的代码 @@ -1289,9 +1445,10 @@ watch( if (apiStatus.four.result) { console.log("执行FourAPI代码:", apiStatus.four.result); - // 将第四个音频添加到播放队列 + // 将第四个音频添加到播放队列(确保顺序:API4) if (audioPreloadStatus.four.url) { - addToAudioQueue(audioPreloadStatus.four.url, "第四个"); + addToAudioQueue(audioPreloadStatus.four.url, "API4-第四个"); + console.log("音频队列:添加API4音频,当前队列长度:", audioQueue.value.length); } // 在这里添加FourAPI成功后需要执行的代码