mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(elevenlabs): keep acoustic diarization when multichannel would be rejected
Stereo auto-switching to use_multi_channel now only happens when ElevenLabs accepts it. With num_speakers set, timestamps_granularity=none, or more than 5 channels, diarization stays acoustic. The combined output style default is also skipped when timestamps are off, since combined requires them
This commit is contained in:
parent
1cff5f1479
commit
8f03515abd
2 changed files with 48 additions and 5 deletions
|
|
@ -39,6 +39,7 @@ _JSON_OBJECTS: Final = TypeAdapter(Iterable[Mapping[str, object]], config=Config
|
|||
_HIDDEN_PARAMS: Final = TypeAdapter(dict[str, object])
|
||||
_CHANNELS: Final = TypeAdapter(int)
|
||||
_DIARIZATION_KEYS: Final = frozenset(("diarize", "use_multi_channel", "multichannel_output_style"))
|
||||
_MAX_MULTICHANNEL_CHANNELS: Final = 5
|
||||
_ELEVENLABS_PARAM_NAMES: Final = MappingProxyType({"language": "language_code"})
|
||||
|
||||
|
||||
|
|
@ -207,26 +208,43 @@ def _channel_count(audio_content: bytes) -> int:
|
|||
return 1
|
||||
|
||||
|
||||
def _has_timestamps(provider_params: Mapping[str, object]) -> bool:
|
||||
return str(provider_params.get("timestamps_granularity", "word")).strip().lower() != "none"
|
||||
|
||||
|
||||
def _can_auto_switch_to_multichannel(provider_params: Mapping[str, object], audio_content: bytes) -> bool:
|
||||
return (
|
||||
provider_params.get("num_speakers") is None
|
||||
and _has_timestamps(provider_params)
|
||||
and 1 < _channel_count(audio_content) <= _MAX_MULTICHANNEL_CHANNELS
|
||||
)
|
||||
|
||||
|
||||
def _resolve_diarization_params(provider_params: Mapping[str, object], audio_content: bytes) -> Mapping[str, object]:
|
||||
"""
|
||||
ElevenLabs rejects diarize and use_multi_channel together. Diarization
|
||||
requested on multi-channel audio uses the channel as the speaker; on mono it
|
||||
falls back to acoustic diarization. An explicit use_multi_channel from the
|
||||
caller wins over auto-detection, and an unreadable header falls back to mono.
|
||||
requested on multi-channel audio uses the channel as the speaker, unless
|
||||
multichannel mode would reject the request (num_speakers set, timestamps off,
|
||||
or too many channels), in which case it stays acoustic diarization, as it does
|
||||
on mono. An explicit use_multi_channel from the caller wins over
|
||||
auto-detection, and an unreadable header falls back to mono.
|
||||
"""
|
||||
diarize_requested: Final = _truthy(provider_params.get("diarize"))
|
||||
multichannel: Final = (
|
||||
_truthy(provider_params["use_multi_channel"])
|
||||
if "use_multi_channel" in provider_params
|
||||
else diarize_requested and _channel_count(audio_content) > 1
|
||||
else diarize_requested and _can_auto_switch_to_multichannel(provider_params, audio_content)
|
||||
)
|
||||
others: Final = {key: value for key, value in provider_params.items() if key not in _DIARIZATION_KEYS}
|
||||
|
||||
if multichannel:
|
||||
output_style: Final = provider_params.get(
|
||||
"multichannel_output_style", "combined" if _has_timestamps(provider_params) else None
|
||||
)
|
||||
return {
|
||||
**others,
|
||||
"use_multi_channel": True,
|
||||
"multichannel_output_style": provider_params.get("multichannel_output_style", "combined"),
|
||||
**({} if output_style is None else {"multichannel_output_style": output_style}),
|
||||
}
|
||||
if diarize_requested:
|
||||
return {**others, "diarize": True}
|
||||
|
|
|
|||
|
|
@ -214,6 +214,31 @@ def test_language_maps_to_language_code():
|
|||
id="explicit-no-multichannel-keeps-diarize-on-stereo",
|
||||
),
|
||||
pytest.param(2, {}, {}, id="no-diarization-requested"),
|
||||
pytest.param(
|
||||
2,
|
||||
{"diarize": True, "num_speakers": 2},
|
||||
{"diarize": "True", "num_speakers": "2"},
|
||||
id="num-speakers-keeps-acoustic-diarize-on-stereo",
|
||||
),
|
||||
pytest.param(
|
||||
2,
|
||||
{"diarize": True, "timestamps_granularity": "none"},
|
||||
{"diarize": "True", "timestamps_granularity": "none"},
|
||||
id="no-timestamps-keeps-acoustic-diarize-on-stereo",
|
||||
),
|
||||
pytest.param(
|
||||
5,
|
||||
{"diarize": True},
|
||||
{"use_multi_channel": "True", "multichannel_output_style": "combined"},
|
||||
id="five-channels-switch-to-multichannel",
|
||||
),
|
||||
pytest.param(6, {"diarize": True}, {"diarize": "True"}, id="six-channels-keep-acoustic-diarize"),
|
||||
pytest.param(
|
||||
1,
|
||||
{"use_multi_channel": True, "timestamps_granularity": "none"},
|
||||
{"use_multi_channel": "True", "timestamps_granularity": "none"},
|
||||
id="explicit-multichannel-without-timestamps-gets-no-combined-default",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_diarization_mechanism_follows_audio_channel_count(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue