Merge pull request #3562 from speechmatics/fix/smx-ttfs-finals
Support TTFS for Speechmatics STT
This commit is contained in:
2
changelog/3562.changed.md
Normal file
2
changelog/3562.changed.md
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
- Added support for TTFS in `SpeechmaticsSTTService` and set the default mode to `EXTERNAL` to support Pipecat-controlled VAD.
|
||||||
|
- Changed dependency to `speechmatics-voice[smart]>=0.2.8`
|
||||||
@@ -109,7 +109,7 @@ silero = [ "onnxruntime>=1.20.1,<2" ]
|
|||||||
simli = [ "simli-ai~=1.0.3"]
|
simli = [ "simli-ai~=1.0.3"]
|
||||||
soniox = [ "pipecat-ai[websockets-base]" ]
|
soniox = [ "pipecat-ai[websockets-base]" ]
|
||||||
soundfile = [ "soundfile~=0.13.1" ]
|
soundfile = [ "soundfile~=0.13.1" ]
|
||||||
speechmatics = [ "speechmatics-voice[smart]>=0.2.6" ]
|
speechmatics = [ "speechmatics-voice[smart]>=0.2.8" ]
|
||||||
strands = [ "strands-agents>=1.9.1,<2" ]
|
strands = [ "strands-agents>=1.9.1,<2" ]
|
||||||
tavus=[]
|
tavus=[]
|
||||||
together = []
|
together = []
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class TurnDetectionMode(str, Enum):
|
|||||||
"""Endpoint and turn detection handling mode.
|
"""Endpoint and turn detection handling mode.
|
||||||
|
|
||||||
How the STT engine handles the endpointing of speech. If using Pipecat's built-in endpointing,
|
How the STT engine handles the endpointing of speech. If using Pipecat's built-in endpointing,
|
||||||
then use `TurnDetectionMode.FIXED` (default).
|
then use `TurnDetectionMode.EXTERNAL` (default).
|
||||||
|
|
||||||
To use the STT engine's built-in endpointing, then use `TurnDetectionMode.ADAPTIVE` for simple
|
To use the STT engine's built-in endpointing, then use `TurnDetectionMode.ADAPTIVE` for simple
|
||||||
voice activity detection or `TurnDetectionMode.SMART_TURN` for more advanced ML-based
|
voice activity detection or `TurnDetectionMode.SMART_TURN` for more advanced ML-based
|
||||||
@@ -106,7 +106,7 @@ class SpeechmaticsSTTService(STTService):
|
|||||||
|
|
||||||
turn_detection_mode: Endpoint handling, one of `TurnDetectionMode.FIXED`,
|
turn_detection_mode: Endpoint handling, one of `TurnDetectionMode.FIXED`,
|
||||||
`TurnDetectionMode.EXTERNAL`, `TurnDetectionMode.ADAPTIVE` and
|
`TurnDetectionMode.EXTERNAL`, `TurnDetectionMode.ADAPTIVE` and
|
||||||
`TurnDetectionMode.SMART_TURN`. Defaults to `TurnDetectionMode.FIXED`.
|
`TurnDetectionMode.SMART_TURN`. Defaults to `TurnDetectionMode.EXTERNAL`.
|
||||||
|
|
||||||
speaker_active_format: Formatter for active speaker ID. This formatter is used to format
|
speaker_active_format: Formatter for active speaker ID. This formatter is used to format
|
||||||
the text output for individual speakers and ensures that the context is clear for
|
the text output for individual speakers and ensures that the context is clear for
|
||||||
@@ -200,6 +200,7 @@ class SpeechmaticsSTTService(STTService):
|
|||||||
extra_params: Extra parameters to pass to the STT engine. This is a dictionary of
|
extra_params: Extra parameters to pass to the STT engine. This is a dictionary of
|
||||||
additional parameters that can be used to configure the STT engine.
|
additional parameters that can be used to configure the STT engine.
|
||||||
Default to None.
|
Default to None.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Service configuration
|
# Service configuration
|
||||||
@@ -207,7 +208,7 @@ class SpeechmaticsSTTService(STTService):
|
|||||||
language: Language | str = Language.EN
|
language: Language | str = Language.EN
|
||||||
|
|
||||||
# Endpointing mode
|
# Endpointing mode
|
||||||
turn_detection_mode: TurnDetectionMode = TurnDetectionMode.FIXED
|
turn_detection_mode: TurnDetectionMode = TurnDetectionMode.EXTERNAL
|
||||||
|
|
||||||
# Output formatting
|
# Output formatting
|
||||||
speaker_active_format: str | None = None
|
speaker_active_format: str | None = None
|
||||||
@@ -345,7 +346,7 @@ class SpeechmaticsSTTService(STTService):
|
|||||||
params.speaker_passive_format or params.speaker_active_format
|
params.speaker_passive_format or params.speaker_active_format
|
||||||
)
|
)
|
||||||
|
|
||||||
# Metrics
|
# Model + metrics
|
||||||
self.set_model_name(self._config.operating_point.value)
|
self.set_model_name(self._config.operating_point.value)
|
||||||
|
|
||||||
# Message queue
|
# Message queue
|
||||||
@@ -691,6 +692,7 @@ class SpeechmaticsSTTService(STTService):
|
|||||||
f"{self} VADUserStoppedSpeakingFrame received but internal VAD is being used"
|
f"{self} VADUserStoppedSpeakingFrame received but internal VAD is being used"
|
||||||
)
|
)
|
||||||
elif not self._enable_vad and self._client is not None:
|
elif not self._enable_vad and self._client is not None:
|
||||||
|
self.request_finalize()
|
||||||
self._client.finalize()
|
self._client.finalize()
|
||||||
|
|
||||||
async def _send_frames(self, segments: list[dict[str, Any]], finalized: bool = False) -> None:
|
async def _send_frames(self, segments: list[dict[str, Any]], finalized: bool = False) -> None:
|
||||||
@@ -734,16 +736,33 @@ class SpeechmaticsSTTService(STTService):
|
|||||||
|
|
||||||
# If final, then re-parse into TranscriptionFrame
|
# If final, then re-parse into TranscriptionFrame
|
||||||
if finalized:
|
if finalized:
|
||||||
|
# Do any segments have `is_eou` set to True?
|
||||||
|
if (
|
||||||
|
any(segment.get("is_eou", False) for segment in segments)
|
||||||
|
and self._finalize_requested
|
||||||
|
):
|
||||||
|
self.confirm_finalize()
|
||||||
|
|
||||||
|
# Add the finalized frames
|
||||||
frames += [TranscriptionFrame(**attr_from_segment(segment)) for segment in segments]
|
frames += [TranscriptionFrame(**attr_from_segment(segment)) for segment in segments]
|
||||||
|
|
||||||
|
# Handle the text (for metrics reporting)
|
||||||
finalized_text = "|".join([s["text"] for s in segments])
|
finalized_text = "|".join([s["text"] for s in segments])
|
||||||
await self._handle_transcription(finalized_text, True, segments[0]["language"])
|
await self._handle_transcription(
|
||||||
|
finalized_text, is_final=True, language=segments[0]["language"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Log the frames
|
||||||
logger.debug(f"{self} finalized transcript: {[f.text for f in frames]}")
|
logger.debug(f"{self} finalized transcript: {[f.text for f in frames]}")
|
||||||
|
|
||||||
# Return as interim results (unformatted)
|
# Return as interim results (unformatted)
|
||||||
else:
|
else:
|
||||||
|
# Add the interim frames
|
||||||
frames += [
|
frames += [
|
||||||
InterimTranscriptionFrame(**attr_from_segment(segment)) for segment in segments
|
InterimTranscriptionFrame(**attr_from_segment(segment)) for segment in segments
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Log the frames
|
||||||
logger.debug(f"{self} interim transcript: {[f.text for f in frames]}")
|
logger.debug(f"{self} interim transcript: {[f.text for f in frames]}")
|
||||||
|
|
||||||
# Send the frames
|
# Send the frames
|
||||||
|
|||||||
Reference in New Issue
Block a user