diff --git a/src/views/AIchat.vue b/src/views/AIchat.vue index aa03422..8fda2cc 100644 --- a/src/views/AIchat.vue +++ b/src/views/AIchat.vue @@ -612,28 +612,142 @@ watch( four: { completed: false, result: null, error: null }, }; + // 音频预加载状态跟踪 + const audioPreloadStatus = { + one: { loaded: false, url: null }, + two: { loaded: false, url: null }, + three: { loaded: false, url: null }, + four: { loaded: false, url: null } + }; + + // 音频播放队列管理 + const audioQueue = ref([]); + const isPlayingAudio = ref(false); + + // 播放音频队列 + const playNextAudio = () => { + if (audioQueue.value.length === 0 || isPlayingAudio.value) { + return; + } + + isPlayingAudio.value = true; + const audioInfo = audioQueue.value.shift(); + + console.log(`开始播放${audioInfo.name}音频`); + + if (audioStore.nowSound) { + audioStore.nowSound.stop(); + } + + const audio = new Howl({ + src: [audioInfo.url], + html5: true, + format: ["mp3", "acc"], + rate: 1.2, + onplay: () => { + audioStore.isPlaying = true; + audioStore.isPaused = false; + console.log(`${audioInfo.name}音频开始播放`); + }, + onend: () => { + audioStore.isPlaying = false; + audioStore.isPaused = false; + isPlayingAudio.value = false; + console.log(`${audioInfo.name}音频播放完成`); + // 播放下一个音频 + setTimeout(() => { + playNextAudio(); + }, 100); + }, + onloaderror: (id, err) => { + console.error(`${audioInfo.name}音频播放失败:`, err); + isPlayingAudio.value = false; + // 播放下一个音频 + setTimeout(() => { + playNextAudio(); + }, 100); + } + }); + + audioStore.nowSound = audio; + audioStore.setAudioInstance(audio); + audio.play(); + }; + + // 添加音频到播放队列 + const addToAudioQueue = (url, name) => { + if (url && audioStore.isVoiceEnabled) { + audioQueue.value.push({ url, name }); + console.log(`音频${name}已添加到播放队列`); + // 如果当前没有播放音频,立即开始播放 + if (!isPlayingAudio.value) { + playNextAudio(); + } + } + }; + + // 预加载音频函数 + const preloadAudio = (url, apiKey) => { + if (!url || !audioStore.isVoiceEnabled) { + audioPreloadStatus[apiKey].loaded = true; + return Promise.resolve(); + } + + return new Promise((resolve) => { + const audio = new Howl({ + src: [url], + html5: true, + format: ["mp3", "acc"], + rate: 1.2, + preload: true, + 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; // 标记为已处理,避免阻塞 + resolve(); + } + }); + }); + }; + + // 检查第一个接口是否可以开始输出(文本和音频都准备好) + const canStartFirstOutput = () => { + return apiStatus.one.completed && audioPreloadStatus.one.loaded; + }; + // 检查并按顺序执行代码的函数 const checkAndExecuteInOrder = () => { - // 检查OneAPI - if (apiStatus.one.completed && !apiStatus.one.executed) { - apiStatus.one.executed = true; - if (apiStatus.one.result) { - console.log("执行OneAPI代码:", apiStatus.one.result); - // 在这里添加OneAPI成功后需要执行的代码 - // 删除正在为您生成信息 - chatStore.messages.pop(); - // 添加报告头和时间 - addTypingTask( - { - sender: "ai", - class: "title1", - type: "title1", - content: codeData.value.name + "全景作战报告", - date: moment().format("MM/DD/YYYY"), - }, - "", - 50 - ); + // 检查OneAPI - 只有当文本和音频都准备好时才开始输出 + if (canStartFirstOutput() && !apiStatus.one.executed) { + apiStatus.one.executed = true; + if (apiStatus.one.result) { + console.log("执行OneAPI代码(文本和音频同步开始):", apiStatus.one.result); + + // 将第一个音频添加到播放队列 + if (audioPreloadStatus.one.url) { + addToAudioQueue(audioPreloadStatus.one.url, "第一个"); + } + + // 在这里添加OneAPI成功后需要执行的代码 + // 删除正在为您生成信息 + chatStore.messages.pop(); + // 添加报告头和时间 + addTypingTask( + { + sender: "ai", + class: "title1", + type: "title1", + content: codeData.value.name + "全景作战报告", + date: moment().format("MM/DD/YYYY"), + }, + "", + 50 + ); // chatStore.messages.push({ // sender: "ai", // class: "title1", @@ -858,6 +972,12 @@ watch( apiStatus.two.executed = true; if (apiStatus.two.result) { console.log("执行TwoAPI代码:", apiStatus.two.result); + + // 将第二个音频添加到播放队列 + if (audioPreloadStatus.two.url) { + addToAudioQueue(audioPreloadStatus.two.url, "第二个"); + } + // 在这里添加TwoAPI成功后需要执行的代码 // 添加标题2 addTypingTask( @@ -930,6 +1050,12 @@ watch( apiStatus.three.executed = true; if (apiStatus.three.result) { console.log("执行ThreeAPI代码:", apiStatus.three.result); + + // 将第三个音频添加到播放队列 + if (audioPreloadStatus.three.url) { + addToAudioQueue(audioPreloadStatus.three.url, "第三个"); + } + // 在这里添加ThreeAPI成功后需要执行的代码 // 添加标题3-2 addTypingTask( @@ -1073,6 +1199,12 @@ watch( apiStatus.four.executed = true; if (apiStatus.four.result) { console.log("执行FourAPI代码:", apiStatus.four.result); + + // 将第四个音频添加到播放队列 + if (audioPreloadStatus.four.url) { + addToAudioQueue(audioPreloadStatus.four.url, "第四个"); + } + // 在这里添加FourAPI成功后需要执行的代码 // 添加标题3-4 addTypingTask( @@ -1177,47 +1309,34 @@ watch( apiStatus.four.completed && apiStatus.four.executed ) { - console.log("所有API已完成,开始收集音频URL"); - // 收集所有音频URL + console.log("所有API已完成,开始收集预加载的音频URL"); + // 收集所有预加载的音频URL const audioUrls = []; - console.log("API返回结果检查:"); - console.log("result21:", result21); - console.log("result22:", result22); - console.log("result23:", result23); - console.log("result24:", result24); + console.log("预加载音频状态检查:"); + console.log("audioPreloadStatus:", audioPreloadStatus); - if (result21?.data?.url) { - console.log("添加result21音频URL:", result21.data.url); - audioUrls.push(result21.data.url.trim()); + if (audioPreloadStatus.one.url) { + console.log("添加预加载音频URL one:", audioPreloadStatus.one.url); + audioUrls.push(audioPreloadStatus.one.url); } - if (result22?.data?.url) { - console.log("添加result22音频URL:", result22.data.url); - audioUrls.push(result22.data.url.trim()); + if (audioPreloadStatus.two.url) { + console.log("添加预加载音频URL two:", audioPreloadStatus.two.url); + audioUrls.push(audioPreloadStatus.two.url); } - if (result23?.data?.url) { - console.log("添加result23音频URL:", result23.data.url); - audioUrls.push(result23.data.url.trim()); + if (audioPreloadStatus.three.url) { + console.log("添加预加载音频URL three:", audioPreloadStatus.three.url); + audioUrls.push(audioPreloadStatus.three.url); } - if (result24?.data?.url) { - console.log("添加result24音频URL:", result24.data.url); - audioUrls.push(result24.data.url.trim()); + if (audioPreloadStatus.four.url) { + console.log("添加预加载音频URL four:", audioPreloadStatus.four.url); + audioUrls.push(audioPreloadStatus.four.url); } - console.log("收集到的音频URLs:", audioUrls); + console.log("收集到的预加载音频URLs:", audioUrls); console.log("语音是否启用:", audioStore.isVoiceEnabled); - // 开始轮流播放音频 - if (audioUrls.length > 0 && audioStore.isVoiceEnabled) { - console.log("开始播放音频序列"); - playAudioSequence(audioUrls); - } else { - console.log( - "跳过音频播放 - audioUrls长度:", - audioUrls.length, - "语音启用状态:", - audioStore.isVoiceEnabled - ); - } + // 音频播放逻辑已移至各个接口的执行代码中 + console.log("所有接口执行完成,音频已在各接口中单独播放"); } }; @@ -1229,12 +1348,20 @@ watch( apiStatus.one.completed = true; apiStatus.one.result = result21; + // 预加载第一个接口的音频 + if (result21?.data?.url) { + await preloadAudio(result21.data.url.trim(), 'one'); + } else { + audioPreloadStatus.one.loaded = true; + } + // 检查是否可以执行 checkAndExecuteInOrder(); } catch (error) { console.error("OneAPI失败:", error); apiStatus.one.completed = true; apiStatus.one.error = error; + audioPreloadStatus.one.loaded = true; // 失败时也标记为已处理 // 即使失败也要检查后续执行 checkAndExecuteInOrder(); } @@ -1248,12 +1375,20 @@ watch( apiStatus.two.completed = true; apiStatus.two.result = result22; + // 预加载第二个接口的音频 + if (result22?.data?.url) { + await preloadAudio(result22.data.url.trim(), 'two'); + } else { + audioPreloadStatus.two.loaded = true; + } + // 检查是否可以执行 checkAndExecuteInOrder(); } catch (error) { console.error("TwoAPI失败:", error); apiStatus.two.completed = true; apiStatus.two.error = error; + audioPreloadStatus.two.loaded = true; checkAndExecuteInOrder(); } }; @@ -1266,12 +1401,20 @@ watch( apiStatus.three.completed = true; apiStatus.three.result = result23; + // 预加载第三个接口的音频 + if (result23?.data?.url) { + await preloadAudio(result23.data.url.trim(), 'three'); + } else { + audioPreloadStatus.three.loaded = true; + } + // 检查是否可以执行 checkAndExecuteInOrder(); } catch (error) { console.error("ThreeAPI失败:", error); apiStatus.three.completed = true; apiStatus.three.error = error; + audioPreloadStatus.three.loaded = true; checkAndExecuteInOrder(); } }; @@ -1284,12 +1427,20 @@ watch( apiStatus.four.completed = true; apiStatus.four.result = result24; + // 预加载第四个接口的音频 + if (result24?.data?.url) { + await preloadAudio(result24.data.url.trim(), 'four'); + } else { + audioPreloadStatus.four.loaded = true; + } + // 检查是否可以执行 checkAndExecuteInOrder(); } catch (error) { console.error("FourAPI失败:", error); apiStatus.four.completed = true; apiStatus.four.error = error; + audioPreloadStatus.four.loaded = true; checkAndExecuteInOrder(); } };