mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-28 06:23:07 +00:00
fix(speech): keep the provider key first but skip local-inference placeholders
Trying the provider key last let OPENAI_API_KEY or AZURE_API_KEY go to a hosted_vllm, deepinfra or azure_ai endpoint whose own key was configured, which leaks the global credential and still fails the reported setup. The provider key goes first again, matching completion() and transcription(), and the fake-api-key / dummy-key placeholders get_llm_provider returns for local-inference providers are skipped there, so a real OPENAI_API_KEY still wins over them
This commit is contained in:
parent
feef600f64
commit
d30be01aca
3 changed files with 28 additions and 8 deletions
|
|
@ -342,6 +342,7 @@ DEFAULT_REASONING_EFFORT_MINIMAL_THINKING_BUDGET: Final = get_env_int(
|
|||
# Provider-specific API base URLs
|
||||
XAI_API_BASE: Final = "https://api.x.ai/v1"
|
||||
PLACEHOLDER_API_KEY: Final = "fake-api-key"
|
||||
PLACEHOLDER_API_KEYS: Final = frozenset({PLACEHOLDER_API_KEY, "dummy-key"})
|
||||
OPEN_SANDBOX_API_BASE_ENV_VAR: Final = "OPEN_SANDBOX_API_BASE"
|
||||
OPEN_SANDBOX_API_KEY_ENV_VAR: Final = "OPEN_SANDBOX_API_KEY"
|
||||
OPEN_SANDBOX_DEFAULT_TEMPLATE: Final = "opensandbox/code-interpreter:v1.1.0"
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ from litellm.constants import (
|
|||
DEFAULT_MOCK_RESPONSE_PROMPT_TOKEN_COUNT,
|
||||
NADIR_DEFAULT_API_BASE,
|
||||
OPENAI_AUDIO_TRANSCRIPTION_PROVIDERS,
|
||||
PLACEHOLDER_API_KEYS,
|
||||
)
|
||||
from litellm.exceptions import LiteLLMUnknownProvider
|
||||
from litellm.integrations.custom_logger import CustomLogger
|
||||
|
|
@ -8588,6 +8589,7 @@ def speech(
|
|||
model, custom_llm_provider, dynamic_api_key, api_base = get_llm_provider(
|
||||
model=model, custom_llm_provider=custom_llm_provider, api_base=api_base or base_url
|
||||
)
|
||||
provider_api_key: Final = None if dynamic_api_key in PLACEHOLDER_API_KEYS else dynamic_api_key
|
||||
kwargs.pop("tags", [])
|
||||
|
||||
optional_params = {}
|
||||
|
|
@ -8677,10 +8679,11 @@ def speech(
|
|||
# set API KEY
|
||||
api_key = (
|
||||
api_key
|
||||
or provider_api_key # for deepinfra/perplexity/anyscale we check in get_llm_provider and pass in the api key from there
|
||||
or litellm.api_key
|
||||
or litellm.openai_key
|
||||
or get_secret("OPENAI_API_KEY")
|
||||
or dynamic_api_key # for deepinfra/perplexity/anyscale we check in get_llm_provider and pass in the api key from there
|
||||
or dynamic_api_key
|
||||
)
|
||||
|
||||
organization = (
|
||||
|
|
@ -8763,11 +8766,11 @@ def speech(
|
|||
|
||||
api_key = (
|
||||
api_key
|
||||
or provider_api_key
|
||||
or litellm.api_key
|
||||
or litellm.azure_key
|
||||
or get_secret("AZURE_OPENAI_API_KEY")
|
||||
or get_secret("AZURE_API_KEY")
|
||||
or dynamic_api_key
|
||||
)
|
||||
|
||||
azure_ad_token: Final[str | None] = optional_params.get("extra_body", {}).pop(
|
||||
|
|
|
|||
|
|
@ -5011,13 +5011,13 @@ def _set_or_clear_env(monkeypatch: pytest.MonkeyPatch, values: dict[str, str | N
|
|||
("provider_key", "openai_key", "sent_authorization"),
|
||||
[
|
||||
("hosted-vllm-scoped-key", None, "Bearer hosted-vllm-scoped-key"),
|
||||
("hosted-vllm-scoped-key", "generic-openai-key", "Bearer generic-openai-key"),
|
||||
("hosted-vllm-scoped-key", "generic-openai-key", "Bearer hosted-vllm-scoped-key"),
|
||||
(None, "generic-openai-key", "Bearer generic-openai-key"),
|
||||
(None, None, "Bearer fake-api-key"),
|
||||
],
|
||||
ids=["provider-key-alone", "generic-key-still-wins", "generic-key-beats-placeholder", "placeholder-when-unset"],
|
||||
ids=["provider-key-alone", "provider-key-beats-generic", "generic-key-beats-placeholder", "placeholder-when-unset"],
|
||||
)
|
||||
def test_speech_openai_compatible_falls_back_to_the_provider_scoped_key(
|
||||
def test_speech_openai_compatible_sends_the_provider_scoped_key(
|
||||
respx_mock: respx.MockRouter,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
provider_key: str | None,
|
||||
|
|
@ -5041,10 +5041,10 @@ def test_speech_openai_compatible_falls_back_to_the_provider_scoped_key(
|
|||
|
||||
@pytest.mark.parametrize(
|
||||
("generic_azure_key", "sent_api_key"),
|
||||
[(None, "azure-ai-scoped-key"), ("generic-azure-key", "generic-azure-key")],
|
||||
ids=["provider-key-alone", "generic-key-still-wins"],
|
||||
[(None, "azure-ai-scoped-key"), ("generic-azure-key", "azure-ai-scoped-key")],
|
||||
ids=["provider-key-alone", "provider-key-beats-generic"],
|
||||
)
|
||||
def test_speech_azure_falls_back_to_the_provider_scoped_key(
|
||||
def test_speech_azure_sends_the_provider_scoped_key(
|
||||
respx_mock: respx.MockRouter, monkeypatch: pytest.MonkeyPatch, generic_azure_key: str | None, sent_api_key: str
|
||||
):
|
||||
_clear_global_tts_keys(monkeypatch)
|
||||
|
|
@ -5069,6 +5069,22 @@ def test_speech_azure_falls_back_to_the_provider_scoped_key(
|
|||
assert route.calls.last.request.headers["api-key"] == sent_api_key
|
||||
|
||||
|
||||
def test_speech_docker_model_runner_placeholder_does_not_beat_a_real_key(
|
||||
respx_mock: respx.MockRouter, monkeypatch: pytest.MonkeyPatch
|
||||
):
|
||||
_clear_global_tts_keys(monkeypatch)
|
||||
_set_or_clear_env(monkeypatch, {"DOCKER_MODEL_RUNNER_API_KEY": None, "OPENAI_API_KEY": "generic-openai-key"})
|
||||
route: Final = respx_mock.post("https://dmr.internal/v1/audio/speech").mock(
|
||||
return_value=httpx.Response(200, content=TTS_AUDIO, headers={"content-type": "audio/mpeg"})
|
||||
)
|
||||
|
||||
litellm.speech(
|
||||
model="docker_model_runner/tts-1", input="which key goes out", voice="alloy", api_base="https://dmr.internal/v1"
|
||||
)
|
||||
|
||||
assert route.calls.last.request.headers["authorization"] == "Bearer generic-openai-key"
|
||||
|
||||
|
||||
def test_speech_keeps_an_explicitly_passed_api_key_over_the_provider_scoped_one(
|
||||
respx_mock: respx.MockRouter, monkeypatch: pytest.MonkeyPatch
|
||||
):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue