mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-10 03:28:53 +00:00
feat: handle Deepgram detected language when available (#16093)
This commit is contained in:
parent
cde9ba5f93
commit
b29ba9e3be
3 changed files with 202 additions and 12 deletions
|
|
@ -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():
|
||||
|
|
|
|||
|
|
@ -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?")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue