From 7513ec69ac32a9a1e93dd0eccbcc2a3019c88636 Mon Sep 17 00:00:00 2001 From: Arjun <6592213+arkml@users.noreply.github.com> Date: Tue, 17 Mar 2026 17:27:15 +0530 Subject: [PATCH] auto stop on silence --- apps/x/apps/renderer/src/App.tsx | 1 + .../src/hooks/useMeetingTranscription.ts | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx index 950cac31..34f96052 100644 --- a/apps/x/apps/renderer/src/App.tsx +++ b/apps/x/apps/renderer/src/App.tsx @@ -3387,6 +3387,7 @@ function App() { } } }, [meetingTranscription, handleVoiceNoteCreated]) + handleToggleMeetingRef.current = handleToggleMeeting const ensureWikiFile = useCallback(async (wikiPath: string) => { const resolvedPath = toKnowledgePath(wikiPath) diff --git a/apps/x/apps/renderer/src/hooks/useMeetingTranscription.ts b/apps/x/apps/renderer/src/hooks/useMeetingTranscription.ts index 26f15b17..e4cec727 100644 --- a/apps/x/apps/renderer/src/hooks/useMeetingTranscription.ts +++ b/apps/x/apps/renderer/src/hooks/useMeetingTranscription.ts @@ -18,6 +18,9 @@ const DEEPGRAM_LISTEN_URL = `wss://api.deepgram.com/v1/listen?${DEEPGRAM_PARAMS. // RMS threshold: system audio above this = "active" (speakers playing) const SYSTEM_AUDIO_GATE_THRESHOLD = 0.005; +// Auto-stop after 2 minutes of silence (no transcript from Deepgram) +const SILENCE_AUTO_STOP_MS = 2 * 60 * 1000; + // --------------------------------------------------------------------------- // Headphone detection // --------------------------------------------------------------------------- @@ -68,7 +71,7 @@ function formatTranscript(entries: TranscriptEntry[], date: string): string { // --------------------------------------------------------------------------- // Hook // --------------------------------------------------------------------------- -export function useMeetingTranscription() { +export function useMeetingTranscription(onAutoStop?: () => void) { const [state, setState] = useState('idle'); const wsRef = useRef(null); const micStreamRef = useRef(null); @@ -79,6 +82,9 @@ export function useMeetingTranscription() { const interimRef = useRef>(new Map()); const notePathRef = useRef(''); const writeTimerRef = useRef | null>(null); + const silenceTimerRef = useRef | null>(null); + const onAutoStopRef = useRef(onAutoStop); + onAutoStopRef.current = onAutoStop; const dateRef = useRef(''); const writeTranscriptToFile = useCallback(async () => { @@ -117,6 +123,10 @@ export function useMeetingTranscription() { clearTimeout(writeTimerRef.current); writeTimerRef.current = null; } + if (silenceTimerRef.current) { + clearTimeout(silenceTimerRef.current); + silenceTimerRef.current = null; + } if (processorRef.current) { processorRef.current.disconnect(); processorRef.current = null; @@ -195,6 +205,13 @@ export function useMeetingTranscription() { const transcript = data.channel.alternatives[0].transcript; if (!transcript) return; + // Reset silence auto-stop timer on any transcript + if (silenceTimerRef.current) clearTimeout(silenceTimerRef.current); + silenceTimerRef.current = setTimeout(() => { + console.log('[meeting] 2 minutes of silence — auto-stopping'); + onAutoStopRef.current?.(); + }, SILENCE_AUTO_STOP_MS); + const channelIndex = data.channel_index?.[0] ?? 0; const isMic = channelIndex === 0;