mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(speech): forward the caching flag and drop malformed cache controls on Gemini and Vertex AI TTS
A non-bool caching or a cache dict with non-string keys is dropped instead of failing the speech call, so it behaves as it does today
This commit is contained in:
parent
fdc7648f43
commit
526a8889fd
4 changed files with 35 additions and 8 deletions
|
|
@ -2,7 +2,6 @@
|
||||||
Handler for transforming /chat/completions api requests to litellm.responses requests
|
Handler for transforming /chat/completions api requests to litellm.responses requests
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections.abc import Mapping
|
|
||||||
from typing import TYPE_CHECKING, Final
|
from typing import TYPE_CHECKING, Final
|
||||||
|
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict
|
||||||
|
|
@ -14,6 +13,7 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
from litellm import LiteLLMLoggingObj
|
from litellm import LiteLLMLoggingObj
|
||||||
from litellm.types.llms.openai import HttpxBinaryResponseContent
|
from litellm.types.llms.openai import HttpxBinaryResponseContent
|
||||||
|
from litellm.types.utils import CacheControlsHint
|
||||||
|
|
||||||
|
|
||||||
class SpeechToCompletionBridgeHandlerInputKwargs(TypedDict):
|
class SpeechToCompletionBridgeHandlerInputKwargs(TypedDict):
|
||||||
|
|
@ -92,7 +92,7 @@ class SpeechToCompletionBridgeHandler:
|
||||||
custom_llm_provider: str,
|
custom_llm_provider: str,
|
||||||
api_base: str | None,
|
api_base: str | None,
|
||||||
timeout: "float | httpx.Timeout | None",
|
timeout: "float | httpx.Timeout | None",
|
||||||
cache: Mapping[str, object] | None,
|
cache_controls: "CacheControlsHint",
|
||||||
) -> "HttpxBinaryResponseContent":
|
) -> "HttpxBinaryResponseContent":
|
||||||
received_args: Final = locals()
|
received_args: Final = locals()
|
||||||
from litellm import completion
|
from litellm import completion
|
||||||
|
|
@ -112,7 +112,7 @@ class SpeechToCompletionBridgeHandler:
|
||||||
model=model,
|
model=model,
|
||||||
input=input,
|
input=input,
|
||||||
optional_params=optional_params,
|
optional_params=optional_params,
|
||||||
litellm_params={**litellm_params, "api_base": api_base, "timeout": timeout, "cache": cache},
|
litellm_params={**litellm_params, "api_base": api_base, "timeout": timeout, **cache_controls},
|
||||||
headers=headers,
|
headers=headers,
|
||||||
litellm_logging_obj=logging_obj,
|
litellm_logging_obj=logging_obj,
|
||||||
custom_llm_provider=custom_llm_provider,
|
custom_llm_provider=custom_llm_provider,
|
||||||
|
|
|
||||||
|
|
@ -8941,7 +8941,7 @@ def speech(
|
||||||
custom_llm_provider=custom_llm_provider,
|
custom_llm_provider=custom_llm_provider,
|
||||||
api_base=api_base,
|
api_base=api_base,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
cache=_CACHE_CONTROLS_HINT.validate_python(kwargs).get("cache"),
|
cache_controls=_CACHE_CONTROLS_HINT.validate_python(kwargs),
|
||||||
)
|
)
|
||||||
|
|
||||||
# Vertex AI Text-to-Speech (Google Cloud TTS)
|
# Vertex AI Text-to-Speech (Google Cloud TTS)
|
||||||
|
|
@ -8995,7 +8995,7 @@ def speech(
|
||||||
custom_llm_provider=custom_llm_provider,
|
custom_llm_provider=custom_llm_provider,
|
||||||
api_base=api_base,
|
api_base=api_base,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
cache=_CACHE_CONTROLS_HINT.validate_python(kwargs).get("cache"),
|
cache_controls=_CACHE_CONTROLS_HINT.validate_python(kwargs),
|
||||||
)
|
)
|
||||||
elif custom_llm_provider == "runwayml":
|
elif custom_llm_provider == "runwayml":
|
||||||
from litellm.llms.runwayml.text_to_speech.transformation import (
|
from litellm.llms.runwayml.text_to_speech.transformation import (
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,10 @@ from pydantic import (
|
||||||
FieldSerializationInfo,
|
FieldSerializationInfo,
|
||||||
GetCoreSchemaHandler,
|
GetCoreSchemaHandler,
|
||||||
JsonValue,
|
JsonValue,
|
||||||
|
OnErrorOmit,
|
||||||
PrivateAttr,
|
PrivateAttr,
|
||||||
SkipValidation,
|
SkipValidation,
|
||||||
|
StrictBool,
|
||||||
field_serializer,
|
field_serializer,
|
||||||
field_validator,
|
field_validator,
|
||||||
)
|
)
|
||||||
|
|
@ -5020,4 +5022,5 @@ class BaseUrlRoutingHint(TypedDict, total=False):
|
||||||
|
|
||||||
|
|
||||||
class CacheControlsHint(TypedDict, total=False):
|
class CacheControlsHint(TypedDict, total=False):
|
||||||
cache: ReadOnly[Mapping[str, object] | None]
|
cache: ReadOnly[OnErrorOmit[Mapping[str, object] | None]]
|
||||||
|
caching: ReadOnly[OnErrorOmit[StrictBool | None]]
|
||||||
|
|
|
||||||
|
|
@ -5521,13 +5521,14 @@ def test_speech_gemini_tts_without_a_timeout_waits_as_long_as_the_same_chat_comp
|
||||||
({}, {}, 1),
|
({}, {}, 1),
|
||||||
({}, {"cache": {"no-cache": True}}, 2),
|
({}, {"cache": {"no-cache": True}}, 2),
|
||||||
({"cache": {"no-store": True}}, {}, 2),
|
({"cache": {"no-store": True}}, {}, 2),
|
||||||
|
({}, {"caching": False}, 2),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_speech_gemini_tts_honors_the_request_cache_controls(
|
def test_speech_gemini_tts_honors_the_request_cache_controls(
|
||||||
respx_mock: respx.MockRouter,
|
respx_mock: respx.MockRouter,
|
||||||
monkeypatch: pytest.MonkeyPatch,
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
first_controls: Mapping[str, Mapping[str, bool]],
|
first_controls: Mapping[str, object],
|
||||||
second_controls: Mapping[str, Mapping[str, bool]],
|
second_controls: Mapping[str, object],
|
||||||
expected_upstream_calls: int,
|
expected_upstream_calls: int,
|
||||||
):
|
):
|
||||||
monkeypatch.setattr(litellm, "cache", Cache(type="local"))
|
monkeypatch.setattr(litellm, "cache", Cache(type="local"))
|
||||||
|
|
@ -5547,6 +5548,29 @@ def test_speech_gemini_tts_honors_the_request_cache_controls(
|
||||||
assert route.call_count == expected_upstream_calls
|
assert route.call_count == expected_upstream_calls
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("malformed_controls", [{"caching": "yes"}, {"caching": 1}, {"cache": {1: True}}])
|
||||||
|
def test_speech_gemini_tts_without_a_cache_ignores_malformed_cache_controls(
|
||||||
|
respx_mock: respx.MockRouter,
|
||||||
|
monkeypatch: pytest.MonkeyPatch,
|
||||||
|
malformed_controls: Mapping[str, object],
|
||||||
|
):
|
||||||
|
monkeypatch.setattr(litellm, "cache", None)
|
||||||
|
route: Final = respx_mock.post(url__regex=GEMINI_DEFAULT_GENERATE_CONTENT_URL).mock(
|
||||||
|
return_value=httpx.Response(200, json=_gemini_tts_generate_content_response())
|
||||||
|
)
|
||||||
|
|
||||||
|
response: Final = litellm.speech(
|
||||||
|
model=f"gemini/{GEMINI_TTS_MODEL}",
|
||||||
|
input="hello",
|
||||||
|
voice="Kore",
|
||||||
|
api_key="fake-gemini-key",
|
||||||
|
**malformed_controls,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert route.call_count == 1
|
||||||
|
assert response.content.startswith(b"RIFF")
|
||||||
|
|
||||||
|
|
||||||
FOUNDRY_HOST: Final = "https://my-project.services.ai.azure.com"
|
FOUNDRY_HOST: Final = "https://my-project.services.ai.azure.com"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue