mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-27 06:13:07 +00:00
fix(aws_polly): read the engine from the bare model name (#47963)
* fix(aws_polly): read the engine from the bare model name speech() strips the aws_polly/ prefix before AWSPollyTextToSpeechConfig sees the model, so _extract_engine_from_model got a bare "standard", found no slash and returned the neural default. Every Polly request went out with Engine: neural whatever the model named. Take the last path segment instead, which covers both the bare name and the prefixed one. * test(aws_polly): move imports to the top of the file * docs(aws_polly): update the engine comment to the bare model name
This commit is contained in:
parent
9fab92672a
commit
428c9f6bf3
3 changed files with 58 additions and 11 deletions
|
|
@ -178,7 +178,7 @@ class AWSPollyTextToSpeechConfig(BaseTextToSpeechConfig, BaseAWSLLM):
|
|||
else:
|
||||
mapped_params["output_format"] = self.DEFAULT_OUTPUT_FORMAT
|
||||
|
||||
# Extract engine from model name (e.g., "aws_polly/neural" -> "neural")
|
||||
# model arrives without the "aws_polly/" prefix, e.g. "standard"
|
||||
engine: Final = self._extract_engine_from_model(model)
|
||||
mapped_params["engine"] = engine
|
||||
|
||||
|
|
@ -196,18 +196,17 @@ class AWSPollyTextToSpeechConfig(BaseTextToSpeechConfig, BaseAWSLLM):
|
|||
"""
|
||||
Extract engine from model name.
|
||||
|
||||
speech() strips the "aws_polly/" prefix before the config is called,
|
||||
so the bare engine name is what normally arrives here.
|
||||
|
||||
Examples:
|
||||
- aws_polly/neural -> neural
|
||||
- aws_polly/standard -> standard
|
||||
- standard -> standard
|
||||
- aws_polly/long-form -> long-form
|
||||
- aws_polly -> neural (default)
|
||||
"""
|
||||
if "/" in model:
|
||||
parts: Final = model.split("/")
|
||||
if len(parts) >= 2:
|
||||
engine: Final = parts[1].lower()
|
||||
if engine in self.VALID_ENGINES:
|
||||
return engine
|
||||
engine: Final = model.rsplit("/", 1)[-1].lower()
|
||||
if engine in self.VALID_ENGINES:
|
||||
return engine
|
||||
return self.DEFAULT_ENGINE
|
||||
|
||||
def validate_environment(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
import litellm
|
||||
import json
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import litellm
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -134,6 +138,34 @@ async def test_aws_polly_tts_with_native_voice():
|
|||
assert request_body.get("TextType", "text") == "text"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("fake_provider_credentials")
|
||||
@pytest.mark.parametrize("engine", ["standard", "neural", "long-form", "generative"])
|
||||
async def test_aws_polly_tts_sends_engine_from_model(engine: str) -> None:
|
||||
"""
|
||||
The engine in the model name must reach Polly. speech() strips the
|
||||
provider prefix before the config reads it, which used to turn every
|
||||
engine into the neural default.
|
||||
"""
|
||||
mock_httpx_response = MagicMock(spec=httpx.Response)
|
||||
mock_httpx_response.content = b"fake_audio_data"
|
||||
mock_httpx_response.status_code = 200
|
||||
mock_httpx_response.headers = {"content-type": "audio/mpeg"}
|
||||
|
||||
with patch("litellm.llms.custom_httpx.http_handler.AsyncHTTPHandler.post") as mock_post:
|
||||
mock_post.return_value = mock_httpx_response
|
||||
|
||||
await litellm.aspeech(
|
||||
model=f"aws_polly/{engine}",
|
||||
voice="Joanna",
|
||||
input="Hello",
|
||||
aws_region_name="us-east-1",
|
||||
)
|
||||
|
||||
request_body = json.loads(mock_post.call_args.kwargs["data"])
|
||||
assert request_body["Engine"] == engine
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.usefixtures("fake_provider_credentials")
|
||||
async def test_aws_polly_tts_with_openai_voice_mapping():
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import json
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
|
||||
from litellm.llms.aws_polly.text_to_speech.transformation import AWSPollyTextToSpeechConfig
|
||||
|
||||
|
||||
|
|
@ -17,3 +19,17 @@ def test_installed_botocore_signs_the_speech_request() -> None:
|
|||
authorization: Final = headers["Authorization"]
|
||||
assert "/us-west-2/polly/aws4_request" in authorization
|
||||
assert json.loads(body) == {"Text": "ping", "VoiceId": "Joanna"}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("model", "expected"),
|
||||
[
|
||||
("standard", "standard"),
|
||||
("Long-Form", "long-form"),
|
||||
("aws_polly/generative", "generative"),
|
||||
("aws_polly", "neural"),
|
||||
("unknown", "neural"),
|
||||
],
|
||||
)
|
||||
def test_extract_engine_from_model(model: str, expected: str) -> None:
|
||||
assert AWSPollyTextToSpeechConfig()._extract_engine_from_model(model) == expected
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue