From dee48d0e7b362aae3a9c1d5d58af82e628708e5e Mon Sep 17 00:00:00 2001 From: Anas Khan <83116240+anxkhn@users.noreply.github.com> Date: Mon, 6 Jul 2026 14:21:17 +0530 Subject: [PATCH] fix(audio): derive transcription filename with os.path.basename process_audio_file derived the multipart filename from a PathLike input with file_path.split("/")[-1]. On Windows, str(Path('C:/dir/name.mp3')) is 'C:\\dir\\name.mp3', which contains no forward slash, so the split returned the entire path (drive letter and backslashes) instead of the basename. That full path was then sent to provider transcription APIs as the form-data file name. Use os.path.basename, matching the sibling PathLike file-input sink in ocr/main.py. Add a regression test that patches os.path to ntpath to reproduce Windows semantics on any host. Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com> --- .../litellm_core_utils/audio_utils/utils.py | 2 +- .../litellm_core_utils/test_audio_utils.py | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/litellm/litellm_core_utils/audio_utils/utils.py b/litellm/litellm_core_utils/audio_utils/utils.py index e5007ceec34..713a993914e 100644 --- a/litellm/litellm_core_utils/audio_utils/utils.py +++ b/litellm/litellm_core_utils/audio_utils/utils.py @@ -69,7 +69,7 @@ def process_audio_file(audio_file: FileTypes) -> ProcessedAudioFile: file_path = str(audio_file) with open(file_path, "rb") as f: file_content = f.read() - filename = file_path.split("/")[-1] + filename = os.path.basename(file_path) elif isinstance(audio_file, tuple): # Tuple format: (filename, content, content_type) or (filename, content) if len(audio_file) >= 2: diff --git a/tests/test_litellm/litellm_core_utils/test_audio_utils.py b/tests/test_litellm/litellm_core_utils/test_audio_utils.py index 0e8176fffce..89858bd072b 100644 --- a/tests/test_litellm/litellm_core_utils/test_audio_utils.py +++ b/tests/test_litellm/litellm_core_utils/test_audio_utils.py @@ -69,6 +69,35 @@ class TestProcessAudioFile: with pytest.raises(ValueError, match="does not accept bare str inputs"): process_audio_file("/etc/passwd") + def test_process_windows_pathlib_input_basename(self): + """A Windows path must yield only the basename, not the full drive path. + + On Windows, str(Path('C:/dir/name.mp3')) is 'C:\\dir\\name.mp3', which + contains no '/'. Deriving the filename with str.split('/')[-1] would send + the entire path (drive letter and backslashes) to the provider as the + multipart file name. os.path is patched to ntpath here to reproduce + Windows semantics on any host. + """ + import ntpath + from pathlib import PureWindowsPath + + windows_path = PureWindowsPath("C:/Users/me/audio recording.mp3") + test_content = b"test audio content" + + with ( + patch("litellm.litellm_core_utils.audio_utils.utils.os.path", ntpath), + patch( + "litellm.litellm_core_utils.audio_utils.utils.open", + mock_open(read_data=test_content), + create=True, + ), + ): + result = process_audio_file(windows_path) + + assert result.file_content == test_content + assert result.filename == "audio recording.mp3" + assert result.content_type == "audio/mpeg" + def test_process_tuple_input_with_bytes(self): """Test processing tuple input with bytes content""" filename = "test.wav"