mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-11 08:38:24 +00:00
fix(elevenlabs): keep the flat word list on diarized responses
This commit is contained in:
parent
fdfc08ae70
commit
f22b17a925
2 changed files with 24 additions and 13 deletions
|
|
@ -3,7 +3,7 @@ Translates from OpenAI's `/v1/audio/transcriptions` to ElevenLabs's `/v1/speech-
|
|||
"""
|
||||
|
||||
import io
|
||||
from collections.abc import Iterable, Iterator, Mapping
|
||||
from collections.abc import Iterable, Iterator, Mapping, Sequence
|
||||
from itertools import chain, groupby
|
||||
from types import MappingProxyType
|
||||
from typing import Final, Protocol
|
||||
|
|
@ -245,7 +245,10 @@ def _transcription_response(response_object: Mapping[str, object]) -> Transcript
|
|||
|
||||
words: Final = tuple(_JSON_OBJECTS.validate_python(response_object.get("words", ())))
|
||||
if any(word.get("speaker_id") is not None for word in words):
|
||||
return _diarized_response(ElevenLabsSTTChunk.model_validate(response_object))
|
||||
response: Final = _diarized_response(ElevenLabsSTTChunk.model_validate(response_object))
|
||||
# Callers already passing diarize=True read the flat word list, so it stays alongside the segments
|
||||
response["words"] = _openai_words(words)
|
||||
return response
|
||||
return _flat_response(response_object, words)
|
||||
|
||||
|
||||
|
|
@ -260,19 +263,23 @@ def _flat_response(
|
|||
|
||||
# Map ElevenLabs words to OpenAI format
|
||||
if "words" in response_object:
|
||||
response["words"] = [
|
||||
{
|
||||
"word": word_data.get("text", ""),
|
||||
"start": word_data.get("start", 0),
|
||||
"end": word_data.get("end", 0),
|
||||
}
|
||||
for word_data in words
|
||||
if word_data.get("type") == "word"
|
||||
]
|
||||
response["words"] = _openai_words(words)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def _openai_words(words: tuple[Mapping[str, object], ...]) -> Sequence[Mapping[str, object]]:
|
||||
return [
|
||||
{
|
||||
"word": word_data.get("text", ""),
|
||||
"start": word_data.get("start", 0),
|
||||
"end": word_data.get("end", 0),
|
||||
}
|
||||
for word_data in words
|
||||
if word_data.get("type") == "word"
|
||||
]
|
||||
|
||||
|
||||
def _diarized_response(transcript: ElevenLabsSTTChunk) -> TranscriptionResponse:
|
||||
response: Final = TranscriptionResponse(text=transcript.text)
|
||||
response["task"] = "transcribe"
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ def test_transform_audio_transcription_response_keeps_only_spoken_words():
|
|||
"language_code": "en",
|
||||
"text": "Hello world",
|
||||
"words": [
|
||||
{"type": "word", "text": "Hello", "start": 0.0, "end": 0.4},
|
||||
{"type": "word", "text": "Hello", "start": 0.0, "end": 0.4, "speaker_id": "speaker_0"},
|
||||
{"type": "spacing", "text": " ", "start": 0.4, "end": 0.5},
|
||||
{"type": "audio_event", "text": "(laughter)", "start": 0.5, "end": 0.9},
|
||||
{"type": "word", "text": "world", "start": 0.9, "end": 1.3},
|
||||
|
|
@ -247,7 +247,11 @@ def test_diarized_response_builds_speaker_segments():
|
|||
"type": "transcript.text.segment",
|
||||
},
|
||||
)
|
||||
assert "words" not in response
|
||||
assert response["words"] == [
|
||||
{"word": "Bom", "start": 3.0, "end": 3.4},
|
||||
{"word": "dia", "start": 3.4, "end": 3.8},
|
||||
{"word": "Oi", "start": 5.0, "end": 5.3},
|
||||
]
|
||||
|
||||
|
||||
def test_diarized_response_reports_fractional_duration_as_typed_usage():
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue