Skip to content

TTS: Normalize language for Google #1314

Open

Description

@AkhileshNegi

Describe the bug

TTS requests with config.blob.completion.provider = "google-native" skip language
normalization, so a language name like "hindi" reaches Gemini unchanged and the call fails:

[GEMINI] Bad request (code: 400): Invalid language 'hindi' in speech_config.
Provide a valid BCP-47 language code (e.g., 'en-US').

The two providers diverge here:

  • provider: "google" validates params through TTSLLMParams
    (backend/app/models/llm/request.py:155). Its normalize_language_casing validator calls
    normalize_bcp47_language() (backend/app/models/llm/constants.py:160), mapping
    "hindi" -> "hi-IN" before map_kaapi_to_google_params forwards it.
  • provider: "google-native" is parsed as NativeCompletionConfig
    (backend/app/models/llm/request.py:333), whose params is a pass-through
    dict[str, Any]. No validator runs, so GoogleAIProvider sets
    speech_config["language"] = language verbatim
    (backend/app/services/llm/providers/google_aistudio.py:364-365).

Impact: 635 jobs failed this way in the period reviewed (451 + 184 across two Gemini error
formats) — the largest single source of failures. Each fails in about a second, so these are not
timeouts. STT is unaffected; it defaults to "auto".

The callers are Glific flows whose text_to_speech node sets provider to google-native:
Glific's tts_payload/4 defaults language to "hindi" when the node leaves the field empty.
NGOs are currently told to switch the node to provider: "google" (see glific/glific#6057,
closed with that workaround). This ticket fixes google-native itself rather than waiting for it
to be deprecated.

Expected behavior

google-native TTS accepts the same language inputs as google — language name, bare ISO 639
code, or BCP-47 tag in any casing — and normalizes to the canonical tag before calling Gemini.
Canonical values (hi-IN) pass through unchanged; unrecognized values also pass through, so the
provider still rejects them.

Steps to reproduce

  1. POST an LLM call with config.blob.completion = { provider: "google-native", type: "tts", params: { model: "gemini-2.5-flash-preview-tts", voice: "Leda", language: "hindi", response_format: "mp3" } }.
  2. The job fails with the Gemini 400 above, in about a second.
  3. Repeat with provider: "google" and identical params — it succeeds, because "hindi" is
    normalized to "hi-IN".

Proposed fix

Call normalize_bcp47_language() on the native Google STT/TTS path, where language /
input_language / output_language are read from generation_params
(google_aistudio.py:206-207, :347), so the native and mapped flows share one normalization
point. The function returns unrecognized input unchanged, so this does not widen what the
provider accepts.

Activity

  1. changed the title [-]LLM Call: Normalize TTS language to BCP-47 on google-native path[/-] [+]TTS: Normalize language for Google[/+] on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions