diff --git a/litellm/llms/deepgram/audio_transcription/transformation.py b/litellm/llms/deepgram/audio_transcription/transformation.py index 0cdfd734de7..faa68e97eae 100644 --- a/litellm/llms/deepgram/audio_transcription/transformation.py +++ b/litellm/llms/deepgram/audio_transcription/transformation.py @@ -58,7 +58,7 @@ class DeepgramAudioTranscriptionConfig(BaseAudioTranscriptionConfig): ) -> AudioTranscriptionRequestData: """ Processes the audio file input based on its type and returns AudioTranscriptionRequestData. - + For Deepgram, the binary audio data is sent directly as the request body. Args: @@ -69,12 +69,11 @@ class DeepgramAudioTranscriptionConfig(BaseAudioTranscriptionConfig): """ # Use common utility to process the audio file processed_audio = process_audio_file(audio_file) - + # Return structured data with binary content and no files # For Deepgram, we send binary data directly as request body return AudioTranscriptionRequestData( - data=processed_audio.file_content, - files=None + data=processed_audio.file_content, files=None ) def transform_audio_transcription_response( @@ -99,9 +98,11 @@ class DeepgramAudioTranscriptionConfig(BaseAudioTranscriptionConfig): # Add additional metadata matching OpenAI format response["task"] = "transcribe" - response["language"] = ( - "english" # Deepgram auto-detects but doesn't return language - ) + + # Use detected_language if available, otherwise default to "en" + detected_language = first_channel.get("detected_language") + response["language"] = detected_language if detected_language else "en" + response["duration"] = response_json["metadata"]["duration"] # Transform words to match OpenAI format @@ -150,7 +151,6 @@ class DeepgramAudioTranscriptionConfig(BaseAudioTranscriptionConfig): return url - def _format_param_value(self, value) -> str: """ Formats a parameter value for use in query string. @@ -180,7 +180,7 @@ class DeepgramAudioTranscriptionConfig(BaseAudioTranscriptionConfig): provider_specific_params = self.get_provider_specific_params( optional_params=optional_params, model=model, - openai_params=self.get_supported_openai_params(model) + openai_params=self.get_supported_openai_params(model), ) for key, value in provider_specific_params.items(): diff --git a/tests/test_litellm/llms/deepgram/audio_transcription/test_deepgram_audio_transcription_transformation.py b/tests/test_litellm/llms/deepgram/audio_transcription/test_deepgram_audio_transcription_transformation.py index 5ca94dd93fa..6a0f4f8fa33 100644 --- a/tests/test_litellm/llms/deepgram/audio_transcription/test_deepgram_audio_transcription_transformation.py +++ b/tests/test_litellm/llms/deepgram/audio_transcription/test_deepgram_audio_transcription_transformation.py @@ -58,13 +58,13 @@ def test_audio_file_handling(fixture_name, request): optional_params={}, litellm_params={}, ) - + # Check that result is AudioTranscriptionRequestData assert isinstance(result, AudioTranscriptionRequestData) - + # Check that data matches expected output assert result.data == expected_output - + # Check that files is None for Deepgram (binary data) assert result.files is None @@ -202,3 +202,39 @@ def test_get_complete_url_with_string_values(): assert "version=latest" in url assert "punctuate=true" in url assert url.startswith("https://api.deepgram.com/v1/listen?") + + +def test_get_complete_url_with_detect_language(): + """Test URL generation with detect_language parameter""" + handler = DeepgramAudioTranscriptionConfig() + url = handler.get_complete_url( + api_base=None, + api_key=None, + model="nova-2", + optional_params={"detect_language": True}, + litellm_params={}, + ) + expected_url = "https://api.deepgram.com/v1/listen?model=nova-2&detect_language=true" + assert url == expected_url + + +def test_get_complete_url_with_detect_language_and_other_params(): + """Test URL generation with detect_language and other parameters""" + handler = DeepgramAudioTranscriptionConfig() + url = handler.get_complete_url( + api_base=None, + api_key=None, + model="nova-2", + optional_params={ + "detect_language": True, + "punctuate": True, + "diarize": False, + }, + litellm_params={}, + ) + # URL should contain all parameters + assert "model=nova-2" in url + assert "detect_language=true" in url + assert "punctuate=true" in url + assert "diarize=false" in url + assert url.startswith("https://api.deepgram.com/v1/listen?") diff --git a/tests/test_litellm/llms/deepgram/test_deepgram_mock_transcription.py b/tests/test_litellm/llms/deepgram/test_deepgram_mock_transcription.py index 27a05199c93..a173441e498 100644 --- a/tests/test_litellm/llms/deepgram/test_deepgram_mock_transcription.py +++ b/tests/test_litellm/llms/deepgram/test_deepgram_mock_transcription.py @@ -277,3 +277,157 @@ class TestDeepgramMockTranscription: # Verify response assert response.text == "Hello, this is a test transcription." + + def test_transcription_response_with_detected_language(self, test_audio_bytes): + """Test response transformation when detected_language is present""" + # Mock response with detected_language + mock_response_data = { + "metadata": { + "transaction_key": "deprecated", + "request_id": "test-request-id", + "sha256": "test-sha", + "created": "2024-01-01T00:00:00.000Z", + "duration": 1.2, + "channels": 1, + "models": ["nova-2"], + }, + "results": { + "channels": [ + { + "detected_language": "fr", + "alternatives": [ + { + "transcript": "Bonjour le monde", + "confidence": 0.99, + "words": [ + {"word": "Bonjour", "start": 0.0, "end": 0.5, "confidence": 0.99}, + {"word": "le", "start": 0.5, "end": 0.7, "confidence": 0.98}, + {"word": "monde", "start": 0.7, "end": 1.2, "confidence": 0.97}, + ] + } + ] + } + ] + }, + } + + mock_response = MagicMock() + mock_response.json.return_value = mock_response_data + mock_response.status_code = 200 + mock_response.headers = {"Content-Type": "application/json"} + + with patch( + "litellm.llms.custom_httpx.http_handler.HTTPHandler.post", + return_value=mock_response, + ): + response: TranscriptionResponse = litellm.transcription( + model="deepgram/nova-2", + file=test_audio_bytes, + api_key="test-api-key", + detect_language=True, + ) + + # Verify that detected_language is used + assert response["language"] == "fr" + assert response.text == "Bonjour le monde" + assert response["task"] == "transcribe" + assert response["duration"] == 1.2 + assert len(response["words"]) == 3 + + def test_transcription_response_without_detected_language(self, test_audio_bytes): + """Test response transformation when detected_language is not present""" + # Mock response without detected_language + mock_response_data = { + "metadata": { + "transaction_key": "deprecated", + "request_id": "test-request-id", + "sha256": "test-sha", + "created": "2024-01-01T00:00:00.000Z", + "duration": 0.8, + "channels": 1, + "models": ["nova-2"], + }, + "results": { + "channels": [ + { + "alternatives": [ + { + "transcript": "Hello world", + "confidence": 0.99, + } + ] + } + ] + }, + } + + mock_response = MagicMock() + mock_response.json.return_value = mock_response_data + mock_response.status_code = 200 + mock_response.headers = {"Content-Type": "application/json"} + + with patch( + "litellm.llms.custom_httpx.http_handler.HTTPHandler.post", + return_value=mock_response, + ): + response: TranscriptionResponse = litellm.transcription( + model="deepgram/nova-2", + file=test_audio_bytes, + api_key="test-api-key", + ) + + # Verify that default language "en" is used + assert response["language"] == "en" + assert response.text == "Hello world" + assert response["task"] == "transcribe" + assert response["duration"] == 0.8 + + def test_transcription_response_with_empty_detected_language(self, test_audio_bytes): + """Test response transformation when detected_language is present but None""" + # Mock response with None detected_language + mock_response_data = { + "metadata": { + "transaction_key": "deprecated", + "request_id": "test-request-id", + "sha256": "test-sha", + "created": "2024-01-01T00:00:00.000Z", + "duration": 1.0, + "channels": 1, + "models": ["nova-2"], + }, + "results": { + "channels": [ + { + "detected_language": None, + "alternatives": [ + { + "transcript": "Test transcript", + "confidence": 0.99, + } + ] + } + ] + }, + } + + mock_response = MagicMock() + mock_response.json.return_value = mock_response_data + mock_response.status_code = 200 + mock_response.headers = {"Content-Type": "application/json"} + + with patch( + "litellm.llms.custom_httpx.http_handler.HTTPHandler.post", + return_value=mock_response, + ): + response: TranscriptionResponse = litellm.transcription( + model="deepgram/nova-2", + file=test_audio_bytes, + api_key="test-api-key", + detect_language=True, + ) + + # Verify that default language "en" is used when detected_language is None + assert response["language"] == "en" + assert response.text == "Test transcript" + assert response["task"] == "transcribe" + assert response["duration"] == 1.0