SuperAPI AI Directory

parakeet

General & other

View repository

Updated 10-16 04:28

About this skill

Parakeet: Local Speech-to-Text (MLX)

Two MLX engines run fully offline on the Metal GPU. Every script is a uv run --script file with inline dependencies, so there is no venv to maintain.

Engine Model Strength Weakness
parakeet mlx-community/parakeet-tdt-0.6b-v2 Fast, per-word confidence, returns empty on non-speech No vocabulary biasing
qwen3 mlx-community/Qwen3-ASR-1.7B-8bit Best open-weight WER (4.95, Open ASR Leaderboard 2026-09-19), hotwords Hallucinates interjections on SFX; can loop without a token cap

Run both on anything that becomes evidence. Their disagreement is the confidence signal.

Commands

S=~/.claude/skills/parakeet/scripts

# One file -> text on stdout (parakeet engine; --engine both prints status<TAB>parakeet<TAB>qwen3)
$S/transcribe.py clip.wav
Batch: files or directories -> JSONL manifest (both engines by default)

$S/batch_transcribe.py clips/ --out manifest.jsonl $S/batch_transcribe.py clips/ --context-file vocab.txt # Qwen3 hotwords, one per line $S/batch_transcribe.py a.wav --engine qwen3 --language auto # or a name / ISO code (fr, French) $S/batch_transcribe.py a.wav --engine parakeet --beam 4 # beam search

Setup check (fast), or full round trip with synthesized speech (downloads ~5 GB once)

$S/check_setup.py $S/check_setup.py --load

Terminal dictation: record until Enter, then transcribe

$S/dictate.py

OpenAI-compatible server (warm models; model ids: parakeet-tdt-0.6b, qwen3-asr)

$S/parakeet_server.py --port 8384 --preload parakeet


Formats: anything ffmpeg decodes (wav incl. 8-bit/ADPCM, mp3, m4a, flac, ogg, aac, webm, aiff).

## Batch Output and Status

Each JSONL record holds the source `sha256`, `duration_s`, `sample_rate_src`, `codec`, the
decode check (`samples`, `peak_dbfs`, `gain_db`, `length_mismatch`), and per-engine `text`,
`model`, and HF `revision`. Parakeet adds `words[{w,start,end,conf}]` and `min_conf`. Qwen3
adds `truncated` and `echo_stripped` (with `raw_text` when it fired). With `--engine both`,
each record gets a `status`:

| Status | Meaning | Action |
|--------|---------|--------|
| `agreed` | Normalized transcripts match, Parakeet `min_conf` ≥ `--min-conf` (0.5), no flag set | Corroborated; still cite as ASR evidence |
| `needs_listen` | Anything else containing words: a disagreement, low or missing confidence, a truncated or echo-stripped Qwen3 result, a length mismatch | A person listens before citing |
| `sfx_likely` | Parakeet empty; Qwen3 produced only interjections ("Oh.", "Whoa.", a loop of them) or only recited its hotwords | Treat as non-speech |
| `silent` | Both engines empty | Non-speech |
| `error` | Decode or transcription failed; `error` carries ffmpeg's reason | Fix the file or exclude it |

One-word lines that are plausible speech ("Fire!", "Okay.") are never `sfx_likely`.
Normalization lowercases, strips punctuation, and folds number words ("One" → "1") and
spelling variants ("manoeuvre" → "maneuver").

With `--out`, records stream to `<out>.partial`. That file is renamed only when the run
completes, and `<out>.meta.json` records the parameters, model revisions, package versions, a
hotword-list hash, the script's sha256, timings, and counts. One bad file never ends a batch,
but the exit status is 1 if any clip errored. Schema and API notes: `references/parakeet-api.md`.

## Short Clips and Legacy Game Audio

Measured on 351 Star Wars Rebellion WAVE resources: 276 are 8-bit PCM and 71 are 16-bit, all at
11,025 Hz, plus 4 that are 16-bit at 44.1 kHz.

- **Padding.** Clips under 2 s get 0.75 s of silence on each side. This lost no words across 30
  short speech clips. It cut Parakeet's hallucinations on short TACTICAL SFX from 23 of 42 clips
  to 2 (unpadded: "Me, me, me.", "Ha ha ha ha!"). Use `--pad 0` to disable.
- **Qwen3 loops.** On one 2.3 s SFX clip Qwen3 produced "Oh, oh, oh, ..." for about 4.7 minutes,
  up to its 8192-token default. Tokens are now capped at `12 * duration_s + 32`, and a clip that
  hits the cap is marked `truncated`.
- **Hotwords are a targeted tool, not a default.** Measured on the same corpus:
  - A 1,196-term dump of every game UI string made Qwen3 recite the list on SFX ("0 Points
    Available, 1 Construction Yards, ...") and doubled prefill time. Whole-output recitations
    are detected (`echo_stripped`), but words inside real speech are never removed.
  - A focused 43-term proper-noun primer made Qwen3 return *empty* on all 63 SFX clips, which is
    the cleanest speech/SFX split. On speech it changed "Censors" to "Sensors" but flipped three
    "There is" lines to "That is" (Parakeet and unprimed Qwen3 agree on "There is").
  - Workflow: run without hotwords first, then re-run only the `needs_listen` clips with a small
    primer as a third opinion. Use a primer on the full run when the goal is SFX triage.
- **Levels.** ffmpeg resamples to 16 kHz mono and peak-normalizes to -1 dBFS. Audio below
  -60 dBFS is left unamplified, because amplifying a noise floor feeds hallucination.

## Long Audio

Recordings over 5 minutes are cut at the quietest 100 ms frame near every 60 s, and each segment
is decoded independently. parakeet-mlx 0.5.2's own overlapping chunker is not used: on a 418 s
test file it dropped a sentence and duplicated two others at a chunk boundary. The segmented
path matched the per-clip ground truth at 0.985 word similarity, with no dropped or duplicated
lines, at 88x realtime. Qwen3 uses mlx-audio's internal chunking (20-minute windows).

## Performance (M4 Max, 36 GB)

| Run | Result |
|-----|--------|
| Parakeet only, 351 clips / 975 s audio | 44 s (22x realtime; per-clip ffmpeg dominates) |
| Both engines, 351 clips | 91 s (11x realtime): 270 agreed, 20 needs_listen, 61 sfx_likely |
| Both engines + 43-term primer | 124 s (8x realtime) |

These timings come from the runs' own summary lines. Newer runs also record them in `.meta.json`.
In the two-engine run, 20 clips were `needs_listen`: 5 TACTICAL SFX-or-speech calls (including
"Yeah." and "Okay.", held because they are plausible one-word lines) and 15 speech lines. In 13 of the 15, Parakeet's reading is implausible and Qwen3's is the plausible
one ("Goal Group" vs Gold Group, "Deaths are approaching" vs Death Star approaching). No one has
listened to those clips yet, so Qwen3's text is a strong hypothesis, not ground truth. In one
clip both were wrong ("Census"/"Censors" for Sensors), and one differed only in formatting
("Task Force V" vs "Five"). Parakeet's `min_conf` on those lines ran 0.65–0.98, so confidence
alone would have passed them.

Don't run two batch jobs at once: they share the GPU, and a contended run took 5x longer.
A cold first load downloads about 2.5 GB per model into `~/.cache/huggingface/hub`.

## Handy (Push-to-Talk Dictation)

[Handy](https://github.com/cjpais/Handy) handles system-wide push-to-talk (Option-Space).
Upgrade to 0.9.7 or later with `brew upgrade --cask handy`, then pick a model in Settings.
The `handy-computer` org publishes `parakeet-unified-en-0.6b-gguf` (NVIDIA 2026-04, offline and
streaming in one model); check whether your Handy version lists it. For live multilingual
streaming, `nvidia/nemotron-3.5-asr-streaming-0.6b` (2026-06, 40 locales) is the current NVIDIA
model. Handy is for dictation, not batch evidence.

## Legacy

`~/Programming/parakeet-dictate` (NeMo/PyTorch menubar app, Voxtral backend) is superseded and has
no venv. Nothing here depends on it or on `PARAKEET_HOME`.