From a0d45ba516cd02fbc20ee5dbb6c1a647f604b259 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Fri, 18 Oct 2024 19:16:14 +0530 Subject: [PATCH] (feat) Support audio param in responses streaming (#6312) * add audio, modalities param * add test for gpt audio models * add get_supported_openai_params for GPT audio models * add supported params for audio * test_audio_output_from_model * bump openai to openai==1.52.0 * bump openai on pyproject * fix audio test * fix test mock_chat_response * handle audio for Message * fix handling audio for OAI compatible API endpoints * fix linting * fix mock dbrx test * add audio to Delta * handle model_response.choices.delta.audio * fix linting --- litellm/types/utils.py | 8 +++ litellm/utils.py | 10 +++ tests/llm_translation/dog.wav | Bin 31278 -> 31200 bytes tests/llm_translation/test_gpt4o_audio.py | 83 ++++++++++++++++------ 4 files changed, 81 insertions(+), 20 deletions(-) diff --git a/litellm/types/utils.py b/litellm/types/utils.py index fce45c336..1057ff2a5 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -451,12 +451,18 @@ class Delta(OpenAIObject): role=None, function_call=None, tool_calls=None, + audio: Optional[ChatCompletionAudioResponse] = None, **params, ): super(Delta, self).__init__(**params) self.content = content self.role = role + # Set default values and correct types + self.function_call: Optional[Union[FunctionCall, Any]] = None + self.tool_calls: Optional[List[Union[ChatCompletionDeltaToolCall, Any]]] = None + self.audio: Optional[ChatCompletionAudioResponse] = None + if function_call is not None and isinstance(function_call, dict): self.function_call = FunctionCall(**function_call) else: @@ -473,6 +479,8 @@ class Delta(OpenAIObject): else: self.tool_calls = tool_calls + self.audio = audio + def __contains__(self, key): # Define custom behavior for the 'in' operator return hasattr(self, key) diff --git a/litellm/utils.py b/litellm/utils.py index de7d528de..1b4864e39 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -7639,6 +7639,10 @@ class CustomStreamWrapper: ) ) model_response.choices[0].delta = Delta() + elif ( + delta is not None and getattr(delta, "audio", None) is not None + ): + model_response.choices[0].delta.audio = delta.audio else: try: delta = ( @@ -7805,6 +7809,12 @@ class CustomStreamWrapper: model_response.choices[0].delta["role"] = "assistant" self.sent_first_chunk = True return model_response + elif ( + len(model_response.choices) > 0 + and hasattr(model_response.choices[0].delta, "audio") + and model_response.choices[0].delta.audio is not None + ): + return model_response else: if hasattr(model_response, "usage"): self.chunks.append(model_response) diff --git a/tests/llm_translation/dog.wav b/tests/llm_translation/dog.wav index 4baa24f3da3f8b56398f8cfdc4babd04be9ed758..3ca0b533b5103267f26d33d5a543578462e553c8 100644 GIT binary patch literal 31200 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 E4?*R34gdfE literal 31278 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 S8g~tA`vzFuH;FcWR{cMM3itv5 diff --git a/tests/llm_translation/test_gpt4o_audio.py b/tests/llm_translation/test_gpt4o_audio.py index 16128c2fe..2eae06a44 100644 --- a/tests/llm_translation/test_gpt4o_audio.py +++ b/tests/llm_translation/test_gpt4o_audio.py @@ -15,40 +15,74 @@ from respx import MockRouter import litellm from litellm import Choices, Message, ModelResponse +from litellm.types.utils import StreamingChoices, ChatCompletionAudioResponse import base64 import requests +def check_non_streaming_response(completion): + assert completion.choices[0].message.audio is not None, "Audio response is missing" + assert isinstance( + completion.choices[0].message.audio, ChatCompletionAudioResponse + ), "Invalid audio response type" + assert len(completion.choices[0].message.audio.data) > 0, "Audio data is empty" + + +async def check_streaming_response(completion): + _audio_bytes = None + _audio_transcript = None + _audio_id = None + async for chunk in completion: + print(chunk) + _choice: StreamingChoices = chunk.choices[0] + if _choice.delta.audio is not None: + if _choice.delta.audio.get("data") is not None: + _audio_bytes = _choice.delta.audio["data"] + if _choice.delta.audio.get("transcript") is not None: + _audio_transcript = _choice.delta.audio["transcript"] + if _choice.delta.audio.get("id") is not None: + _audio_id = _choice.delta.audio["id"] + # Atleast one chunk should have set _audio_bytes, _audio_transcript, _audio_id + assert _audio_bytes is not None + assert _audio_transcript is not None + assert _audio_id is not None + + @pytest.mark.asyncio -@pytest.mark.flaky(retries=3, delay=1) -async def test_audio_output_from_model(): - litellm.set_verbose = True +# @pytest.mark.flaky(retries=3, delay=1) +@pytest.mark.parametrize("stream", [True, False]) +async def test_audio_output_from_model(stream): + audio_format = "pcm16" + if stream is False: + audio_format = "wav" + litellm.set_verbose = False completion = await litellm.acompletion( model="gpt-4o-audio-preview", modalities=["text", "audio"], - audio={"voice": "alloy", "format": "wav"}, + audio={"voice": "alloy", "format": "pcm16"}, messages=[{"role": "user", "content": "response in 1 word - yes or no"}], + stream=stream, ) - print("response= ", completion) + if stream is True: + await check_streaming_response(completion) - print(completion.choices[0]) - - assert completion.choices[0].message.audio is not None - assert isinstance( - completion.choices[0].message.audio, - litellm.types.utils.ChatCompletionAudioResponse, - ) - assert len(completion.choices[0].message.audio.data) > 0 - - wav_bytes = base64.b64decode(completion.choices[0].message.audio.data) - with open("dog.wav", "wb") as f: - f.write(wav_bytes) + else: + print("response= ", completion) + check_non_streaming_response(completion) + wav_bytes = base64.b64decode(completion.choices[0].message.audio.data) + with open("dog.wav", "wb") as f: + f.write(wav_bytes) @pytest.mark.asyncio -async def test_audio_input_to_model(): +@pytest.mark.parametrize("stream", [True, False]) +async def test_audio_input_to_model(stream): # Fetch the audio file and convert it to a base64 encoded string + audio_format = "pcm16" + if stream is False: + audio_format = "wav" + litellm.set_verbose = True url = "https://openaiassets.blob.core.windows.net/$web/API/docs/audio/alloy.wav" response = requests.get(url) response.raise_for_status() @@ -58,7 +92,8 @@ async def test_audio_input_to_model(): completion = await litellm.acompletion( model="gpt-4o-audio-preview", modalities=["text", "audio"], - audio={"voice": "alloy", "format": "wav"}, + audio={"voice": "alloy", "format": audio_format}, + stream=stream, messages=[ { "role": "user", @@ -73,4 +108,12 @@ async def test_audio_input_to_model(): ], ) - print(completion.choices[0].message) + if stream is True: + await check_streaming_response(completion) + else: + print("response= ", completion) + + check_non_streaming_response(completion) + wav_bytes = base64.b64decode(completion.choices[0].message.audio.data) + with open("dog.wav", "wb") as f: + f.write(wav_bytes)