Add to_string helper on output DTMF frames

Mirrors the existing `from_string` classmethod and lets callers
turn a frame's `buttons` list back into a dial string like `"123#"`.
`__str__` and the Daily transport's native DTMF path reuse it.
This commit is contained in:
Aleix Conchillo Flaqué
2026-04-15 15:14:47 -07:00
parent 9fbe1bf2a3
commit f094ce80fb
2 changed files with 27 additions and 11 deletions

View File

@@ -745,11 +745,11 @@ class OutputDTMFFrame(DTMFFrame, DataFrame):
"""DTMF keypress output frame for transport queuing.
Parameters:
buttons: Sequence of one or more DTMF keypad buttons to send. Use
:meth:`from_string` to build this from a string like ``"123#"``.
button: Convenience shortcut for sending a single DTMF keypad
entry. Equivalent to ``buttons=[button]``. If both ``buttons``
and ``button`` are provided, ``buttons`` takes precedence.
buttons: Sequence of one or more DTMF keypad buttons to send. Use
:meth:`from_string` to build this from a string like ``"123#"``.
"""
button: Optional[KeypadEntry] = None
@@ -763,8 +763,7 @@ class OutputDTMFFrame(DTMFFrame, DataFrame):
raise ValueError(f"{self.__class__.__name__} requires `buttons` or `button` to be set")
def __str__(self):
buttons_str = "".join(b.value for b in self.buttons) if self.buttons else ""
return f"{self.name}(buttons: {buttons_str})"
return f"{self.name}(buttons: {self.to_string()})"
@classmethod
def from_string(cls, buttons: str, **kwargs) -> "OutputDTMFFrame":
@@ -782,6 +781,16 @@ class OutputDTMFFrame(DTMFFrame, DataFrame):
"""
return cls(buttons=[KeypadEntry(c) for c in buttons], **kwargs)
def to_string(self) -> str:
"""Return the frame's ``buttons`` as a dial string.
Returns:
A string such as ``"123#"`` formed by concatenating the values
of each :class:`~pipecat.audio.dtmf.types.KeypadEntry` in
``buttons``, or an empty string if ``buttons`` is not set.
"""
return "".join(b.value for b in self.buttons) if self.buttons else ""
#
# System frames
@@ -1280,11 +1289,11 @@ class OutputDTMFUrgentFrame(DTMFFrame, SystemFrame):
"""DTMF keypress output frame for immediate sending.
Parameters:
buttons: Sequence of one or more DTMF keypad buttons to send. Use
:meth:`from_string` to build this from a string like ``"123#"``.
button: Convenience shortcut for sending a single DTMF keypad
entry. Equivalent to ``buttons=[button]``. If both ``buttons``
and ``button`` are provided, ``buttons`` takes precedence.
buttons: Sequence of one or more DTMF keypad buttons to send. Use
:meth:`from_string` to build this from a string like ``"123#"``.
"""
button: Optional[KeypadEntry] = None
@@ -1298,8 +1307,7 @@ class OutputDTMFUrgentFrame(DTMFFrame, SystemFrame):
raise ValueError(f"{self.__class__.__name__} requires `buttons` or `button` to be set")
def __str__(self):
buttons_str = "".join(b.value for b in self.buttons) if self.buttons else ""
return f"{self.name}(buttons: {buttons_str})"
return f"{self.name}(buttons: {self.to_string()})"
@classmethod
def from_string(cls, buttons: str, **kwargs) -> "OutputDTMFUrgentFrame":
@@ -1317,6 +1325,16 @@ class OutputDTMFUrgentFrame(DTMFFrame, SystemFrame):
"""
return cls(buttons=[KeypadEntry(c) for c in buttons], **kwargs)
def to_string(self) -> str:
"""Return the frame's ``buttons`` as a dial string.
Returns:
A string such as ``"123#"`` formed by concatenating the values
of each :class:`~pipecat.audio.dtmf.types.KeypadEntry` in
``buttons``, or an empty string if ``buttons`` is not set.
"""
return "".join(b.value for b in self.buttons) if self.buttons else ""
@dataclass
class SpeechControlParamsFrame(SystemFrame):

View File

@@ -2185,14 +2185,12 @@ class DailyOutputTransport(BaseOutputTransport):
if not frame.buttons:
return
settings: Dict[str, Any] = {"tones": "".join(b.value for b in frame.buttons)}
settings: Dict[str, Any] = {"tones": frame.to_string()}
if isinstance(frame, (DailyOutputDTMFFrame, DailyOutputDTMFUrgentFrame)):
if frame.session_id is not None:
settings["sessionId"] = frame.session_id
if frame.digit_duration_ms is not None:
settings["digitDurationMs"] = frame.digit_duration_ms
elif frame.transport_destination is not None:
settings["sessionId"] = frame.transport_destination
await self._client.send_dtmf(settings)