Transcripts were far worse on Linux than on Windows for the same model, because
of what reached the API rather than the model itself.
Picking any mic from the tray menu never worked: PortAudio exposes the friendly
names through PipeWire's JACK host API, which only accepts 48 kHz, so opening at
16 kHz failed outright and recording always fell back to the system default —
whichever source PipeWire happened to prefer at that moment. That source is
often the raw AMD digital mic, which ships a +0.14 FS DC bias, a full-scale
clipped click in the first 15 ms of every stream, and speech around -50 dBFS.
Windows' vendor driver hides all of this; PipeWire hands over the raw stream.
- Negotiate rate and channels per device, then downmix and resample with
resample_poly, so every listed device can actually be recorded from.
- Hide devices that cannot work: playback endpoints JACK re-exposes as inputs,
and raw ALSA hw: devices a sound server already owns (acp: hw:2,0 blocks
forever on open).
- Persist the chosen device by name in device.txt; PortAudio indices shift as
USB gear comes and goes. Add a "System default" menu entry.
- Condition every clip before upload: trim the warm-up click, high-pass out DC,
normalise towards -20 dBFS under a -1 dBFS ceiling.
- Refuse near-silent clips instead of paying for a hallucination, and log
capture levels (speech, rms, peak, DC, clipping) plus PortAudio status
warnings, which previously went to a discarded stderr.
- Import scipy.signal as dsp: it was shadowing the stdlib signal module that
the SIGUSR1 hotkey toggle depends on.
mic_check.py records from Blurt's configured input, reports levels before and
after conditioning, saves the WAV, and transcribes it with the current model.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Launches Blurt via `uv run --project`, which resolves the project/venv
without altering cwd. Blurt anchors all config to the script location,
so no working-directory change is needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
README documents minimal setup, run, and config for Linux and Windows. export.py bundles just the source into a zip (no .venv, caches, or API key files) for moving to another machine; it's pure stdlib run via 'uv run export.py', so it behaves identically on Linux and Windows with no shell required.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Transcription:
- Provider-pluggable backend: each model routes to OpenAI (multipart
upload) or OpenRouter (JSON + base64 body). Add OpenRouter's
whisper-large-v3-turbo (Groq-served, ~216x real-time) to the tray
menu for far lower latency than whisper-1.
- Load API keys env -> keyring -> file for both providers via a shared
helper.
- Encode the WAV in memory and reuse a warm requests.Session (no temp file).
Other improvements:
- blurt-toggle signals the running app directly via SIGUSR1 instead of
paying ~0.5s to import the full stack through "uv run blurt toggle".
- Remove the redundant dead blurt shell script.
- Suppress the benign Gdk-CRITICAL warning from pystray's GtkStatusIcon.
- gitignore openrouter_key.txt.
Transcription code is platform-agnostic; the Windows/Linux platform layer
is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>