Mercurial > vim
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> |
