Warn when VAD stop_secs misconfiguration may degrade turn detection
Add warnings in SpeechTimeoutUserTurnStopStrategy and TurnAnalyzerUserTurnStopStrategy when stop_secs differs from the recommended default (0.2s) or when stop_secs >= STT p99 latency, which collapses the STT wait timeout to 0s. Document the stop_secs=0.2 assumption in stt_latency.py.
This commit is contained in:
@@ -13,6 +13,10 @@ transcript is received.
|
||||
These values are used by turn stop strategies to optimize timing. Each STT
|
||||
service publishes its latency via STTMetadataFrame at pipeline start.
|
||||
|
||||
All built-in values were measured with VADParams.stop_secs=0.2, the recommended
|
||||
default. If you change stop_secs, re-run the benchmark with your VAD settings
|
||||
and pass the measured value to your STT service constructor.
|
||||
|
||||
To measure latency for your specific deployment (region, network conditions,
|
||||
self-hosted instances), use the STT benchmark tool:
|
||||
https://github.com/pipecat-ai/stt-benchmark
|
||||
|
||||
@@ -10,6 +10,9 @@ import asyncio
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from pipecat.audio.vad.vad_analyzer import VAD_STOP_SECS
|
||||
from pipecat.frames.frames import (
|
||||
Frame,
|
||||
STTMetadataFrame,
|
||||
@@ -51,6 +54,7 @@ class SpeechTimeoutUserTurnStopStrategy(BaseUserTurnStopStrategy):
|
||||
self._user_speech_timeout = user_speech_timeout
|
||||
self._stt_timeout: float = 0.0 # STT P99 latency from STTMetadataFrame
|
||||
self._stop_secs: float = 0.0 # VAD stop_secs from VADUserStoppedSpeakingFrame
|
||||
self._stop_secs_warned: bool = False
|
||||
|
||||
self._text = ""
|
||||
self._vad_user_speaking = False
|
||||
@@ -98,6 +102,7 @@ class SpeechTimeoutUserTurnStopStrategy(BaseUserTurnStopStrategy):
|
||||
"""
|
||||
if isinstance(frame, STTMetadataFrame):
|
||||
self._stt_timeout = frame.ttfs_p99_latency
|
||||
self._stop_secs_warned = False
|
||||
elif isinstance(frame, VADUserStartedSpeakingFrame):
|
||||
await self._handle_vad_user_started_speaking(frame)
|
||||
elif isinstance(frame, VADUserStoppedSpeakingFrame):
|
||||
@@ -123,6 +128,26 @@ class SpeechTimeoutUserTurnStopStrategy(BaseUserTurnStopStrategy):
|
||||
self._stop_secs = frame.stop_secs
|
||||
self._vad_stopped_time = frame.timestamp
|
||||
|
||||
if not self._stop_secs_warned:
|
||||
if self._stop_secs != VAD_STOP_SECS:
|
||||
self._stop_secs_warned = True
|
||||
logger.warning(
|
||||
f"{self}: VAD stop_secs ({self._stop_secs}s) differs from the "
|
||||
f"recommended default ({VAD_STOP_SECS}s). Built-in p99 latency "
|
||||
f"values assume stop_secs={VAD_STOP_SECS}. Re-run "
|
||||
f"https://github.com/pipecat-ai/stt-benchmark with your settings "
|
||||
f"and pass the TTFS P99 latency result as ttfs_p99_latency to "
|
||||
f"your STT service."
|
||||
)
|
||||
if self._stt_timeout > 0 and self._stop_secs >= self._stt_timeout:
|
||||
self._stop_secs_warned = True
|
||||
logger.warning(
|
||||
f"{self}: VAD stop_secs ({self._stop_secs}s) >= STT p99 latency "
|
||||
f"({self._stt_timeout}s). STT wait timeout collapsed to 0s, which "
|
||||
f"may cause delayed turn detection specified by the "
|
||||
f"user_turn_stop_timeout parameter in the LLMUserAggregatorParams."
|
||||
)
|
||||
|
||||
# Start the timeout task
|
||||
timeout = self._calculate_timeout()
|
||||
self._timeout_task = self.task_manager.create_task(
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
import asyncio
|
||||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from pipecat.audio.turn.base_turn_analyzer import BaseTurnAnalyzer, EndOfTurnState
|
||||
from pipecat.audio.vad.vad_analyzer import VAD_STOP_SECS
|
||||
from pipecat.frames.frames import (
|
||||
Frame,
|
||||
InputAudioRawFrame,
|
||||
@@ -54,6 +57,8 @@ class TurnAnalyzerUserTurnStopStrategy(BaseUserTurnStopStrategy):
|
||||
self._stt_timeout: float = 0.0 # STT P99 latency from STTMetadataFrame
|
||||
self._stop_secs: float = 0.0 # VAD stop_secs from VADUserStoppedSpeakingFrame
|
||||
|
||||
self._stop_secs_warned: bool = False
|
||||
|
||||
self._text = ""
|
||||
self._turn_complete = False
|
||||
self._vad_user_speaking = False
|
||||
@@ -104,6 +109,7 @@ class TurnAnalyzerUserTurnStopStrategy(BaseUserTurnStopStrategy):
|
||||
await self._start(frame)
|
||||
elif isinstance(frame, STTMetadataFrame):
|
||||
self._stt_timeout = frame.ttfs_p99_latency
|
||||
self._stop_secs_warned = False
|
||||
elif isinstance(frame, VADUserStartedSpeakingFrame):
|
||||
await self._handle_vad_user_started_speaking(frame)
|
||||
elif isinstance(frame, VADUserStoppedSpeakingFrame):
|
||||
@@ -163,6 +169,27 @@ class TurnAnalyzerUserTurnStopStrategy(BaseUserTurnStopStrategy):
|
||||
|
||||
# Start the STT timeout (adjusted by VAD stop_secs since that time already elapsed)
|
||||
timeout = max(0, self._stt_timeout - self._stop_secs)
|
||||
|
||||
if not self._stop_secs_warned:
|
||||
if self._stop_secs != VAD_STOP_SECS:
|
||||
self._stop_secs_warned = True
|
||||
logger.warning(
|
||||
f"{self}: VAD stop_secs ({self._stop_secs}s) differs from the "
|
||||
f"recommended default ({VAD_STOP_SECS}s). Built-in p99 latency "
|
||||
f"values assume stop_secs={VAD_STOP_SECS}. Re-run "
|
||||
f"https://github.com/pipecat-ai/stt-benchmark with your settings "
|
||||
f"and pass the TTFS P99 latency result as ttfs_p99_latency to "
|
||||
f"your STT service."
|
||||
)
|
||||
if self._stt_timeout > 0 and self._stop_secs >= self._stt_timeout:
|
||||
self._stop_secs_warned = True
|
||||
logger.warning(
|
||||
f"{self}: VAD stop_secs ({self._stop_secs}s) >= STT p99 latency "
|
||||
f"({self._stt_timeout}s). STT wait timeout collapsed to 0s, which "
|
||||
f"may cause delayed turn detection specified by the "
|
||||
f"user_turn_stop_timeout parameter in the LLMUserAggregatorParams."
|
||||
)
|
||||
|
||||
self._timeout_task = self.task_manager.create_task(
|
||||
self._timeout_handler(timeout), f"{self}::_timeout_handler"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user