fix(vertex-ai): preserve nested speech locale and voice

This commit is contained in:
Emerson Gomes 2026-09-22 19:16:11 -05:00
parent 271f19822e
commit 2cd0639fd6
No known key found for this signature in database
GPG key ID: D3DF28AB5D1B5E17
2 changed files with 28 additions and 5 deletions

View file

@ -245,10 +245,13 @@ class VertexAITextToSpeechConfig(BaseTextToSpeechConfig, VertexBase):
self,
voice: dict, # mutable-ok: provider voice payload arrives as a concrete dictionary
) -> str | None:
voice_name: Final = self._get_str_value(voice, "name", "voiceName", "voice_name")
voice_name: Final = self._get_str_value(voice, "name", "voiceName", "voice_name", "voice")
if voice_name is not None:
return voice_name
speech_config: Final = self._get_dict_value(voice, "speechConfig", "speech_config") or voice
nested_voice_name: Final = self._get_str_value(speech_config, "name", "voiceName", "voice_name", "voice")
if nested_voice_name is not None:
return nested_voice_name
voice_config: Final = self._get_dict_value(speech_config, "voiceConfig", "voice_config")
if voice_config is None:
return None
@ -273,7 +276,12 @@ class VertexAITextToSpeechConfig(BaseTextToSpeechConfig, VertexBase):
"name": voice,
}
language_code: Final = self._get_str_value(voice, "languageCode", "language_code") or self.DEFAULT_LANGUAGE_CODE
speech_config: Final = self._get_dict_value(voice, "speechConfig", "speech_config") or voice
language_code: Final = (
self._get_str_value(voice, "languageCode", "language_code")
or self._get_str_value(speech_config, "languageCode", "language_code")
or self.DEFAULT_LANGUAGE_CODE
)
model_name: Final = model
speaker_configs: Final = self._extract_gemini_tts_speaker_configs(voice)
if speaker_configs:

View file

@ -190,6 +190,23 @@ class TestVertexAITextToSpeechConfig:
assert optional_params["audioEncoding"] == "LINEAR16"
assert optional_params["vertex_voice_dict"] == expected_voice
def test_gemini_tts_nested_language_and_voice_alias_reach_cloud_tts(self):
config: Final = VertexAITextToSpeechConfig()
voice: Final = {"speech_config": {"language_code": "fr-FR"}, "voice": "Kore"}
voice_name, optional_params = config.map_openai_params(
model="gemini-3.1-flash-tts-preview",
optional_params={"response_format": "mp3"},
voice=voice,
)
assert voice_name is None
assert optional_params["vertex_voice_dict"] == {
"languageCode": "fr-FR",
"modelName": "gemini-3.1-flash-tts-preview",
"name": "Kore",
}
@pytest.mark.parametrize(
"voice",
[
@ -481,9 +498,7 @@ class TestVertexAILyriaTextToSpeechConfig:
)
def test_get_complete_url_encodes_injected_predict_path_segments(self, monkeypatch: pytest.MonkeyPatch) -> None:
injected: Final = (
"victim-project/locations/us-central1/publishers/google/models/other-model:predict?ignored="
)
injected: Final = "victim-project/locations/us-central1/publishers/google/models/other-model:predict?ignored="
encoded: Final = (
"victim-project%2Flocations%2Fus-central1%2Fpublishers%2Fgoogle"
"%2Fmodels%2Fother-model%3Apredict%3Fignored%3D"