From ab90b7c7df7f9cc002c8a2eadfccdfe87c3d1cc2 Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Mon, 9 Feb 2026 16:47:58 +0800 Subject: [PATCH] Voice debug drawer can select device and asr no duplicate --- web/pages/Assistants.tsx | 43 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/web/pages/Assistants.tsx b/web/pages/Assistants.tsx index 0de0761..5956363 100644 --- a/web/pages/Assistants.tsx +++ b/web/pages/Assistants.tsx @@ -1076,6 +1076,7 @@ export const DebugDrawer: React.FC<{ const micProcessorRef = useRef(null); const micGainRef = useRef(null); const userDraftIndexRef = useRef(null); + const lastUserFinalRef = useRef(''); // Initialize useEffect(() => { @@ -1382,6 +1383,7 @@ export const DebugDrawer: React.FC<{ try { setCallStatus('calling'); setMessages([]); + lastUserFinalRef.current = ''; setWsError(''); closeWs(); if (textTtsEnabled) await ensureAudioContext(); @@ -1406,6 +1408,7 @@ export const DebugDrawer: React.FC<{ closeWs(); setCallStatus('idle'); setMessages([]); + lastUserFinalRef.current = ''; setIsLoading(false); }; @@ -1450,6 +1453,7 @@ export const DebugDrawer: React.FC<{ setWsError(''); // Start every text debug run as a fresh session transcript. setMessages([]); + lastUserFinalRef.current = ''; assistantDraftIndexRef.current = null; // Force a fresh WS session so updated assistant runtime config // (voice/model/provider/speed) is applied on session.start. @@ -1566,6 +1570,7 @@ export const DebugDrawer: React.FC<{ pendingRejectRef.current = null; assistantDraftIndexRef.current = null; userDraftIndexRef.current = null; + lastUserFinalRef.current = ''; setTextSessionStarted(false); stopPlaybackImmediately(); if (isOpen) setWsStatus('disconnected'); @@ -1670,7 +1675,8 @@ export const DebugDrawer: React.FC<{ return next; } const next = [...prev]; - next[idx] = { ...next[idx], text: next[idx].text + delta }; + // ASR interim is typically the latest partial text, not a true text delta. + next[idx] = { ...next[idx], text: delta }; return next; }); return; @@ -1678,15 +1684,37 @@ export const DebugDrawer: React.FC<{ if (type === 'transcript.final') { const finalText = String(payload.text || ''); + if (!finalText) { + userDraftIndexRef.current = null; + return; + } + if (lastUserFinalRef.current === finalText) { + userDraftIndexRef.current = null; + return; + } setMessages((prev) => { const idx = userDraftIndexRef.current; userDraftIndexRef.current = null; if (idx !== null && prev[idx] && prev[idx].role === 'user') { const next = [...prev]; next[idx] = { ...next[idx], text: finalText || next[idx].text }; + lastUserFinalRef.current = finalText; return next; } - if (!finalText) return prev; + const last = prev[prev.length - 1]; + if (last?.role === 'user') { + if (last.text === finalText) { + lastUserFinalRef.current = finalText; + return prev; + } + if (finalText.startsWith(last.text) || last.text.startsWith(finalText)) { + const next = [...prev]; + next[next.length - 1] = { ...last, text: finalText }; + lastUserFinalRef.current = finalText; + return next; + } + } + lastUserFinalRef.current = finalText; return [...prev, { role: 'user', text: finalText }]; }); return; @@ -1986,6 +2014,17 @@ export const DebugDrawer: React.FC<{
{mode === 'voice' ? (
+
+ +