comparison plugins/voicenote/voicenote.vim @ 22:c8ad85e95854 default tip

Some general updates
author Luka Sitas <lsitas@avatarasoftware.com>
date Thu, 16 Jul 2026 14:47:23 -0400
parents 203279635445
children
comparison
equal deleted inserted replaced
21:20ce06ac3a68 22:c8ad85e95854
1 let g:audio_record_file = -1 1 " Voicenote
2 let g:audio_record_tmp_file = -1 2 " A very simple plugin for transcribing text and inserting it into vim at the
3 let g:audio_record_cmd = expand('~/record.sh') 3 " cursor.
4 let g:audio_transcribe_cmd = expand('~/transcribe.sh') 4 " Utilizes simple shell commands to record audio at the press of a key binding
5 let g:audio_record_pid = -1 5 " Then stops recording after another keybinding
6 let g:audio_record_transcript_file = -1 6 " After recording sends the audio to an openai compatible audio transcription
7 " endpoint
8 " Finally parses the output and inserts the text at the cursor.
7 9
8 function! ToggleVoiceNote() 10 let g:record_job = -1
9 if g:audio_record_pid != -1 11 let g:record_job_running = -1
10 call StopRecording() 12 let g:record_file = ''
11 call TranscribeLastRecording() 13
12 else 14
13 call StartRecording() 15 " Begin new recording.
16 function! StartRecording()
17 " Check for already running recording.
18 if g:record_job_running < 0
19 let l:file = tempname()
20 let g:record_file = l:file
21 let g:record_job = job_start(['arecord', '-f', 'cd', '-r', '44100', l:file])
22 let g:record_job_running = 1
14 endif 23 endif
15 endfunction 24 endfunction
16 25
17 function! StartRecording() 26 " Stop the recording and transcribe.
18 if g:audio_record_pid != -1 27 function! StopRecording()
19 echo "Recording already in progress (PID " . g:audio_record_pid . ")" 28 " Check if we're already starting recording.
29 if g:record_job_running > 0
30 call StopAndWait(g:record_job)
31
32 " Transcribe the text.
33 let l:response = system('curl -s "http://127.0.0.1:52625/v1/audio/transcriptions" -F "model=whisper-v3" -F file=@' . g:record_file)
34 if !empty(l:response)
35 let l:data = json_decode(l:response)
36 if has_key(l:data, 'text')
37 execute 'normal! a' . escape(l:data.text, '\')
38 endif
39 endif
40
41 " Clean up.
42 let g:record_job_running = -1
43 let g:record_job = -1
44 let g:record_file = ''
45
46 endif
47 endfunction
48
49 function! StopAndWait(job)
50 " If the job is already dead, nothing to do
51 if empty(a:job) || job_status(a:job) == 'dead'
20 return 52 return
21 endif 53 endif
22 54
23 " Temp file where record.sh will write the WAV path 55 " Request the job to stop
24 let l:temp_file = tempname() 56 call job_stop(a:job)
25 57
26 " Run record.sh; its stdout (the wav path) goes to temp_file. 58 " Wait until the status reports it as dead
27 " Then echo the background PID. 59 while job_status(a:job) != 'dead'
28 let l:cmd = printf('%s > %s 2>/dev/null & echo $!', shellescape(g:audio_record_cmd), shellescape(l:temp_file)) 60 sleep 100m " adjust granularity if needed
29 61 endwhile
30 let l:pid = str2nr(system(l:cmd))
31
32 if l:pid <= 0
33 echoerr "Failed to start recording"
34 return
35 endif
36
37 " Read the file path written by record.sh
38 let g:audio_record_file = trim(system('cat ' . shellescape(l:temp_file)))
39 let g:audio_record_tmp_file = l:temp_file
40 let g:audio_record_pid = l:pid
41
42 echo "Recording started (PID " . g:audio_record_pid . ") -> " . g:audio_record_file
43 endfunction 62 endfunction
44 63
45 function! StopRecording() 64 nnoremap <leader>s :call StartRecording()<CR>
46 if g:audio_record_pid == -1 65 nnoremap <leader>e :call StopRecording()<CR>
47 echo "No recording in progress"
48 return
49 endif
50
51 call system('kill ' . g:audio_record_pid)
52
53 if g:audio_record_tmp_file != -1
54 call system('rm -f ' . shellescape(g:audio_record_tmp_file))
55 let g:audio_record_tmp_file = -1
56 endif
57
58 let g:audio_record_pid = -1
59 let g:audio_record_transcript_file = -1
60
61 echo "Recording stopped."
62 endfunction
63
64
65 function! TranscribeLastRecording()
66 if g:audio_record_file == -1
67 echo "No recent recording"
68 return
69 endif
70
71 let l:cmd = printf('%s %s', shellescape(g:audio_transcribe_cmd), shellescape(g:audio_record_file))
72
73 " transcribe.sh echoes the .txt path
74 let l:transcription_file = trim(system(l:cmd))
75
76 if v:shell_error != 0 || empty(l:transcription_file)
77 echoerr "Transcription failed"
78 return
79 endif
80
81 let g:audio_record_file = -1
82 execute 'tabe' fnameescape(l:transcription_file)
83 endfunction
84
85
86
87 " BINDINGS
88
89 command! VoiceNote call ToggleVoiceNote()
90
91 nnoremap <Leader>vn :VoiceNote<CR>