nc://live-voice

v0.1.0Pinned
ThomSharktools/nodecode-live-voice: Dictate to the agent from your microphone and hear its answers spoken aloud, through OpenAI's audio API. - a rewrite of Synero/hermes-live-voice (MIT), credited to Synerof59647d· 9 Nov1 commit
test1 filecell.lisp20.4 KBvoice.lisp11.7 KB

nodecode-live-voice

Live Voice: talk to your agent instead of typing, and hear its answers spoken aloud. A Nodecode rewrite of Synero/hermes-live-voice by Synero.

The original kept a full-duplex WebRTC call open between a desktop app and OpenAI's live model: a mic button in the composer, an iMessage-style transcript, tool calls spoken into a chat. An image has no WebRTC and no composer button, so the one call becomes two turns the model drives: voice_listen records from this machine's microphone and answers the words, voice_speak writes an answer as speech and plays it here, and /voice shows the transcript of both.

> make the tests green, I'll say it
voice_listen(seconds: 10)            -> "make the tests green"
   ... the agent works ...
voice_speak(text: "All twelve tests pass now.")
saved ~/.nodecode/voice/said_20261108_101500_3f2a9c1b.mp3
4.1 KB, mp3, gpt-4o-mini-tts (alloy), 29 characters
played here: the operator hears it now

Get it

Tell the agent "add the live-voice cell", or run:

nodecode add nc://live-voice

Set it up

The cell needs an OpenAI API key and, on this machine, a recorder and a player:

  • key — paste one into the cell's api_key in /settings, or export it:
    export OPENAI_API_KEY=...
  • a recorder, one of ffmpeg, sox's rec or arecord (alsa-utils), found on PATH.
  • a player, one of afplay, mpv, ffplay, sox's play, paplay or aplay, found on PATH.

/voice reports all four. When a device needs a flag of its own, name the whole command in recorder or player: %f is the file and %s the seconds, so an interface other than the default is one setting away — for example recorder = ffmpeg -f avfoundation -i "2:0" -t %s %f.

The section, as ~/.nodecode/config.jsonc carries it:

Setting Default What it does
api_key (unset) the OpenAI key, written inline as a secret
api_key_env OPENAI_API_KEY the variable read when api_key is empty
base_url https://api.openai.com/v1 change only for an OpenAI-compatible stand-in; https unless it is loopback
transcribe_model gpt-4o-mini-transcribe what voice_listen transcribes with (gpt-4o-transcribe, whisper-1)
speech_model gpt-4o-mini-tts what voice_speak speaks with (tts-1, tts-1-hd)
voice alloy the voice a call uses when it names none: alloy, ash, coral, echo, fable, nova, onyx, sage, shimmer, verse
audio_format mp3 what a spoken answer is saved as: mp3, wav, opus, flac or aac (aplay and paplay want wav)
max_seconds 60 the longest one recording may be
recorder (detected) a recorder command of your own, %f the file, %s the seconds
player (detected) a player command of your own, %f the file
directory voice/ where recordings, spoken files and transcript.jsonl are kept, under the home

Without a key nothing is sent and nothing is billed: the tool answers the sentence that says which setting to fill.

Use it

Tool What it does
voice_listen(seconds?, language?) records this machine's microphone (8 seconds unless set) and answers the words; language is an ISO-639-1 hint. One call per utterance
voice_speak(text, voice?, instructions?, play?) has OpenAI say text, saves it in the folder, and plays it here; instructions sets tone, pace and accent for gpt-4o-mini-tts; play false saves only

/voice reports the key, the microphone, the player, the folder and the last lines of the transcript. /voice say TEXT speaks. /voice hear [SECONDS] records and answers the words. /voice transcript lists what was heard and said. (help :voice) carries the primer the model reads.

The call waits while the answer plays, so the agent is told to keep the spoken form to a sentence or two and leave detail in the page: a hands-free reply is a summary, not the whole answer.

Cost and privacy. Every call is billed to your OpenAI account: transcription by the minute, speech by the character. What leaves the machine is the recording itself for voice_listen, and the spoken text and its instructions for voice_speak, sent to base_url with your key; nothing else of the conversation does. The recordings, the spoken files and the transcript stay in the folder, and a profile that loses the transcript loses a line of history, never the audio.

Tests

.github/test-cell.sh tools/nodecode-live-voice

No device and no network: the endpoint answers handcrafted bytes, a stub writes the WAV a recorder would write, and a machine with no player is a binding. The suite proves the request shapes and their headers, the file that comes back and the player that runs on it, the multipart transcription upload and the transcript line a recording leaves, and that a missing key, a missing recorder and a length past max_seconds all refuse before anything is sent.

Credits

A rewrite of Synero's Live Voice plugin for Hermes, MIT, at commit 0578e0cc35022a9dcb469cb9fbfc4d8afc93fc65: see NOTICE for what was rewritten and what was left out, and LICENSE for the original licence.

Add nc://live-voice

  1. 1

    Install Nodecode

    Once per machine.

    $ curl -fsSL https://nodecode.ai/install.sh | sh
  2. 2

    Add the cell

    Pinned at f59647d.

    $ nodecode add nc://live-voice

    Or tell the agent add the live voice cell.