Skip to content

fix(mlx_whisper): recast "auto"/blank language to None server-side - #8

Merged
vr000m merged 4 commits into
mainfrom
fix/whisper-auto-language
Jun 6, 2026
Merged

fix(mlx_whisper): recast "auto"/blank language to None server-side#8
vr000m merged 4 commits into
mainfrom
fix/whisper-auto-language

Conversation

@vr000m

@vr000m vr000m commented Jun 6, 2026

Copy link
Copy Markdown
Owner

Summary

Makes "auto" a safe, uniform "detect the language" sentinel across all STT backends by recasting it server-side, instead of asking every client to special-case it.

Why

A client connects to a socket and is backend-agnostic — it can't see whether nemotron, parakeet, or whisper is behind it. So pushing "send None, not "auto"" onto clients is the wrong layer. Today:

Backend client "auto" (before) client None
mlx_whisper ValueError: Unsupported language: autotranscript.failed ✅ auto-detect
parakeet ✅ ignored (language-pinned by model) ✅ ignored
nemotron ✅ valid prompt key → LID ✅ → DEFAULT_NEMOTRON_LANGUAGE="auto" → LID

Only Whisper breaks: mlx_whisper.transcribe's tokenizer accepts only real codes/names, and language=None is how Whisper itself requests auto-detection.

Change

Recast "auto"/blank → None in the whisper backend (_normalize_language), at the one layer that knows both its engine's idiom and that the backend is whisper. Real codes ("en", "es-ES") pass through unchanged.

Localized, not server-generic, on purpose: parakeet ignores language and nemotron treats "auto" as a first-class token (and already maps None → its "auto" default). A blanket server-level "auto"→None would couple the sentinel to nemotron's default — a later change to DEFAULT_NEMOTRON_LANGUAGE would silently change what "auto" means there. Translating per-backend avoids that.

Net effect: a uniform client "auto" (or None) means "auto-detect" on every backend, with no client-side branching.

Tests

Parametrized whisper backend cases: auto / AUTO / " auto " / "" / NoneNone; en / es-ES pass through. Three-way language-contract docstring in nemotron.py refreshed.

Full suite: 293 passed, 2 skipped; ruff format + ruff check clean.

Downstream note

This lets a language-configurable client (e.g. koda's STT_WS_LANGUAGE) send the literal "auto" and have it work uniformly — the client no longer needs to map its "auto" sentinel to omitting the field.

Release

This PR also bumps the version to 0.3.1 and adds the CHANGELOG [0.3.1] "Fixed" entry for this change (wheel METADATA verified PyPI-clean at 0.3.1). The git tag v0.3.1 + GitHub release are cut after merge.

vr000m added 4 commits June 6, 2026 11:46
Clients connect to a socket and don't know which backend is behind it, so a
uniform "auto" is the natural 'detect the language' request. But Whisper has
no "auto" token — mlx_whisper.transcribe(language="auto") raises ValueError
in its tokenizer, and language=None is how Whisper asks for auto-detect. Recast
"auto"/blank -> None in the whisper backend (the one layer that knows its
engine idiom and that the backend is whisper), rather than pushing the quirk
onto every backend-agnostic client.

Localized to the whisper backend on purpose: parakeet ignores language, and
nemotron accepts "auto" as a first-class prompt key (None already maps to its
"auto" default) — so a server-generic recast would needlessly couple the
sentinel to nemotron's default. Net effect: a uniform client "auto" (or None)
means auto-detect on all three backends.

Adds parametrized whisper tests (auto/AUTO/'  auto  '/''/None -> None; real
codes pass through); refreshes the three-way language contract docstring.
Full suite 293 passed, 2 skipped; ruff clean.
Post-ship follow-up note in the nemotron plan's workspace (below the review
marker, contract hash untouched): records that the three-way language contract
was refined by PR #8 — mlx_whisper now normalises 'auto'/blank to None before
forwarding (Whisper has no 'auto' token). CHANGELOG entry deferred to the next
patch release.
Address two Minor deep-review findings (discoverability, no behavior change):
- server.py: comment at the open_stream call naming the accepted language
  sentinels (None/'auto'/ISO code) and each backend's treatment, so a future
  backend author sees the contract at the call site.
- mlx_whisper.py: module docstring now states it recasts 'auto'/blank->None and
  points to nemotron.py's full three-way contract table.
Bump version 0.3.0 -> 0.3.1 and add the CHANGELOG [0.3.1] 'Fixed' entry for the
mlx_whisper 'auto'/blank -> None recast (PR #8). Footer link added; dev-plan
Findings note updated to record the fix shipped in 0.3.1. Wheel METADATA stays
PyPI-clean at 0.3.1 (no mlx-audio/direct-URL in Requires-Dist). Git tag v0.3.1
+ GitHub release are cut after merge.
@vr000m
vr000m merged commit fc93d6a into main Jun 6, 2026
4 checks passed
@vr000m
vr000m deleted the fix/whisper-auto-language branch June 6, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant