Skip to content

Commit d765235

Browse files
authored
fix: account for STT fallback transcript alignment (livekit#6633)
1 parent bbdf116 commit d765235

2 files changed

Lines changed: 40 additions & 5 deletions

File tree

livekit-agents/livekit/agents/inference/stt.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -613,13 +613,23 @@ def __init__(
613613

614614
vad = _resolve_vad_for_model(model, vad if is_given(vad) else None)
615615

616+
fallback_models: NotGivenOr[list[FallbackModel]] = NOT_GIVEN
617+
if is_given(fallback):
618+
fallback_models = _normalize_fallback(fallback)
619+
models = [model]
620+
if is_given(fallback_models):
621+
models.extend(item["model"] for item in fallback_models)
622+
aligned_transcript: Literal["word", False] = (
623+
"word" if all(_aligned_transcript_for_model(item) for item in models) else False
624+
)
625+
616626
# chat_context follows the model's native support; the session decides whether to forward
617627
super().__init__(
618628
capabilities=stt.STTCapabilities(
619629
streaming=True,
620630
interim_results=True,
621631
diarization=diarization_enabled,
622-
aligned_transcript=_aligned_transcript_for_model(model),
632+
aligned_transcript=aligned_transcript,
623633
offline_recognize=False,
624634
keyterms=_keyterms_extra_for_model(model) is not None,
625635
chat_context=_supports_agent_context_carryover(model),
@@ -647,9 +657,6 @@ def __init__(
647657
raise ValueError(
648658
"api_secret is required, either as argument or set LIVEKIT_API_SECRET environmental variable"
649659
)
650-
fallback_models: NotGivenOr[list[FallbackModel]] = NOT_GIVEN
651-
if is_given(fallback):
652-
fallback_models = _normalize_fallback(fallback)
653660

654661
self._opts = STTOptions(
655662
model=model,
@@ -741,11 +748,16 @@ def update_options(
741748

742749
self._opts.model = model
743750
self._vad = _resolve_vad_for_model(model, self._vad)
751+
models = [self._opts.model]
752+
if is_given(self._opts.fallback):
753+
models.extend(item["model"] for item in self._opts.fallback)
744754
self._capabilities = replace(
745755
self._capabilities,
746756
keyterms=_keyterms_extra_for_model(self._opts.model) is not None,
747757
chat_context=_supports_agent_context_carryover(self._opts.model),
748-
aligned_transcript=_aligned_transcript_for_model(self._opts.model),
758+
aligned_transcript=(
759+
"word" if all(_aligned_transcript_for_model(item) for item in models) else False
760+
),
749761
)
750762
if is_given(language):
751763
self._opts.language = LanguageCode(language)

tests/test_inference_stt_aligned_transcript_claim.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,29 @@ def test_unknown_models_do_not_claim_alignment(_fake_credentials: None) -> None:
102102
assert stt_impl.capabilities.aligned_transcript is False
103103

104104

105+
@pytest.mark.parametrize(
106+
("fallback", "expected"),
107+
[
108+
pytest.param("cartesia/ink-whisper", "word", id="aligned-fallback"),
109+
pytest.param("cartesia/ink-2", False, id="unaligned-fallback"),
110+
pytest.param("new-provider/new-turn-model", False, id="unknown-fallback"),
111+
],
112+
)
113+
def test_fallback_models_constrain_alignment_claim(
114+
fallback: str, expected: object, _fake_credentials: None
115+
) -> None:
116+
stt_impl = inference.STT(model="deepgram/nova-3", fallback=fallback)
117+
assert stt_impl.capabilities.aligned_transcript == expected
118+
119+
120+
def test_alignment_update_still_accounts_for_fallback(_fake_credentials: None) -> None:
121+
stt_impl = inference.STT(model="cartesia/ink-2", fallback="new-provider/new-turn-model")
122+
123+
stt_impl.update_options(model="deepgram/nova-3")
124+
125+
assert stt_impl.capabilities.aligned_transcript is False
126+
127+
105128
def test_gateway_ink2_payload_carries_no_word_alignment() -> None:
106129
"""The advertised word alignment is not in the data the gateway sends."""
107130
stream = InferenceSpeechStream.__new__(InferenceSpeechStream)

0 commit comments

Comments
 (0)