小喇叭修改

This commit is contained in:
tanglong 2026-10-27 15:25:29 +08:00
parent ed1fef31be
commit e74900bcb0
3 changed files with 27 additions and 34 deletions

1
.gitattributes vendored
View File

@ -4,3 +4,4 @@
*.png -text
*.jpg -text
*.jpeg -text
*.sh text eol=lf

View File

@ -16,8 +16,7 @@ if ! docker compose version >/dev/null 2>&1; then
exit 1
fi
# Do not reuse an old frontend layer: media files must always come from the
# currently uploaded source package.
# Force a fresh image so replaced media files cannot be hidden by build cache.
docker compose build --no-cache shuziren
docker compose up -d --force-recreate --remove-orphans shuziren

View File

@ -1,6 +1,6 @@
<template>
<main class="realtime-dh-wrapper">
<section class="realtime-dh-stage" @pointerdown.capture="unlockAudioAndPlay">
<section class="realtime-dh-stage" @pointerdown.capture.once="unlockAudioAndPlay">
<div class="visual-stage">
<div class="standby-scene" :class="{thinking: waitingForAnswer}">
<video
@ -92,11 +92,11 @@
type="button"
class="sound-button"
:class="{enabled: soundEnabled}"
:aria-label="soundEnabled ? '关闭声音' : '开启声音'"
:title="soundEnabled ? '声音已开启,点击关闭' : '声音已关闭,点击开启'"
@click="handleMute"
aria-label="开启并保持数字人声音"
title="开启并保持声音"
@click="enableSound"
>
<img :src="soundEnabled ? VoiceSvg : MutedSvg" class="mute-icon" alt="" />
<img :src="soundEnabled && audioUnlocked ? VoiceSvg : MutedSvg" class="mute-icon" alt="" />
</button>
</div>
@ -322,8 +322,10 @@ const tryPlayPendingAnswer = async () => {
const canPlayWithSound = audioUnlocked.value || await checkPlayUnMute();
if (generation !== connectionGeneration || !humanReady.value) return;
if (!canPlayWithSound) {
if (!soundUnlockTip.value) {
ElMessage.warning('请点击一次小喇叭开启数字人声音');
}
soundUnlockTip.value = true;
ElMessage.warning('请点击屏幕任意位置,数字人将开启声音并重新口播');
showToolbar();
return;
}
@ -331,7 +333,7 @@ const tryPlayPendingAnswer = async () => {
dhIframe.playVideo(true);
dhIframe.muteAudio(false);
videoIsMuted.value = false;
await new Promise(resolve => setTimeout(resolve, 350));
await new Promise(resolve => window.setTimeout(resolve, 240));
} else if (!soundEnabled.value && !videoIsMuted.value) {
dhIframe.muteAudio(true);
videoIsMuted.value = true;
@ -381,32 +383,9 @@ const handleVoiceError = (message) => {
const handleVoiceStatus = (message) => {
voiceStatus.value = message;
};
const handleMute = () => {
const nextEnabled = !soundEnabled.value;
soundEnabled.value = nextEnabled;
if (nextEnabled) {
audioUnlocked.value = true;
soundUnlockTip.value = false;
if (showHuman.value) dhIframe.playVideo(true);
} else {
soundUnlockTip.value = false;
}
if (!showHuman.value) {
showToolbar();
return;
}
dhIframe.muteAudio(!nextEnabled);
window.setTimeout(() => {
if (showHuman.value) {
videoIsMuted.value = !nextEnabled;
if (nextEnabled) void tryPlayPendingAnswer();
}
}, 300);
showToolbar();
};
const unlockAudioAndPlay = () => {
if (!soundEnabled.value) return;
if (audioUnlocked.value && !soundUnlockTip.value) return;
soundEnabled.value = true;
audioUnlocked.value = true;
soundUnlockTip.value = false;
if (showHuman.value) {
@ -418,6 +397,20 @@ const unlockAudioAndPlay = () => {
connectHuman();
}
};
const enableSound = () => {
soundEnabled.value = true;
audioUnlocked.value = true;
soundUnlockTip.value = false;
if (showHuman.value) {
dhIframe.playVideo(true);
dhIframe.muteAudio(false);
videoIsMuted.value = false;
window.setTimeout(() => void tryPlayPendingAnswer(), 120);
} else if (pendingSpeechText.value) {
connectHuman();
}
showToolbar();
};
const keepConnectionAlive = () => {
showTimeoutTip.value = false;
sendSpeech('我还在,很高兴继续为你服务。');
@ -439,7 +432,7 @@ const onMessage = (event) => {
humanVisualReady.value = false;
}
if (content.action === 'localVideoMuted') {
videoIsMuted.value = parseMutedState(content.body);
if (parseMutedState(content.body)) videoIsMuted.value = true;
if (soundEnabled.value && videoIsMuted.value && !audioUnlocked.value
&& (pendingSpeechText.value || speechBusy.value)) {
soundUnlockTip.value = true;