diff --git a/tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py b/tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py index fc5e310e71b..2d6e1f2ef63 100644 --- a/tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py +++ b/tests/test_litellm/llms/ovhcloud/test_ovhcloud_audio_transcription_transformation.py @@ -1,12 +1,18 @@ +import json import os from typing import Dict +from unittest.mock import MagicMock +import httpx import litellm import pytest from litellm.llms.base_llm.audio_transcription.transformation import ( BaseAudioTranscriptionConfig, ) +from litellm.llms.ovhcloud.audio_transcription.transformation import ( + OVHCloudAudioTranscriptionConfig, +) from litellm.utils import ProviderConfigManager from tests.llm_translation.base_audio_transcription_unit_tests import ( BaseLLMAudioTranscriptionTest, @@ -56,4 +62,71 @@ def test_ovhcloud_audio_transcription_config_installed(): assert isinstance(config, BaseAudioTranscriptionConfig) +def _make_mock_response(body: dict) -> httpx.Response: + """Helper to build a mock httpx.Response with a JSON body.""" + mock = MagicMock(spec=httpx.Response) + mock.json.return_value = body + mock.text = json.dumps(body) + mock.status_code = 200 + mock.headers = {} + return mock + +class TestOVHCloudTranscriptionResponseTransformation: + """Unit tests for OVHCloudAudioTranscriptionConfig.transform_audio_transcription_response.""" + + def setup_method(self): + self.config = OVHCloudAudioTranscriptionConfig() + + def test_verbose_json_segments_preserved(self): + """ + Regression test for https://github.com/BerriAI/litellm/issues/25633. + + When response_format=verbose_json, the OVHCloud Whisper endpoint returns + `segments` (and optionally `words`, `language`, `duration`). The + transformer must pass all fields through to TranscriptionResponse. + """ + verbose_response = { + "task": "transcribe", + "language": "english", + "duration": 3.14, + "text": "Hello world.", + "segments": [ + { + "id": 0, + "seek": 0, + "start": 0.0, + "end": 1.5, + "text": "Hello world.", + "tokens": [50364, 2425, 1002, 13], + "temperature": 0.0, + "avg_logprob": -0.3, + "compression_ratio": 1.0, + "no_speech_prob": 0.01, + } + ], + } + + raw_response = _make_mock_response(verbose_response) + result = self.config.transform_audio_transcription_response(raw_response) + + assert result.text == "Hello world." + # segments must be preserved + assert hasattr(result, "segments") or "segments" in result._hidden_params + segments = getattr(result, "segments", None) or result._hidden_params.get( + "segments" + ) + assert segments is not None + assert len(segments) == 1 + + def test_plain_text_response(self): + """A minimal JSON response with only `text` should still work.""" + raw_response = _make_mock_response({"text": "Simple transcript."}) + result = self.config.transform_audio_transcription_response(raw_response) + assert result.text == "Simple transcript." + + def test_transcript_field_normalised_to_text(self): + """If OVHCloud returns `transcript` instead of `text`, it should be normalised.""" + raw_response = _make_mock_response({"transcript": "Normalised text."}) + result = self.config.transform_audio_transcription_response(raw_response) + assert result.text == "Normalised text."