|
|
@@ -19,7 +19,7 @@
|
|
|
<el-icon class="arrow-icon"><CaretLeft /></el-icon>
|
|
|
</div>
|
|
|
<div class="arrow-icon-circle" @click="togglePlay">
|
|
|
- <span class="play-text">{{ isPlaying ? '暂停' : '播放' }}</span>
|
|
|
+ <span class="play-text">{{ isPlaying ? '暂停' : '自动' }}</span>
|
|
|
</div>
|
|
|
<div class="arrow-icon-circle" @click="playNext" :class="{ 'disabled': currentSectionIndex === scriptData.sections.length - 1 && currentDialogueIndex === currentSection.dialogues.length - 1 }">
|
|
|
<el-icon class="arrow-icon"><CaretRight /></el-icon>
|
|
|
@@ -297,7 +297,7 @@ const playBackgroundAudio = () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const playDialogueAudio = () => {
|
|
|
+const playDialogueAudio = (isAutoPlay = false) => {
|
|
|
// 停止之前的对话语音
|
|
|
if (dialogueAudio.value) {
|
|
|
dialogueAudio.value.pause()
|
|
|
@@ -306,41 +306,49 @@ const playDialogueAudio = () => {
|
|
|
|
|
|
// 播放当前对话的语音
|
|
|
if (currentDialogue.value?.voiceoverUrl) {
|
|
|
- dialogueAudio.value = new Audio(currentDialogue.value.voiceoverUrl)
|
|
|
- return new Promise((resolve) => {
|
|
|
- // 最短3秒跳转
|
|
|
- const minDelay = 3000
|
|
|
- let audioEnded = false
|
|
|
-
|
|
|
- // 音频结束事件
|
|
|
- dialogueAudio.value.onended = () => {
|
|
|
- audioEnded = true
|
|
|
- resolve()
|
|
|
+ const audio = new Audio(currentDialogue.value.voiceoverUrl)
|
|
|
+ dialogueAudio.value = audio
|
|
|
+
|
|
|
+ // 音频结束事件
|
|
|
+ audio.onended = () => {
|
|
|
+ // 如果是自动播放状态,继续播放下一条
|
|
|
+ if (isAutoPlay && isPlaying.value) {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (!playNext(true)) {
|
|
|
+ // 播放完毕
|
|
|
+ isPlaying.value = false
|
|
|
+ stopAllAudio()
|
|
|
+ }
|
|
|
+ }, 100)
|
|
|
}
|
|
|
-
|
|
|
- // 播放音频
|
|
|
- dialogueAudio.value.play().catch(e => {
|
|
|
- console.error('对话语音播放失败:', e)
|
|
|
- // 播放失败时,2秒后跳转
|
|
|
- setTimeout(resolve, minDelay)
|
|
|
- })
|
|
|
-
|
|
|
- // 检查音频时长
|
|
|
- dialogueAudio.value.addEventListener('loadedmetadata', () => {
|
|
|
- const duration = dialogueAudio.value.duration
|
|
|
- // 如果音频时长小于2秒,2秒后跳转
|
|
|
- if (duration < 2) {
|
|
|
- setTimeout(() => {
|
|
|
- if (!audioEnded) {
|
|
|
- resolve()
|
|
|
- }
|
|
|
- }, minDelay)
|
|
|
- }
|
|
|
- })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 播放音频
|
|
|
+ audio.play().catch(e => {
|
|
|
+ console.error('对话语音播放失败:', e)
|
|
|
+ // 播放失败时,2秒后跳转(暂时注销,因为会导致user类型数字人回复播报跳转后语音播报报错,直接2秒跳转)
|
|
|
+ // if (isAutoPlay && isPlaying.value) {
|
|
|
+ // setTimeout(() => {
|
|
|
+ // if (!playNext(true)) {
|
|
|
+ // // 播放完毕
|
|
|
+ // isPlaying.value = false
|
|
|
+ // stopAllAudio()
|
|
|
+ // }
|
|
|
+ // }, 2000)
|
|
|
+ // }
|
|
|
})
|
|
|
+ } else {
|
|
|
+ // 如果没有语音文件,2秒后跳转
|
|
|
+ if (isAutoPlay && isPlaying.value && currentDialogue.value?.type !== 'user') {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (!playNext(true)) {
|
|
|
+ // 播放完毕
|
|
|
+ isPlaying.value = false
|
|
|
+ stopAllAudio()
|
|
|
+ }
|
|
|
+ }, 2000)
|
|
|
+ }
|
|
|
}
|
|
|
- // 如果没有语音文件,2秒后跳转
|
|
|
- return new Promise(resolve => setTimeout(resolve, 2000))
|
|
|
}
|
|
|
|
|
|
const togglePlay = () => {
|
|
|
@@ -356,26 +364,15 @@ const togglePlay = () => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-const playSequence = async () => {
|
|
|
+// 自动播放序列
|
|
|
+const playSequence = () => {
|
|
|
if (!isPlaying.value) return
|
|
|
|
|
|
// 如果当前是用户输入卡片,暂停播放等待用户输入
|
|
|
- if (currentDialogue.value?.type === 'user') {
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 播放当前对话语音
|
|
|
- await playDialogueAudio()
|
|
|
+ if (currentDialogue.value?.type === 'user') return
|
|
|
|
|
|
- // 播放下一个对话
|
|
|
- if (!playNext()) {
|
|
|
- // 播放完毕
|
|
|
- isPlaying.value = false
|
|
|
- // 停止所有音频,包括背景音
|
|
|
- stopAllAudio()
|
|
|
- } else {
|
|
|
- playSequence()
|
|
|
- }
|
|
|
+ // 播放当前对话语音,传递isAutoPlay参数
|
|
|
+ playDialogueAudio(true)
|
|
|
}
|
|
|
|
|
|
const playPrevious = () => {
|
|
|
@@ -384,7 +381,7 @@ const playPrevious = () => {
|
|
|
|
|
|
// 如果正在进行数字人对话,调用stopStream清理
|
|
|
recoverQuestDialogue()
|
|
|
- stopPlayback()
|
|
|
+ stopPlayback(false) // 不触发回调
|
|
|
if (conversationInProgress.value) {
|
|
|
stopStream()
|
|
|
}
|
|
|
@@ -400,10 +397,14 @@ const playPrevious = () => {
|
|
|
// 播放背景音
|
|
|
playBackgroundAudio()
|
|
|
// 播放当前对话语音
|
|
|
- playDialogueAudio()
|
|
|
+ if (isPlaying.value) {
|
|
|
+ playDialogueAudio(true)
|
|
|
+ } else {
|
|
|
+ playDialogueAudio()
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-const playNext = () => {
|
|
|
+const playNext = (isAutoPlay = false) => {
|
|
|
// 停止当前对话语音
|
|
|
if (dialogueAudio.value) {
|
|
|
dialogueAudio.value.pause()
|
|
|
@@ -412,23 +413,31 @@ const playNext = () => {
|
|
|
|
|
|
// 如果正在进行数字人对话,调用stopStream清理
|
|
|
recoverQuestDialogue()
|
|
|
- stopPlayback()
|
|
|
+ stopPlayback(false)
|
|
|
if (conversationInProgress.value) {
|
|
|
stopStream()
|
|
|
}
|
|
|
|
|
|
if (currentSection.value && currentDialogueIndex.value < currentSection.value.dialogues.length - 1) {
|
|
|
currentDialogueIndex.value++
|
|
|
- // 播放当前对话语音
|
|
|
- playDialogueAudio()
|
|
|
+ // 根据是否为自动播放状态决定如何播放语音
|
|
|
+ if (isPlaying.value) {
|
|
|
+ playDialogueAudio(true)
|
|
|
+ } else {
|
|
|
+ playDialogueAudio()
|
|
|
+ }
|
|
|
return true
|
|
|
} else if (currentSectionIndex.value < props.scriptData.sections.length - 1) {
|
|
|
currentSectionIndex.value++
|
|
|
currentDialogueIndex.value = 0
|
|
|
// 播放背景音
|
|
|
playBackgroundAudio()
|
|
|
- // 播放当前对话语音
|
|
|
- playDialogueAudio()
|
|
|
+ // 根据是否为自动播放状态决定如何播放语音
|
|
|
+ if (isPlaying.value) {
|
|
|
+ playDialogueAudio(true)
|
|
|
+ } else {
|
|
|
+ playDialogueAudio()
|
|
|
+ }
|
|
|
return true
|
|
|
}
|
|
|
return false
|
|
|
@@ -630,10 +639,17 @@ const handleAudioPlaybackComplete = () => {
|
|
|
// AI回答完成后,如果之前是播放状态,继续播放
|
|
|
|
|
|
stopAllAudio();
|
|
|
- // // playNext()
|
|
|
- // if (isPlaying.value) {
|
|
|
- // playNext()
|
|
|
- // }
|
|
|
+ // 如果处于自动播放状态,继续播放下一条对话
|
|
|
+ if (isPlaying.value) {
|
|
|
+ if (playNext()) {
|
|
|
+ // 继续自动播放序列
|
|
|
+ playSequence();
|
|
|
+ } else {
|
|
|
+ // 播放完毕
|
|
|
+ isPlaying.value = false;
|
|
|
+ stopAllAudio();
|
|
|
+ }
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
// 组件挂载时添加键盘事件监听
|
|
|
@@ -651,7 +667,7 @@ onMounted(() => {
|
|
|
onUnmounted(() => {
|
|
|
window.removeEventListener('keydown', handleKeydown)
|
|
|
stopAllAudio()
|
|
|
- stopPlayback()
|
|
|
+ stopPlayback(false)
|
|
|
})
|
|
|
</script>
|
|
|
|