From 158d90f41504a02723f10a5baa6513a18c2f2501 Mon Sep 17 00:00:00 2001 From: Arjun <6592213+arkml@users.noreply.github.com> Date: Mon, 2 Feb 2026 23:05:37 +0530 Subject: [PATCH] feat: transcribe voice memos with Deepgram and save as .txt After saving a voice memo, send the audio to Deepgram's Nova-2 STT API and write the transcript as a .txt file alongside the audio in ~/.rowboat/voice_memos/. Reads the API key from config/deepgram.json. Co-Authored-By: Claude Opus 4.5 --- .../src/components/sidebar-content.tsx | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/apps/x/apps/renderer/src/components/sidebar-content.tsx b/apps/x/apps/renderer/src/components/sidebar-content.tsx index f42e64d9..de60eee8 100644 --- a/apps/x/apps/renderer/src/components/sidebar-content.tsx +++ b/apps/x/apps/renderer/src/components/sidebar-content.tsx @@ -143,6 +143,35 @@ export function SidebarContentPanel({ ) } +async function transcribeWithDeepgram(audioBlob: Blob): Promise { + try { + const configResult = await window.ipc.invoke('workspace:readFile', { + path: 'config/deepgram.json', + encoding: 'utf8', + }) + const { api_key } = JSON.parse(configResult.data) as { api_key: string } + if (!api_key) throw new Error('No api_key in deepgram.json') + + const response = await fetch( + 'https://api.deepgram.com/v1/listen?model=nova-2&smart_format=true', + { + method: 'POST', + headers: { + Authorization: `Token ${api_key}`, + 'Content-Type': audioBlob.type, + }, + body: audioBlob, + }, + ) + + if (!response.ok) throw new Error(`Deepgram API error: ${response.status}`) + const result = await response.json() + return result.results?.channels?.[0]?.alternatives?.[0]?.transcript ?? null + } catch { + return null + } +} + // Voice Note Recording Button function VoiceNoteButton() { const [isRecording, setIsRecording] = React.useState(false) @@ -191,6 +220,21 @@ function VoiceNoteButton() { toast('Voice memo saved', 'success') } catch { toast('Failed to save voice memo', 'error') + return + } + + // Transcribe and save transcript alongside the audio file + const transcript = await transcribeWithDeepgram(blob) + if (transcript) { + const txtFilename = filename.replace(/\.[^.]+$/, '.txt') + await window.ipc.invoke('workspace:writeFile', { + path: `voice_memos/${txtFilename}`, + data: transcript, + opts: { encoding: 'utf8' }, + }) + toast('Transcription saved', 'success') + } else { + toast('Transcription failed', 'error') } }