From cccd82a6175879969af4264a3b3f97b8b2361fbc Mon Sep 17 00:00:00 2001 From: Pete Date: Sat, 2 Aug 2025 14:34:00 -0400 Subject: [PATCH 1/2] Refactor `TextInputMessage` class to replace `realtimeInput` with a `text` attribute. This was sending a 1007 because it was wrapping RealtimeInput in the json. - Updated the `TextInputMessage` class to directly store text input as a string. - Modified the `from_text` class method to create an instance using the new `text` attribute. --- src/pipecat/services/gemini_multimodal_live/events.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pipecat/services/gemini_multimodal_live/events.py b/src/pipecat/services/gemini_multimodal_live/events.py index 3fb04b147..8f89b977f 100644 --- a/src/pipecat/services/gemini_multimodal_live/events.py +++ b/src/pipecat/services/gemini_multimodal_live/events.py @@ -195,7 +195,7 @@ class VideoInputMessage(BaseModel): class TextInputMessage(BaseModel): """Message containing text input data.""" - realtimeInput: RealtimeInput + text: str @classmethod def from_text(cls, text: str) -> "TextInputMessage": @@ -207,7 +207,7 @@ class TextInputMessage(BaseModel): Returns: A TextInputMessage instance. """ - return cls(realtimeInput=RealtimeInput(text=text)) + return cls(text=text) class ClientContentMessage(BaseModel): From 258e83c904d863f6acf7ecaf533ce3d6a297781e Mon Sep 17 00:00:00 2001 From: Pete Date: Sun, 3 Aug 2025 10:58:59 -0400 Subject: [PATCH 2/2] Fix: Correct Gemini Live API text input to prevent 1007 WebSocket errors - Restore TextInputMessage.realtimeInput structure for correct API format - Remove invalid turnComplete message from _send_user_text method - turnComplete is only valid for clientContent, not realtimeInput messages - realtimeInput text completion is automatically inferred by the API This fixes WebSocket 1007 errors caused by mixing realtimeInput and clientContent message types in violation of the Gemini Live API contract. --- src/pipecat/services/gemini_multimodal_live/events.py | 4 ++-- src/pipecat/services/gemini_multimodal_live/gemini.py | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/pipecat/services/gemini_multimodal_live/events.py b/src/pipecat/services/gemini_multimodal_live/events.py index 8f89b977f..3fb04b147 100644 --- a/src/pipecat/services/gemini_multimodal_live/events.py +++ b/src/pipecat/services/gemini_multimodal_live/events.py @@ -195,7 +195,7 @@ class VideoInputMessage(BaseModel): class TextInputMessage(BaseModel): """Message containing text input data.""" - text: str + realtimeInput: RealtimeInput @classmethod def from_text(cls, text: str) -> "TextInputMessage": @@ -207,7 +207,7 @@ class TextInputMessage(BaseModel): Returns: A TextInputMessage instance. """ - return cls(text=text) + return cls(realtimeInput=RealtimeInput(text=text)) class ClientContentMessage(BaseModel): diff --git a/src/pipecat/services/gemini_multimodal_live/gemini.py b/src/pipecat/services/gemini_multimodal_live/gemini.py index b7adb8c49..c62a9c86e 100644 --- a/src/pipecat/services/gemini_multimodal_live/gemini.py +++ b/src/pipecat/services/gemini_multimodal_live/gemini.py @@ -976,17 +976,14 @@ class GeminiMultimodalLiveLLMService(LLMService): with audio and video inputs, preventing temporal misalignment that can occur when different modalities are processed through separate API pathways. - After sending the text, we signal turn completion to trigger a model response - for text-only interactions. + For realtimeInput, turn completion is automatically inferred by the API based + on user activity, so no explicit turnComplete signal is needed. Args: text: The text to send as user input. """ evt = events.TextInputMessage.from_text(text) await self.send_client_event(evt) - # After sending text, we need to signal that the turn is complete. - evt = events.ClientContentMessage.model_validate({"clientContent": {"turnComplete": True}}) - await self.send_client_event(evt) async def _send_user_video(self, frame): """Send user video frame to Gemini Live API."""