TranscriptProcessor: send TranscriptionUpdateFrame after interruption

This commit is contained in:
Aleix Conchillo Flaqué
2025-04-01 10:21:21 -07:00
parent 64ad916c5f
commit 3a37b11e56
4 changed files with 24 additions and 12 deletions

View File

@@ -73,6 +73,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Fixed an issue that could cause the `TranscriptionUpdateFrame` being pushed
because of an interruption to be discarded.
- Fixed an issue that would cause `SegmentedSTTService` based services - Fixed an issue that would cause `SegmentedSTTService` based services
(e.g. `OpenAISTTService`) to try to transcribe non-spoken audio, causing (e.g. `OpenAISTTService`) to try to transcribe non-spoken audio, causing
invalid transcriptions. invalid transcriptions.

View File

@@ -175,22 +175,28 @@ class AssistantTranscriptProcessor(BaseTranscriptProcessor):
""" """
await super().process_frame(frame, direction) await super().process_frame(frame, direction)
if isinstance(frame, TTSTextFrame): if isinstance(frame, (StartInterruptionFrame, CancelFrame)):
# Push frame first otherwise our emitted transcription update frame
# might get cleaned up.
await self.push_frame(frame, direction)
# Emit accumulated text with interruptions
await self._emit_aggregated_text()
elif isinstance(frame, TTSTextFrame):
# Start timestamp on first text part # Start timestamp on first text part
if not self._aggregation_start_time: if not self._aggregation_start_time:
self._aggregation_start_time = time_now_iso8601() self._aggregation_start_time = time_now_iso8601()
self._current_text_parts.append(frame.text) self._current_text_parts.append(frame.text)
elif isinstance(frame, (BotStoppedSpeakingFrame, StartInterruptionFrame, CancelFrame)): # Push frame.
# Emit accumulated text when bot finishes speaking or is interrupted await self.push_frame(frame, direction)
elif isinstance(frame, (BotStoppedSpeakingFrame, EndFrame)):
# Emit accumulated text when bot finishes speaking or pipeline ends.
await self._emit_aggregated_text() await self._emit_aggregated_text()
# Push frame.
elif isinstance(frame, EndFrame): await self.push_frame(frame, direction)
# Emit any remaining text when pipeline ends else:
await self._emit_aggregated_text() await self.push_frame(frame, direction)
await self.push_frame(frame, direction)
class TranscriptProcessor: class TranscriptProcessor:

View File

@@ -41,7 +41,10 @@ from pipecat.services.google.llm import (
GoogleLLMContext, GoogleLLMContext,
GoogleUserContextAggregator, GoogleUserContextAggregator,
) )
from pipecat.services.openai import OpenAIAssistantContextAggregator, OpenAIUserContextAggregator from pipecat.services.openai.llm import (
OpenAIAssistantContextAggregator,
OpenAIUserContextAggregator,
)
from pipecat.tests.utils import SleepFrame, run_test from pipecat.tests.utils import SleepFrame, run_test
AGGREGATION_TIMEOUT = 0.1 AGGREGATION_TIMEOUT = 0.1

View File

@@ -238,8 +238,8 @@ class TestUserTranscriptProcessor(unittest.IsolatedAsyncioTestCase):
TTSTextFrame(text="world!"), TTSTextFrame(text="world!"),
SleepFrame(sleep=0.1), SleepFrame(sleep=0.1),
StartInterruptionFrame(), # User interrupts here StartInterruptionFrame(), # User interrupts here
BotStartedSpeakingFrame(),
SleepFrame(sleep=0.1), SleepFrame(sleep=0.1),
BotStartedSpeakingFrame(),
TTSTextFrame(text="New"), TTSTextFrame(text="New"),
TTSTextFrame(text="response"), TTSTextFrame(text="response"),
SleepFrame(sleep=0.1), SleepFrame(sleep=0.1),
@@ -251,8 +251,8 @@ class TestUserTranscriptProcessor(unittest.IsolatedAsyncioTestCase):
BotStartedSpeakingFrame, BotStartedSpeakingFrame,
TTSTextFrame, # "Hello" TTSTextFrame, # "Hello"
TTSTextFrame, # "world!" TTSTextFrame, # "world!"
StartInterruptionFrame,
TranscriptionUpdateFrame, # First message (emitted due to interruption) TranscriptionUpdateFrame, # First message (emitted due to interruption)
StartInterruptionFrame, # Interruption frame comes after the update
BotStartedSpeakingFrame, BotStartedSpeakingFrame,
TTSTextFrame, # "New" TTSTextFrame, # "New"
TTSTextFrame, # "response" TTSTextFrame, # "response"