Twilio serializer reading dtmf websocket messages and generating InputDTMFFrame containing the corresponding value of KeypadEntry
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
from enum import Enum
|
||||||
from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Literal, Mapping, Optional, Tuple
|
from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Literal, Mapping, Optional, Tuple
|
||||||
|
|
||||||
from pipecat.audio.vad.vad_analyzer import VADParams
|
from pipecat.audio.vad.vad_analyzer import VADParams
|
||||||
@@ -18,6 +19,23 @@ if TYPE_CHECKING:
|
|||||||
from pipecat.observers.base_observer import BaseObserver
|
from pipecat.observers.base_observer import BaseObserver
|
||||||
|
|
||||||
|
|
||||||
|
class KeypadEntry(str, Enum):
|
||||||
|
"""DTMF entries."""
|
||||||
|
|
||||||
|
ONE = "1"
|
||||||
|
TWO = "2"
|
||||||
|
THREE = "3"
|
||||||
|
FOUR = "4"
|
||||||
|
FIVE = "5"
|
||||||
|
SIX = "6"
|
||||||
|
SEVEN = "7"
|
||||||
|
EIGHT = "8"
|
||||||
|
NINE = "9"
|
||||||
|
ZERO = "0"
|
||||||
|
POUND = "#"
|
||||||
|
STAR = "*"
|
||||||
|
|
||||||
|
|
||||||
def format_pts(pts: int | None):
|
def format_pts(pts: int | None):
|
||||||
return nanoseconds_to_str(pts) if pts else None
|
return nanoseconds_to_str(pts) if pts else None
|
||||||
|
|
||||||
@@ -615,6 +633,13 @@ class VisionImageRawFrame(InputImageRawFrame):
|
|||||||
return f"{self.name}(pts: {pts}, text: [{self.text}], size: {self.size}, format: {self.format})"
|
return f"{self.name}(pts: {pts}, text: [{self.text}], size: {self.size}, format: {self.format})"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class InputDTMFFrame(Frame):
|
||||||
|
"""A DTMF button input"""
|
||||||
|
|
||||||
|
button: KeypadEntry
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Control frames
|
# Control frames
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -10,7 +10,14 @@ import json
|
|||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from pipecat.audio.utils import pcm_to_ulaw, ulaw_to_pcm
|
from pipecat.audio.utils import pcm_to_ulaw, ulaw_to_pcm
|
||||||
from pipecat.frames.frames import AudioRawFrame, Frame, InputAudioRawFrame, StartInterruptionFrame
|
from pipecat.frames.frames import (
|
||||||
|
AudioRawFrame,
|
||||||
|
Frame,
|
||||||
|
InputAudioRawFrame,
|
||||||
|
InputDTMFFrame,
|
||||||
|
KeypadEntry,
|
||||||
|
StartInterruptionFrame,
|
||||||
|
)
|
||||||
from pipecat.serializers.base_serializer import FrameSerializer, FrameSerializerType
|
from pipecat.serializers.base_serializer import FrameSerializer, FrameSerializerType
|
||||||
|
|
||||||
|
|
||||||
@@ -48,9 +55,7 @@ class TwilioFrameSerializer(FrameSerializer):
|
|||||||
def deserialize(self, data: str | bytes) -> Frame | None:
|
def deserialize(self, data: str | bytes) -> Frame | None:
|
||||||
message = json.loads(data)
|
message = json.loads(data)
|
||||||
|
|
||||||
if message["event"] != "media":
|
if message["event"] == "media":
|
||||||
return None
|
|
||||||
else:
|
|
||||||
payload_base64 = message["media"]["payload"]
|
payload_base64 = message["media"]["payload"]
|
||||||
payload = base64.b64decode(payload_base64)
|
payload = base64.b64decode(payload_base64)
|
||||||
|
|
||||||
@@ -61,3 +66,13 @@ class TwilioFrameSerializer(FrameSerializer):
|
|||||||
audio=deserialized_data, num_channels=1, sample_rate=self._params.sample_rate
|
audio=deserialized_data, num_channels=1, sample_rate=self._params.sample_rate
|
||||||
)
|
)
|
||||||
return audio_frame
|
return audio_frame
|
||||||
|
elif message["event"] == "dtmf":
|
||||||
|
digit = message.get("dtmf", {}).get("digit")
|
||||||
|
|
||||||
|
try:
|
||||||
|
return InputDTMFFrame(KeypadEntry(digit))
|
||||||
|
except ValueError as e:
|
||||||
|
# Handle case where string doesn't match any enum value
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|||||||
Reference in New Issue
Block a user