diff --git a/changelog/3930.added.md b/changelog/3930.added.md new file mode 100644 index 000000000..dd799f9ec --- /dev/null +++ b/changelog/3930.added.md @@ -0,0 +1 @@ +- Added `push_empty_transcripts` parameter to `BaseWhisperSTTService` and `OpenAISTTService` to allow empty transcripts to be pushed downstream as `TranscriptionFrame` instead of discarding them (the default behavior). This is intended for situations where VAD fires even though the user did not speak. In these cases, it is useful to know that nothing was transcribed so that the agent can resume speaking, instead of waiting longer for a transcription. \ No newline at end of file diff --git a/src/pipecat/services/whisper/base_stt.py b/src/pipecat/services/whisper/base_stt.py index cf3342f4b..08310831c 100644 --- a/src/pipecat/services/whisper/base_stt.py +++ b/src/pipecat/services/whisper/base_stt.py @@ -136,6 +136,7 @@ class BaseWhisperSTTService(SegmentedSTTService): prompt: Optional[str] = None, temperature: Optional[float] = None, include_prob_metrics: bool = False, + push_empty_transcripts: bool = False, ttfs_p99_latency: Optional[float] = WHISPER_TTFS_P99, **kwargs, ): @@ -151,6 +152,12 @@ class BaseWhisperSTTService(SegmentedSTTService): include_prob_metrics: If True, enables probability metrics in API response. Each service implements this differently (see child classes). Defaults to False. + push_empty_transcripts: - If true, allow empty `TranscriptionFrame` frames to be + pushed downstream instead of discarding them. This is intended for situations + where VAD fires even though the user did not speak. In these cases, it is + useful to know that nothing was transcribed so that the agent can resume + speaking, instead of waiting longer for a transcription. + Defaults to False. ttfs_p99_latency: P99 latency from speech end to final transcript in seconds. Override for your deployment. See https://github.com/pipecat-ai/stt-benchmark **kwargs: Additional arguments passed to SegmentedSTTService. @@ -171,6 +178,7 @@ class BaseWhisperSTTService(SegmentedSTTService): self._prompt = prompt self._temperature = temperature self._include_prob_metrics = include_prob_metrics + self._push_empty_transcripts = push_empty_transcripts def _create_client(self, api_key: Optional[str], base_url: Optional[str]): return AsyncOpenAI(api_key=api_key, base_url=base_url) @@ -237,7 +245,10 @@ class BaseWhisperSTTService(SegmentedSTTService): text = response.text.strip() - if text: + if not text: + logger.warning("Received empty transcription from API") + + if text or self._push_empty_transcripts: await self._handle_transcription(text, True, self._language) logger.debug(f"Transcription: [{text}]") yield TranscriptionFrame( @@ -246,8 +257,6 @@ class BaseWhisperSTTService(SegmentedSTTService): time_now_iso8601(), result=response, ) - else: - logger.warning("Received empty transcription from API") except Exception as e: yield ErrorFrame(error=f"Unknown error occurred: {e}")