Skip to content

Conversation

@Otoru
Copy link

@Otoru Otoru commented Nov 11, 2025

Problem

The audio transcription endpoint was not considering the actual audio file content when generating cache keys. Instead, it was only using the filename, which caused incorrect cache hits when:

  • Two different audio files had the same filename
  • Audio files were passed as bytes without a filename
  • File-like objects without unique names were used

This resulted in the same transcription being returned for different audio files, causing data integrity issues.

Solution

This PR fixes the cache key generation for audio transcriptions by:

  1. Added calculate_audio_file_hash() function (litellm/litellm_core_utils/audio_utils/utils.py):

    • Calculates SHA256 hash of the actual audio file content
    • Handles all input types (bytes, file paths, file-like objects, tuples)
    • Returns a unique hash based on file content, not filename
  2. Updated file_checksum calculation (litellm/utils.py):

    • Changed from using get_audio_file_name() to calculate_audio_file_hash()
    • Now generates cache keys based on actual file content
  3. Enhanced cache key generation (litellm/caching/caching.py):

    • Improved _get_file_param_value() with proper fallback logic
    • First checks for pre-calculated file_checksum in metadata
    • Falls back to calculating hash if not present
    • Final fallback to filename if hash calculation fails
  4. Added comprehensive tests (tests/test_litellm/caching/test_transcription_cache.py):

    • Tests that different files with same name generate different cache keys
    • Tests that identical files generate the same cache key
    • Tests various input types (bytes, file path, file-like objects)
    • Tests fallback behavior when hash calculation fails

Changes Made

  • litellm/litellm_core_utils/audio_utils/utils.py: Added calculate_audio_file_hash() function
  • litellm/utils.py: Updated to use content hash instead of filename
  • litellm/caching/caching.py: Enhanced cache key generation with hash fallback
  • tests/test_litellm/caching/test_transcription_cache.py: Added comprehensive test suite

Testing

All new tests pass and verify:

  • ✅ Different audio files with same name generate different cache keys
  • ✅ Identical audio files generate the same cache key
  • ✅ Works correctly with bytes, file paths, and file-like objects
  • ✅ Proper fallback behavior when hash calculation fails

Impact

  • Breaking Change: No - this is a bug fix that maintains backward compatibility
  • Performance: Minimal overhead from hash calculation (SHA256 is fast)
  • Security: No security implications
  • User Experience: Fixes incorrect transcriptions being returned from cache

Related Issues

Fixes the issue where audio transcription cache keys were based on filename instead of file content, causing incorrect cache hits for different audio files.

Checklist

  • Code follows the project's style guidelines
  • Self-review completed
  • Comments added for complex code
  • Documentation updated (if needed)
  • Tests added/updated
  • All tests pass
  • No breaking changes introduced

- Add calculate_audio_file_hash() function to generate SHA256 hash of audio file content
- Update file_checksum calculation in utils.py to use content hash instead of filename
- Enhance _get_file_param_value() in caching.py with hash calculation fallback
- Add comprehensive tests for transcription cache key generation

Fixes issue where different audio files with same name would share cache keys,
causing incorrect transcriptions to be returned from cache.
@vercel
Copy link

vercel bot commented Nov 11, 2025

@Otoru is attempting to deploy a commit to the CLERKIEAI Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant
Copy link

CLAassistant commented Nov 11, 2025

CLA assistant check
All committers have signed the CLA.

Otoru and others added 10 commits November 11, 2025 00:53
When tests pass MagicMock() as file parameter, hash calculation may fail.
Added try-except to fallback to filename if hash calculation fails,
ensuring the flow continues and client creation is not blocked.
…DIO_ANALYZER_API_BASE

The tests test_presidio_sets_guardrail_information_in_request_data and
test_request_data_flows_to_apply_guardrail were failing because they didn't
use mock_testing=True, causing Presidio to try to initialize and require
the PRESIDIO_ANALYZER_API_BASE environment variable. Adding mock_testing=True
allows these tests to run without external dependencies, consistent with
other Presidio tests in the file.
- Remove unused 'traceback' import
- Separate 'status' import into its own line for clarity
- Replace traceback.format_exc() with verbose_proxy_logger.exception() which is the proper way to log exceptions
Replace manual exception handling with handle_exception_on_proxy() helper
function from litellm.proxy.utils, which is the standard approach used
throughout the codebase. This simplifies the code and ensures consistent
error handling.
…ion_on_proxy

Maintain the verbose_proxy_logger.error() call before handle_exception_on_proxy()
to ensure proper error logging, as per the main branch version.
The status import is no longer needed after using handle_exception_on_proxy()
helper function which handles status codes internally.
- Add check for None file object before processing
- Add nested try-except for more robust fallback handling
- Improve error message in calculate_audio_file_hash to preserve original exception
- This should prevent 500 errors when file processing fails in edge cases
- Remove unused exception variable 'e' in audio file hash calculation
- Fix test_base_email.py to properly add enterprise directory to sys.path
- This ensures litellm_enterprise modules can be imported correctly
Change FileTypes to Optional[FileTypes] since kwargs.get('file') can return None.
This fixes the mypy type error on line 785.

file_checksum = calculate_audio_file_hash(audio_file=file)
# Store in metadata for future use
if "metadata" in kwargs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handle metadata being none

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also why check this again, we already have a metadata var above (line 361)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like this?


file_checksum = calculate_audio_file_hash(audio_file=file)
# Store in metadata for future use
if "metadata" in kwargs:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also why check this again, we already have a metadata var above (line 361)

- Change metadata.get() to handle None case with 'or {}'
- Remove redundant 'if metadata in kwargs' check and use existing metadata variable
- Simplify code by directly updating metadata variable and kwargs
@Otoru Otoru requested a review from krrishdholakia November 11, 2025 11:30
- Change import from litellm_enterprise.types to enterprise.litellm_enterprise.types
- Ensures test uses local enterprise code instead of installed package
- Fixes ImportError for SendKeyRotatedEmailEvent in CI
- Add enterprise/litellm_enterprise directory to sys.path before enterprise
- Allows base_email.py to find litellm_enterprise.types from local code
- Fixes ImportError when base_email.py imports from litellm_enterprise.types
- Remove installed litellm_enterprise modules before importing to force use of local code
- Ensures SendKeyRotatedEmailEvent is found from local enterprise code
- Fixes ImportError when installed package doesn't have latest types
- All 18 tests passing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants