mcpField
P
parakeet

parakeet

github.com/tdiminoCreative & media4145 installsUpdated 1w ago
Repository

About parakeet

parakeet is a local speech-to-text skill for processing audio offline with two MLX engines on the Metal GPU. It supports single-file and batch transcription, with status labels that help identify clips needing human review.

Key features

  1. 01Offline transcription with two MLX engines
  2. 02Single-file and batch processing
  3. 03JSONL manifests with decode metadata
  4. 04Confidence and review status labels
  5. 05Audio format support via ffmpeg

Use cases

  1. 01Transcribe audio clips locally
  2. 02Batch-process recordings into a manifest
  3. 03Flag uncertain or likely non-speech clips
  4. 04Review long recordings in segments

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/tdimino/claude-code-minoan --skill parakeet

After installing, type/parakeetin Claude Code to confirm it loaded.

Bundled files

References and scripts installed along with SKILL.md.

README.md
references/
parakeet-api.md
scripts/
batch_transcribe.py
check_setup.py
dictate.py
parakeet_server.py
transcribe.py

Details

From the project README

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.

EngineModelStrengthWeakness
parakeetmlx-community/parakeet-tdt-0.6b-v2Fast, per-word confidence, returns empty on non-speechNo vocabulary biasing
qwen3mlx-community/Qwen3-ASR-1.7B-8bitBest open-weight WER (4.95, Open ASR Leaderboard 2026-09-19), hotwordsHallucinates 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:

StatusMeaningAction
agreedNormalized transcripts match, Parakeet min_conf ≥ --min-conf (0.5), no flag setCorroborated; still cite as ASR evidence
needs_listenAnything else containing words: a disagreement, low or missing confidence, a truncated or echo-stripped Qwen3 result, a length mismatchA person listens before citing
sfx_likelyParakeet empty; Qwen3 produced only interjections ("Oh.", "Whoa.", a loop of them) or only recited its hotwordsTreat as non-speech
silentBoth engines emptyNon-speech
errorDecode or transcription failed; error carries ffmpeg's reasonFix 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)

RunResult
Parakeet only, 351 clips / 975 s audio44 s (22x realtime; per-clip ffmpeg dominates)
Both engines, 351 clips91 s (11x realtime): 270 agreed, 20 needs_listen, 61 sfx_likely
Both engines + 43-term primer124 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 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.

Comments

Markdown supported