felixmandClaude Opus 5 6ad8526920 Add Voxtral Small 24B as a transcription option
Whisper large-v3 mis-segments unfamiliar proper nouns: "Whisper Large"
came back as "Wisp Alarge", and it leaves doubled words and sentence
breaks in the wrong places. Voxtral decodes with a 24B language model,
so ambiguous acoustics get resolved against what a sentence can mean.
Checked both against saved captures: Voxtral fixed the proper noun and
the punctuation, at 1.7 s round-trip for 15 s of audio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QrC2xo3RUExhVPzWGnGfRK
2026-08-22 09:22:13 -04:00
2026-05-30 23:30:37 -04:00
2026-05-30 23:30:37 -04:00
2026-05-30 23:30:37 -04:00

Blurt

Tray-based push-to-talk voice-to-text for Linux and Windows. Toggle recording with a hotkey, speak, toggle off — Blurt transcribes the clip and copies the text to your clipboard.

If a transcript starts with to my agent, the rest is dispatched as an agent task instead of copied.

Setup

Requires uv and Python 3.11+.

uv sync

API key

Blurt reads the key for its current model's provider in this order: environment variable → OS keyring → local file.

Provider Env var Keyring (service / user) File
OpenAI OPENAI_API_KEY openai-api-key / felixm api_key.txt
OpenRouter OPENROUTER_API_KEY openrouter-api-key / felixm openrouter_key.txt

Key files and runtime config stay local (gitignored).

Running

Linux — uv run blurt starts the tray icon. Bind a hotkey to ./blurt-toggle, which signals the running instance to start/stop recording.

Windows — launch blurt.vbs (runs Blurt with no console window). The global hotkey is F20.

Configuration

Set from the tray menu, or via files / env vars:

  • Model — model.txt / BLURT_TRANSCRIPTION_MODEL. For lowest latency use openai/whisper-large-v3-turbo (OpenRouter, served by Groq).
  • Language — language.txt / BLURT_TRANSCRIPTION_LANGUAGE (en, de).
  • Input device — tray menu (persisted by name in device.txt / BLURT_INPUT_DEVICE). Pick an explicit mic: PortAudio device indices shift when USB gear comes and goes, and the OS default source can change under you. The menu hides playback endpoints and raw ALSA hw: devices that the sound server already owns; BLURT_INPUT_DEVICE can still name one directly. Devices that refuse 16 kHz (raw ALSA and PipeWire's JACK endpoints do) are captured at their native rate and resampled.

Every clip is conditioned before upload — the stream-open click is trimmed off the front (only as much of it as is actually there, up to 150 ms), DC bias is filtered out, and the level is normalised towards -20 dBFS. Near-silent clips are refused instead of being sent, since transcription models answer silence with confident hallucinations.

Nothing else is cut: the whole recording is uploaded. If a transcript comes back missing words, check blurt.log — each clip logs its length, speech level, noise floor, and dead=, the longest run of digital silence inside it. A non-zero dead= means the input dropped out mid-clip, which is what following the system default source invites; pin a device instead. Set BLURT_SAVE_CAPTURES=1 (or to a directory) to keep the raw and uploaded WAVs for every clip and hear exactly what the API got.

Checking the microphone

uv run mic_check.py [device] [seconds] records from Blurt's configured input, prints levels before and after conditioning, saves the WAV it would have uploaded, and transcribes it with the current model. Use it when transcripts come back wrong: bad audio shows up as a DC bias, clipping, or a speech level far below -30 dBFS.

Logs are written to blurt.log in your temp directory (openable from the tray menu).

Moving to another machine

uv run export.py writes a zip of just the source (no 200 MB+ .venv, no caches, no key files) to your temp directory. It's pure Python, so it runs the same on Linux and Windows — no shell needed — and it only reads, so it's safe while Blurt is recording. Unzip on the other machine and uv sync to rebuild .venv for that OS. (Or simply git clone the repo fresh.)

S
Description
No description provided
Readme
288 KiB
Languages
Python 99.6%
Shell 0.3%
VBScript 0.1%