feat:语音对话优化

This commit is contained in:
2026-06-14 19:54:22 +08:00
parent 16105f5ac6
commit c3118dd72a
11 changed files with 156 additions and 52 deletions

View File

@@ -15,7 +15,7 @@ import { loadConfig, saveConfig } from "../lib/storage";
import { useI18n } from "../lib/i18n";
import { useCamera } from "../components/CameraManager";
import { useMicrophone } from "../components/MicManager";
import { useVAD, sampleFrame, compareFrames } from "../components/EdgeProcessor";
import { useVAD, sampleFrame } from "../components/EdgeProcessor";
import { useWebSocketManager } from "../components/WebSocketManager";
import { useObservationMode } from "./useObservationMode";
import type { ChatMessage, SessionConfig, ServerMessage, LLMDoneMessage } from "../types";
@@ -194,24 +194,13 @@ export function useVisionSession(accessToken?: string | null) {
ttsPlayerRef.current?.stop();
setIsAudioPlaying(false);
// 尝试捕获图像帧(允许为 null纯语音场景无需画面
const frame = captureFrame();
if (!frame) {
console.warn("[Session] 无法捕获图像帧");
return;
}
// 关键帧检测:与上一帧对比,相似度过高则跳过
// 更新帧参考(供观察模式使用,但不以此阻断语音请求)
const video = videoRef.current;
if (video) {
const currentSample = sampleFrame(video);
if (currentSample && prevFrameRef.current) {
const { similarity } = compareFrames(prevFrameRef.current, currentSample);
if (similarity > 0.9) {
console.log(`[Session] 画面无变化 (similarity=${similarity.toFixed(2)}),跳过`);
prevFrameRef.current = currentSample;
return;
}
}
if (currentSample) {
prevFrameRef.current = currentSample;
}
@@ -221,7 +210,7 @@ export function useVisionSession(accessToken?: string | null) {
send({
type: "query",
request_id: requestId,
image: dataUrlToBase64(frame),
image: frame ? dataUrlToBase64(frame) : "",
audio: encodeAudioToBase64(audio),
});
@@ -304,6 +293,20 @@ export function useVisionSession(accessToken?: string | null) {
case "error":
console.error("[Session] 服务端错误:", msg.code, msg.message);
showToast(getErrorMessage(msg.code, t), "error");
// STT 失败时:将"语音识别中..."占位消息替换为失败提示
if (msg.code === "STT_ERROR") {
setMessages((prev) => {
const updated = [...prev];
const lastUserIdx = updated.findLastIndex((m) => m.role === "user");
if (lastUserIdx >= 0 && updated[lastUserIdx].content === t("session.recognizing")) {
updated[lastUserIdx] = {
...updated[lastUserIdx],
content: t("session.sttFailed"),
};
}
return updated;
});
}
setIsProcessing(false);
break;
}