Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/6351.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Added `output_type` to the RTVI `bot-output` message, the counterpart of `input_type` on `user-input`. It says what kind of text the message holds: a sentence, a word, a backchannel, or a custom type such as `"code"`.
1 change: 1 addition & 0 deletions changelog/6351.deprecated.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Deprecated the `text_type` field of the RTVI `bot-output` message. Read `output_type` instead, which carries the same value. The bot sends `output_type`, `text_type` and the deprecated `aggregated_by` until 2.0.0.
4 changes: 2 additions & 2 deletions docs/architecture/word-trecking/rtvi-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ onBotOutput: (data) => {
}
// Anything else (including spoken_status "new") → render a new bubble element
this.addConversationMessage(
data.text, 'bot', data.text_type, data.segment_id,
data.text, 'bot', data.output_type, data.segment_id,
);
}

Expand All @@ -159,7 +159,7 @@ highlightSpokenText(data) {
}
```

`data.text_type` carries the segment type, so the client also renders a `code` segment
`data.output_type` carries the segment type, so the client also renders a `code` segment
as a syntax-highlighted `<pre>` block and a `link` segment as an anchor — **without parsing
any tags itself**.

Expand Down
15 changes: 13 additions & 2 deletions scripts/deprecations/deprecations.json
Original file line number Diff line number Diff line change
Expand Up @@ -1461,8 +1461,19 @@
"deprecated_in": "1.13.0",
"removed_in": "2.0.0",
"relation": "use_existing",
"replacement": "text_type",
"message": "Use ``text_type`` instead. Will be removed in 2.0.0.",
"replacement": "output_type",
"message": "Use ``output_type`` instead. Will be removed in 2.0.0.",
"location": "pipecat/processors/frameworks/rtvi/models.py"
},
{
"subject": "BotOutputMessageData.text_type",
"module": "pipecat.processors.frameworks.rtvi.models",
"kind": "parameter",
"deprecated_in": "1.14.0",
"removed_in": "2.0.0",
"relation": "use_existing",
"replacement": "output_type",
"message": "Use ``output_type`` instead. Will be removed in 2.0.0.",
"location": "pipecat/processors/frameworks/rtvi/models.py"
},
{
Expand Down
2 changes: 1 addition & 1 deletion src/pipecat/evals/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ def _user_input_event(self, data: dict) -> dict | None:

def _bot_backchannel_event(self, data: dict) -> dict | None:
"""The bot's backchannel, from the ``bot-output`` reporting it was spoken to the end."""
if data.get("text_type") != "backchannel" or data.get("spoken_status") != "completed":
if data.get("output_type") != "backchannel" or data.get("spoken_status") != "completed":
return None
progress = data.get("spoken_progress") or {}
return {
Expand Down
27 changes: 17 additions & 10 deletions src/pipecat/processors/frameworks/rtvi/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,11 +505,17 @@ class BotOutputMessageData(TextMessageData):
only sees the fields relevant to its version.

Parameters:
text_type: What form the text is in (e.g., sentence, code, etc.).
aggregated_by: What form the text is in, always the same as ``text_type``.
output_type: What form the text is in (e.g., sentence, code, etc.).
text_type: What form the text is in, always the same as ``output_type``.

.. deprecated:: 1.14.0
Use ``output_type`` instead.
Will be removed in 2.0.0.

aggregated_by: What form the text is in, always the same as ``output_type``.

.. deprecated:: 1.13.0
Use ``text_type`` instead.
Use ``output_type`` instead.
Will be removed in 2.0.0.

segment_id: ID of the source AggregatedTextFrame.
Expand All @@ -523,7 +529,8 @@ class BotOutputMessageData(TextMessageData):
Present when ``will_be_spoken`` is ``True``.
"""

text_type: TextType | str
output_type: TextType | str
text_type: TextType | str | None = None
aggregated_by: TextType | str | None = None
segment_id: int | None = None
# v1 field (protocol 1.4.x)
Expand All @@ -535,13 +542,13 @@ class BotOutputMessageData(TextMessageData):

@model_validator(mode="before")
@classmethod
def _sync_text_type(cls, data: Any) -> Any:
"""Fill whichever of ``text_type`` and ``aggregated_by`` is missing from the other."""
def _sync_output_type(cls, data: Any) -> Any:
"""Fill whichever of ``output_type`` and its deprecated names are missing."""
if isinstance(data, dict):
if "text_type" not in data and "aggregated_by" in data:
data = {**data, "text_type": data["aggregated_by"]}
elif "aggregated_by" not in data and "text_type" in data:
data = {**data, "aggregated_by": data["text_type"]}
names = ("output_type", "text_type", "aggregated_by")
given = [data[name] for name in names if name in data]
if given:
data = {**dict.fromkeys(names, given[0]), **data}
return data


Expand Down
4 changes: 2 additions & 2 deletions src/pipecat/processors/frameworks/rtvi/observer.py
Original file line number Diff line number Diff line change
Expand Up @@ -913,7 +913,7 @@ async def _handle_aggregated_progress(self, frame: AggregatedTextProgressFrame):
data=RTVI.BotOutputMessageData(
text=text,
will_be_spoken=True,
text_type=text_type,
output_type=text_type,
segment_id=frame.segment_id,
spoken_status=spoken_status,
spoken_progress=RTVI.SpokenProgressData(
Expand Down Expand Up @@ -1007,7 +1007,7 @@ async def _send_aggregated_llm_text(self, frame: AggregatedTextFrame):
text=text,
spoken=isTTS,
will_be_spoken=will_be_spoken,
text_type=text_type,
output_type=text_type,
segment_id=segment_id,
spoken_status=spoken_status,
spoken_progress=progress,
Expand Down
4 changes: 2 additions & 2 deletions tests/test_evals_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,12 @@ def msg(msg_type, data):
message={"label": RTVI.MESSAGE_LABEL, "type": msg_type, "data": data}
)

def bot_output(text_type, status, accumulated="Mm-hmm."):
def bot_output(output_type, status, accumulated="Mm-hmm."):
return msg(
"bot-output",
{
"text": "Mm-hmm.",
"text_type": text_type,
"output_type": output_type,
"spoken_status": status,
"spoken_progress": {"accumulated_text": accumulated, "remaining_text": ""},
},
Expand Down
2 changes: 1 addition & 1 deletion tests/test_rtvi_observer_pushes.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ async def test_a_backchannel_is_sent_as_output_and_tts_text(self):
[RTVI.BotOutputMessage, RTVI.BotTTSTextMessage, RTVI.BotOutputMessage],
)
self.assertEqual(
[(data.text_type, data.spoken_status) for data in self._sent_outputs()],
[(data.output_type, data.spoken_status) for data in self._sent_outputs()],
[(TextType.BACKCHANNEL, "new"), (TextType.BACKCHANNEL, "in-progress")],
)
self.assertEqual(messages[1].data.text, "Mm-hmm,")
Expand Down
5 changes: 3 additions & 2 deletions tests/test_text_type_deprecations.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,12 @@ def test_tts_service_transformer_aggregation_type():
assert tts._text_transforms == []


@pytest.mark.parametrize("field", ["text_type", "aggregated_by"])
def test_bot_output_message_carries_both_fields(field):
@pytest.mark.parametrize("field", ["output_type", "text_type", "aggregated_by"])
def test_bot_output_message_carries_every_name(field):
data = RTVI.BotOutputMessageData(text="Hello.", **{field: "status"})
assert data.model_dump(exclude_none=True) == {
"text": "Hello.",
"output_type": "status",
"text_type": "status",
"aggregated_by": "status",
}
Expand Down
Loading