// dudu 桌面端 · 识别浮层演示 // 在仿真备忘录窗口上方演示完整 push-to-talk 流程: // 按住按钮(= 按住 ⌘⇧Space)→ 聆听中 → partial 流式 → 松开 → final 注入输入框 const DEMO_SENTENCES = [ '帮我把这份周报整理一下,重点突出本周的进展和下周的计划。', '好的,我马上把文件发给你,大概十分钟之内。', '明天上午十点的会改到下午三点,记得同步给项目组。', ]; function OverlayDemo() { const { RecognitionOverlay } = window.DuduDesignSystem_2e0172; const [phase, setPhase] = React.useState('idle'); // idle | listening | streaming const [finalText, setFinalText] = React.useState(''); const [partialText, setPartialText] = React.useState(''); const [docText, setDocText] = React.useState(''); const [sentenceIdx, setSentenceIdx] = React.useState(0); const timerRef = React.useRef(null); const stateRef = React.useRef({}); stateRef.current = { finalText, partialText, sentenceIdx }; const stop = React.useCallback(() => { clearInterval(timerRef.current); const { finalText: f, partialText: p, sentenceIdx: idx } = stateRef.current; const committed = f + p; if (committed) { setDocText((d) => d + committed); setSentenceIdx((idx + 1) % DEMO_SENTENCES.length); } setFinalText(''); setPartialText(''); setPhase('idle'); }, []); const start = React.useCallback(() => { if (timerRef.current) clearInterval(timerRef.current); setPhase('listening'); setFinalText(''); setPartialText(''); const sentence = DEMO_SENTENCES[stateRef.current.sentenceIdx]; let i = 0; setTimeout(() => setPhase((ph) => (ph === 'listening' ? 'streaming' : ph)), 420); timerRef.current = setInterval(() => { i += 1; if (i >= sentence.length) { clearInterval(timerRef.current); setFinalText(sentence); setPartialText(''); return; } // 模拟流式:句读处定稿(final),其余为 partial const lastPunct = Math.max(sentence.lastIndexOf(',', i), sentence.lastIndexOf('。', i)); setFinalText(sentence.slice(0, lastPunct + 1)); setPartialText(sentence.slice(lastPunct + 1, i)); }, 90); }, []); React.useEffect(() => () => clearInterval(timerRef.current), []); const overlayState = phase === 'streaming' && (finalText || partialText) ? 'text' : 'listening'; return (