Skip to content

Send the picked target language to OmniVoice (CrispASR) - #13337

Merged
niksedk merged 1 commit into
mainfrom
fix/13273-omnivoice-crispasr-language
Aug 7, 2026
Merged

Send the picked target language to OmniVoice (CrispASR)#13337
niksedk merged 1 commit into
mainfrom
fix/13273-omnivoice-crispasr-language

Conversation

@niksedk

@niksedk niksedk commented Aug 7, 2026

Copy link
Copy Markdown
Member

Fixes the SE half of #13273.

The engine advertised HasLanguageParameter and offered all 646 of the model's languages, but Speak() took the TtsLanguage and never put it on the request — the payload was only {input, response_format, speed}. As reported, the menu was decoration.

It has to be a payload field rather than a startup flag: SE keeps one crispasr server for the whole session, so a launch argument could never follow a combo change after the first line. The other cloning CrispASR engines already send it this way.

The default had to be fixed first

Adding the field alone would have made things worse. The view model had no arm for this engine, so it fell through to the first entry of an alphabetical list — "Abadi" (kbt), a real ISO 639-3 id the model would happily condition on — and the pick was never persisted.

So OmniVoiceLanguages.All now leads with "Auto" (empty code → no field → language-agnostic, i.e. the pre-existing behaviour), with the 646 generated entries kept in a private Catalog so they can still be regenerated wholesale. Both the main TTS window and the review window restore the saved pick — they had drifted apart, review already defaulting to English while the main window defaulted to Abadi — and a new OmniVoiceCrispAsrLanguage setting stores it.

Two things beyond the report

  • ResolveLanguageArg(null) falls back to the saved pick. The cast dialog's voice-test button and every cross-engine cast row pass null on purpose ("engines fall back to their own saved defaults") — the same hole CosyVoice3 had in CosyVoice-TTS - The target language is not assigned during cloning. #13272.
  • Values that are not the model's own ids are dropped rather than sent. crispasr falls back to language-agnostic on those anyway, but a locale code like de-DE or a leftover language object from another engine has no business on the wire.

Note on the ids

They are ISO 639-3 individual languages, so there is no ar — Arabic is arb (Standard), arz (Egyptian), ary (Moroccan) and ~20 more. That is the model's vocabulary, not a gap in the list; asserted in tests so it does not get "fixed" later by inventing an id the model has never seen.

Requires a CrispASR bump to take effect

On the pinned v0.8.25 the CLI adapter applies the language only at startup, so the field is parsed and ignored on every request. The fixes — per-request apply, the session C-ABI arm, and running _resolve_language() on the id — are on CrispASR main and in no release yet.

Sending it on v0.8.25 is harmless (SE only ever puts the model's own ids on the wire) and it goes live the moment CrispAsrDownloadService is bumped past v0.8.25 — the same bump CosyVoice3 cross-lingual (#13272) is waiting on. Flagged in the class docs so nobody debugs it as broken in the meantime.

Not fixed here

The other half of #13273 — the reference accent — is a separate, structural problem. OmniVoice has no cross-lingual mode: the reference transcript sits before the reference audio in a single token stream, so it cannot be dropped the way CosyVoice3 does. Cloning an English speaker onto German text may still sound English however the tag is set. Thanks to @CrispStrobe for the detailed backend analysis and for not overclaiming that part.

Testing

Full UI suite: 1599 passed, 0 failed. New coverage for the Auto-leads invariant, the null/Auto/unknown resolution paths, and the absent-ar case.

🤖 Generated with Claude Code

The engine advertised HasLanguageParameter and offered all 646 of the
model's languages, but Speak() took the TtsLanguage and never put it on
the request - the payload was only {input, response_format, speed}. The
combo was decoration (#13273).

It has to be a payload field rather than a startup flag: SE keeps one
crispasr server for the whole session, so a launch argument could never
follow a combo change after the first line. The other cloning CrispASR
engines already send it this way.

Wiring it up needed a default first. The view model had no arm for this
engine, so it fell through to the first entry of an alphabetical list -
"Abadi", a real ISO 639-3 id the model would happily condition on - and
the pick was never persisted. So the list now leads with "Auto" (send no
field, stay language-agnostic, i.e. today's behaviour), both the main and
review windows restore the saved pick, and OmniVoiceCrispAsrLanguage
stores it.

Values that are not the model's own ids are dropped rather than sent.
crispasr falls back to language-agnostic on those anyway, but a locale
code like "de-DE" or a leftover language object from another engine has
no business on the wire.

Note the ids are ISO 639-3 individual languages, so there is no "ar" -
Arabic is arb/arz/ary and ~20 more. That is the model's vocabulary, not a
gap; asserted in tests so it does not get "fixed" later.

Honouring the field per request needs a crispasr build newer than the
pinned v0.8.25, where the adapter applies the language only at startup.
Sending it there is harmless and it goes live on the pin bump - the same
bump CosyVoice3 cross-lingual (#13272) is waiting on.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@niksedk
niksedk merged commit a5fa6ed into main Aug 7, 2026
1 check passed
@niksedk
niksedk deleted the fix/13273-omnivoice-crispasr-language branch August 7, 2026 13:48
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