diff --git a/CHANGELOG.md b/CHANGELOG.md index 07c669d4c..4460c029d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Using the universal `LLMContext` and associated `LLMContextAggregatorPair` is a pre-requisite for using `LLMSwitcher` to switch between LLMs at runtime. +- Added new fields to the development runner's `parse_telephony_websocket` + method in support of providing dynamic data to a bot. + + - Twilio: Added a new `body` parameter, which parses the websocket message + for `customParameters`. Provide data via the `Parameter` nouns in your + TwiML to use this feature. + - Telnyx & Exotel: Both providers make the `to` and `from` phone numbers + available in the websocket messages. You can now access these numbers as + `call_data["to"]` and `call_data["from"]`. + + Note: Each telephony provider offers different features. Refer to the + corresponding example in `pipecat-examples` to see how to pass custom data + to your bot. + +- Added `body` to the `WebsocketRunnerArguments` as an optional parameter. + Custom `body` information can be passed from the server into the bot file via + the `bot()` method using this new parameter. + - Added video streaming support to `LiveKitTransport`. - Added `OpenAIRealtimeLLMService` and `AzureRealtimeLLMService` which provide diff --git a/src/pipecat/runner/types.py b/src/pipecat/runner/types.py index 842765d25..89aecd84c 100644 --- a/src/pipecat/runner/types.py +++ b/src/pipecat/runner/types.py @@ -51,9 +51,11 @@ class WebSocketRunnerArguments(RunnerArguments): Parameters: websocket: WebSocket connection for audio streaming + body: Additional request data """ websocket: WebSocket + body: Optional[Any] = field(default_factory=dict) @dataclass diff --git a/src/pipecat/runner/utils.py b/src/pipecat/runner/utils.py index 585bd02b2..c505fdaa6 100644 --- a/src/pipecat/runner/utils.py +++ b/src/pipecat/runner/utils.py @@ -99,16 +99,35 @@ async def parse_telephony_websocket(websocket: WebSocket): tuple: (transport_type: str, call_data: dict) call_data contains provider-specific fields: - - Twilio: {"stream_id": str, "call_id": str} - - Telnyx: {"stream_id": str, "call_control_id": str, "outbound_encoding": str} - - Plivo: {"stream_id": str, "call_id": str} - - Exotel: {"stream_id": str, "call_id": str, "account_sid": str} + - Twilio: { + "stream_id": str, + "call_id": str, + "body": dict + } + - Telnyx: { + "stream_id": str, + "call_control_id": str, + "outbound_encoding": str, + "from": str, + "to": str, + } + - Plivo: { + "stream_id": str, + "call_id": str, + } + - Exotel: { + "stream_id": str, + "call_id": str, + "account_sid": str, + "from": str, + "to": str, + } Example usage:: transport_type, call_data = await parse_telephony_websocket(websocket) - if transport_type == "telnyx": - outbound_encoding = call_data["outbound_encoding"] + if transport_type == "twilio": + user_id = call_data["body"]["user_id"] """ # Read first two messages start_data = websocket.iter_text() @@ -151,9 +170,12 @@ async def parse_telephony_websocket(websocket: WebSocket): # Extract provider-specific data if transport_type == "twilio": start_data = call_data_raw.get("start", {}) + body_data = start_data.get("customParameters", {}) call_data = { "stream_id": start_data.get("streamSid"), "call_id": start_data.get("callSid"), + # All custom parameters + "body": body_data, } elif transport_type == "telnyx": @@ -163,6 +185,8 @@ async def parse_telephony_websocket(websocket: WebSocket): "outbound_encoding": call_data_raw.get("start", {}) .get("media_format", {}) .get("encoding"), + "from": call_data_raw.get("start", {}).get("from", ""), + "to": call_data_raw.get("start", {}).get("to", ""), } elif transport_type == "plivo": @@ -178,6 +202,8 @@ async def parse_telephony_websocket(websocket: WebSocket): "stream_id": start_data.get("stream_sid"), "call_id": start_data.get("call_sid"), "account_sid": start_data.get("account_sid"), + "from": start_data.get("from", ""), + "to": start_data.get("to", ""), } else: