h2voice

Audio to text. Voice for your agent.

Voice-to-text entirely on your machine — audio and video in, text out. No cloud, no API keys.

Queue for audio & video

Drop any audio or video: ffmpeg decodes, live segments, ETA.

Lives in the tray

Closes to the tray — the queue and voice API keep running.

Autodetect language

The first ~10 seconds detect the language — and the best model for it is picked automatically.

Full auto mode

decode → detect → route → transcribe → save. Walk away.

mp3 h2voice .txt

Podcasts, lectures & interviews

Downloaded an episode or lecture? Drop it in — get searchable text.

mp3 · m4a · wav · ogg
— you drop the file, — it picks the engine. .srt .txt

Subtitles & transcripts for video

Load a video, get a timestamped transcript — read, search, translate.

mp4 · mkv · webm · timestamps
h2code > add tests for the retry logic

Voice coding

Record, speak, send — your words land in the h2code prompt.

record → transcribe → prompt
0:07 E2EE h2voice your machine

h2code integration

Send voice messages from your phone or the desktop app — transcribed locally into the same session.

phone · desktop · local transcription

Three steps, one time

Download the app, let it pull the models once — after that h2voice simply lives in your system tray.

h2voice linux · macos · windows

Download the app

Grab the desktop build for your OS — Linux, macOS or Windows — and install it like any other app.

whisper.cpp multilingual STT GigaAM russian STT downloaded once · stored on your disk

Load the models

On first launch the app pulls the STT models once. From then on they live on your disk — nothing is fetched again.

h2voice closing… queue & voice API keep running

It lives in the tray

Close the window — the app keeps running in the system tray. The queue and voice API stay up; dictation is one hotkey away.

Voice protocol if you like to use it in your apps

h2voice serves a small HTTP/1.1 API on a local Unix domain socket — ~/.h2voice/voice.sock (chmod 0600, override with H2VOICE_VOICE_SOCKET). JSON in, JSON out; recording streams progress over Server-Sent Events. Audio and models never leave your machine.

GET /health Liveness + protocol version
# 200 OK
{"status": "ok", "version": "0.2.1"}
GET /v1/status Engine readiness, active session state
# 200 OK
{
  "recording": false,
  "device": "default",
  "stt_engine": "auto",
  "stt_ready": true,
  "language": "auto",
  "sample_rate": 16000
}
POST /v1/record/start Start mic capture — SSE stream

Request body (all fields optional): {"language": "auto", "stt_engine": "auto"}. The response is an SSE stream; the final transcript arrives as the result event.

# 200 OK — text/event-stream
data: {"type": "started", "sample_rate": 16000, "channels": 1, "device": "default"}

data: {"type": "level", "rms": 0.062}
data: {"type": "level", "rms": 0.118}

data: {"type": "stopped", "duration_ms": 2130}
data: {"type": "transcribing", "engine": "gigaam", "language": "ru"}
data: {"type": "result", "text": "добавь тесты на retry-логику", "duration_ms": 2130, "language": "ru", "engine": "gigaam"}
POST /v1/record/stop Stop capture — result via SSE
# 200 OK
{"status": "stopped", "duration_ms": 2130}
POST /v1/transcribe/file Transcribe a saved local file — synchronous

Request: {"path": "/home/u/notes.m4a", "engine": "auto", "language": null} — file up to 25 MB by default, from ~/.h2code/voice or the temp dir.

# 200 OK
{"text": "расшифрованный текст", "duration_sec": 12.4, "engine": "gigaam", "language": "ru"}
voice-api.sh
# liveness + protocol version
curl --unix-socket ~/.h2voice/voice.sock http://localhost/health
# → {"status": "ok", "version": "0.2.1"}

# transcribe a local file (engine & language are optional, "auto" by default)
curl --unix-socket ~/.h2voice/voice.sock http://localhost/v1/transcribe/file \
  -d '{"path": "/home/u/notes.m4a", "engine": "auto", "language": null}'
# → {"text": "…", "duration_sec": 12.4, "engine": "gigaam", "language": "ru"}

Engine auto-selection: Russian goes to GigaAM when ready, everything else to Whisper. A headless h2voice-server serves the same protocol and socket for running without the GUI.