Merge pull request #2532 from pipecat-ai/aleix/universal-dtmf-support
Universal DTMF support
This commit is contained in:
25
CHANGELOG.md
25
CHANGELOG.md
@@ -5,6 +5,31 @@ All notable changes to **Pipecat** will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- `BaseOutputTransport` now implements `write_dtmf()` by loading DTMF audio and
|
||||||
|
sending it through the transport. This makes sending DTMF generic across all
|
||||||
|
output transports.
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- `pipecat.frames.frames.KeypadEntry` is deprecated and has been moved to
|
||||||
|
`pipecat.audio.dtmf.types.KeypadEntry`.
|
||||||
|
|
||||||
|
## Removed
|
||||||
|
|
||||||
|
- `DailyTransport.write_dtmf()` has been removed in favor of the generic
|
||||||
|
`BaseOutputTransport.write_dtmf()`.
|
||||||
|
|
||||||
|
- Remove deprecated `DailyTransport.send_dtmf()`.
|
||||||
|
|
||||||
|
## Deprecated
|
||||||
|
|
||||||
|
- `pipecat.frames.frames.KeypadEntry` is deprecated use
|
||||||
|
`pipecat.audio.dtmf.types.KeypadEntry` instead.
|
||||||
|
|
||||||
## [0.0.82] - 2025-08-28
|
## [0.0.82] - 2025-08-28
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ classifiers = [
|
|||||||
"Topic :: Scientific/Engineering :: Artificial Intelligence"
|
"Topic :: Scientific/Engineering :: Artificial Intelligence"
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"aiofiles>=24.1.0,<25",
|
||||||
"aiohttp>=3.11.12,<4",
|
"aiohttp>=3.11.12,<4",
|
||||||
"audioop-lts~=0.2.1; python_version>='3.13'",
|
"audioop-lts~=0.2.1; python_version>='3.13'",
|
||||||
"docstring_parser~=0.16",
|
"docstring_parser~=0.16",
|
||||||
@@ -137,6 +138,20 @@ where = ["src"]
|
|||||||
|
|
||||||
[tool.setuptools.package-data]
|
[tool.setuptools.package-data]
|
||||||
"pipecat" = ["py.typed"]
|
"pipecat" = ["py.typed"]
|
||||||
|
"pipecat.audio.dtmf" = [
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-0.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-1.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-2.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-3.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-4.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-5.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-6.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-7.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-8.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-9.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-pound.wav",
|
||||||
|
"src/pipecat/audio/dtmf/dtmf-star.wav",
|
||||||
|
]
|
||||||
"pipecat.services.aws_nova_sonic" = ["src/pipecat/services/aws_nova_sonic/ready.wav"]
|
"pipecat.services.aws_nova_sonic" = ["src/pipecat/services/aws_nova_sonic/ready.wav"]
|
||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
|
|||||||
35
scripts/dtmf/generate_dtmf.sh
Executable file
35
scripts/dtmf/generate_dtmf.sh
Executable file
@@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# DTMF frequency map (low, high)
|
||||||
|
declare -A DTMF=(
|
||||||
|
[1]="697 1209"
|
||||||
|
[2]="697 1336"
|
||||||
|
[3]="697 1477"
|
||||||
|
[4]="770 1209"
|
||||||
|
[5]="770 1336"
|
||||||
|
[6]="770 1477"
|
||||||
|
[7]="852 1209"
|
||||||
|
[8]="852 1336"
|
||||||
|
[9]="852 1477"
|
||||||
|
["star"]="941 1209"
|
||||||
|
[0]="941 1336"
|
||||||
|
["pound"]="941 1477"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Tone duration (seconds) + gap after
|
||||||
|
DURATION=0.2
|
||||||
|
GAP=0.05
|
||||||
|
SAMPLERATE=8000
|
||||||
|
|
||||||
|
for key in "${!DTMF[@]}"; do
|
||||||
|
freqs=(${DTMF[$key]})
|
||||||
|
low=${freqs[0]}
|
||||||
|
high=${freqs[1]}
|
||||||
|
echo "Generating DTMF tone for $key ($low Hz + $high Hz)"
|
||||||
|
ffmpeg -hide_banner -loglevel error -y \
|
||||||
|
-f lavfi -i "sine=frequency=$low:duration=$DURATION:sample_rate=$SAMPLERATE" \
|
||||||
|
-f lavfi -i "sine=frequency=$high:duration=$DURATION:sample_rate=$SAMPLERATE" \
|
||||||
|
-f lavfi -i "anullsrc=r=$SAMPLERATE:cl=mono:d=$GAP" \
|
||||||
|
-filter_complex "[0][1]amix=2[a];[a][2]concat=n=2:v=0:a=1[out]" \
|
||||||
|
-map "[out]" -c:a pcm_s16le -ar $SAMPLERATE "dtmf-${key}.wav"
|
||||||
|
done
|
||||||
0
src/pipecat/audio/dtmf/__init__.py
Normal file
0
src/pipecat/audio/dtmf/__init__.py
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-0.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-0.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-1.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-1.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-2.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-2.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-3.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-3.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-4.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-4.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-5.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-5.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-6.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-6.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-7.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-7.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-8.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-8.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-9.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-9.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-pound.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-pound.wav
Normal file
Binary file not shown.
BIN
src/pipecat/audio/dtmf/dtmf-star.wav
Normal file
BIN
src/pipecat/audio/dtmf/dtmf-star.wav
Normal file
Binary file not shown.
47
src/pipecat/audio/dtmf/types.py
Normal file
47
src/pipecat/audio/dtmf/types.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Copyright (c) 2024–2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
"""This module defines generic type for DTMS.
|
||||||
|
|
||||||
|
It defines the `KeypadEntry` enumeration, representing dual-tone multi-frequency
|
||||||
|
(DTMF) keypad entries for phone system integration. Each entry corresponds to a
|
||||||
|
key on the telephone keypad, facilitating the handling of input in
|
||||||
|
telecommunication applications.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class KeypadEntry(str, Enum):
|
||||||
|
"""DTMF keypad entries for phone system integration.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
ONE: Number key 1.
|
||||||
|
TWO: Number key 2.
|
||||||
|
THREE: Number key 3.
|
||||||
|
FOUR: Number key 4.
|
||||||
|
FIVE: Number key 5.
|
||||||
|
SIX: Number key 6.
|
||||||
|
SEVEN: Number key 7.
|
||||||
|
EIGHT: Number key 8.
|
||||||
|
NINE: Number key 9.
|
||||||
|
ZERO: Number key 0.
|
||||||
|
POUND: Pound/hash key (#).
|
||||||
|
STAR: Star/asterisk key (*).
|
||||||
|
"""
|
||||||
|
|
||||||
|
ONE = "1"
|
||||||
|
TWO = "2"
|
||||||
|
THREE = "3"
|
||||||
|
FOUR = "4"
|
||||||
|
FIVE = "5"
|
||||||
|
SIX = "6"
|
||||||
|
SEVEN = "7"
|
||||||
|
EIGHT = "8"
|
||||||
|
NINE = "9"
|
||||||
|
ZERO = "0"
|
||||||
|
|
||||||
|
POUND = "#"
|
||||||
|
STAR = "*"
|
||||||
70
src/pipecat/audio/dtmf/utils.py
Normal file
70
src/pipecat/audio/dtmf/utils.py
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024–2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
"""DTMF audio utilities.
|
||||||
|
|
||||||
|
This module provides functionality to load DTMF (Dual-Tone Multi-Frequency)
|
||||||
|
audio files corresponding to phone keypad entries. Audio data is cached
|
||||||
|
in-memory after first load to improve performance on subsequent accesses.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import io
|
||||||
|
import wave
|
||||||
|
from importlib.resources import files
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry
|
||||||
|
from pipecat.audio.resamplers.base_audio_resampler import BaseAudioResampler
|
||||||
|
from pipecat.audio.utils import create_file_resampler
|
||||||
|
|
||||||
|
__DTMF_LOCK__ = asyncio.Lock()
|
||||||
|
__DTMF_AUDIO__: Dict[KeypadEntry, bytes] = {}
|
||||||
|
__DTMF_RESAMPLER__: Optional[BaseAudioResampler] = None
|
||||||
|
|
||||||
|
__DTMF_FILE_NAME = {
|
||||||
|
KeypadEntry.POUND: "dtmf-pound.wav",
|
||||||
|
KeypadEntry.STAR: "dtmf-star.wav",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def load_dtmf_audio(button: KeypadEntry, *, sample_rate: int = 8000) -> bytes:
|
||||||
|
"""Load audio for DTMF tones associated with the given button.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
button (KeypadEntry): The button for which the DTMF audio is to be loaded.
|
||||||
|
sample_rate (int, optional): The sample rate for the audio. Defaults to 8000.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bytes: The audio data for the DTMF tone as bytes.
|
||||||
|
"""
|
||||||
|
global __DTMF_AUDIO__, __DTMF_RESAMPLER__
|
||||||
|
|
||||||
|
async with __DTMF_LOCK__:
|
||||||
|
if button in __DTMF_AUDIO__:
|
||||||
|
return __DTMF_AUDIO__[button]
|
||||||
|
|
||||||
|
if not __DTMF_RESAMPLER__:
|
||||||
|
__DTMF_RESAMPLER__ = create_file_resampler()
|
||||||
|
|
||||||
|
dtmf_file_name = __DTMF_FILE_NAME.get(button, f"dtmf-{button.value}.wav")
|
||||||
|
dtmf_file_path = files("pipecat.audio.dtmf").joinpath(dtmf_file_name)
|
||||||
|
|
||||||
|
async with aiofiles.open(dtmf_file_path, "rb") as f:
|
||||||
|
data = await f.read()
|
||||||
|
|
||||||
|
with io.BytesIO(data) as buffer:
|
||||||
|
with wave.open(buffer, "rb") as wf:
|
||||||
|
audio = wf.readframes(wf.getnframes())
|
||||||
|
in_sample_rate = wf.getframerate()
|
||||||
|
resampled_audio = await __DTMF_RESAMPLER__.resample(
|
||||||
|
audio, in_sample_rate, sample_rate
|
||||||
|
)
|
||||||
|
__DTMF_AUDIO__[button] = resampled_audio
|
||||||
|
|
||||||
|
return __DTMF_AUDIO__[button]
|
||||||
@@ -41,13 +41,15 @@ def create_default_resampler(**kwargs) -> BaseAudioResampler:
|
|||||||
"""
|
"""
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"`create_default_resampler` is deprecated. "
|
warnings.simplefilter("always")
|
||||||
"Use `create_stream_resampler` for real-time processing scenarios or "
|
warnings.warn(
|
||||||
"`create_file_resampler` for batch processing of complete audio files.",
|
"`create_default_resampler` is deprecated. "
|
||||||
DeprecationWarning,
|
"Use `create_stream_resampler` for real-time processing scenarios or "
|
||||||
stacklevel=2,
|
"`create_file_resampler` for batch processing of complete audio files.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
return SOXRAudioResampler(**kwargs)
|
return SOXRAudioResampler(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ and LLM processing.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum
|
|
||||||
from typing import (
|
from typing import (
|
||||||
TYPE_CHECKING,
|
TYPE_CHECKING,
|
||||||
Any,
|
Any,
|
||||||
@@ -28,6 +27,7 @@ from typing import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from pipecat.adapters.schemas.tools_schema import ToolsSchema
|
from pipecat.adapters.schemas.tools_schema import ToolsSchema
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry as NewKeypadEntry
|
||||||
from pipecat.audio.interruptions.base_interruption_strategy import BaseInterruptionStrategy
|
from pipecat.audio.interruptions.base_interruption_strategy import BaseInterruptionStrategy
|
||||||
from pipecat.audio.turn.smart_turn.base_smart_turn import SmartTurnParams
|
from pipecat.audio.turn.smart_turn.base_smart_turn import SmartTurnParams
|
||||||
from pipecat.audio.vad.vad_analyzer import VADParams
|
from pipecat.audio.vad.vad_analyzer import VADParams
|
||||||
@@ -41,9 +41,13 @@ if TYPE_CHECKING:
|
|||||||
from pipecat.processors.frame_processor import FrameProcessor
|
from pipecat.processors.frame_processor import FrameProcessor
|
||||||
|
|
||||||
|
|
||||||
class KeypadEntry(str, Enum):
|
class DeprecatedKeypadEntry:
|
||||||
"""DTMF keypad entries for phone system integration.
|
"""DTMF keypad entries for phone system integration.
|
||||||
|
|
||||||
|
.. deprecated:: 0.0.82
|
||||||
|
This class is deprecated and will be removed in a future version.
|
||||||
|
Instead, use `audio.dtmf.types.KeypadEntry`.
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
ONE: Number key 1.
|
ONE: Number key 1.
|
||||||
TWO: Number key 2.
|
TWO: Number key 2.
|
||||||
@@ -59,18 +63,38 @@ class KeypadEntry(str, Enum):
|
|||||||
STAR: Star/asterisk key (*).
|
STAR: Star/asterisk key (*).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ONE = "1"
|
_enum = NewKeypadEntry
|
||||||
TWO = "2"
|
|
||||||
THREE = "3"
|
@classmethod
|
||||||
FOUR = "4"
|
def _warn(cls):
|
||||||
FIVE = "5"
|
import warnings
|
||||||
SIX = "6"
|
|
||||||
SEVEN = "7"
|
with warnings.catch_warnings():
|
||||||
EIGHT = "8"
|
warnings.simplefilter("always")
|
||||||
NINE = "9"
|
warnings.warn(
|
||||||
ZERO = "0"
|
"`pipecat.frames.frames.KeypadEntry` is deprecated and will be removed in a future version. "
|
||||||
POUND = "#"
|
"Use `pipecat.audio.dtmf.types.KeypadEntry` instead.",
|
||||||
STAR = "*"
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
||||||
|
"""Allow the instance to be called as a function."""
|
||||||
|
self._warn()
|
||||||
|
return self._enum(*args, **kwargs)
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
"""Retrieve an attribute from the underlying enum."""
|
||||||
|
self._warn()
|
||||||
|
return getattr(self._enum, name)
|
||||||
|
|
||||||
|
def __getitem__(self, name):
|
||||||
|
"""Retrieve an item from the underlying enum."""
|
||||||
|
self._warn()
|
||||||
|
return self._enum[name]
|
||||||
|
|
||||||
|
|
||||||
|
KeypadEntry = DeprecatedKeypadEntry()
|
||||||
|
|
||||||
|
|
||||||
def format_pts(pts: Optional[int]):
|
def format_pts(pts: Optional[int]):
|
||||||
@@ -526,15 +550,16 @@ class LLMMessagesFrame(DataFrame):
|
|||||||
super().__post_init__()
|
super().__post_init__()
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.simplefilter("always")
|
with warnings.catch_warnings():
|
||||||
warnings.warn(
|
warnings.simplefilter("always")
|
||||||
"LLMMessagesFrame is deprecated and will be removed in a future version. "
|
warnings.warn(
|
||||||
"Instead, use either "
|
"LLMMessagesFrame is deprecated and will be removed in a future version. "
|
||||||
"`LLMMessagesUpdateFrame` with `run_llm=True`, or "
|
"Instead, use either "
|
||||||
"`OpenAILLMContextFrame` with desired messages in a new context",
|
"`LLMMessagesUpdateFrame` with `run_llm=True`, or "
|
||||||
DeprecationWarning,
|
"`OpenAILLMContextFrame` with desired messages in a new context",
|
||||||
stacklevel=2,
|
DeprecationWarning,
|
||||||
)
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -668,7 +693,7 @@ class DTMFFrame:
|
|||||||
button: The DTMF keypad entry that was pressed.
|
button: The DTMF keypad entry that was pressed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
button: KeypadEntry
|
button: NewKeypadEntry
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ for downstream processing by LLM context aggregators.
|
|||||||
import asyncio
|
import asyncio
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
BotInterruptionFrame,
|
BotInterruptionFrame,
|
||||||
CancelFrame,
|
CancelFrame,
|
||||||
EndFrame,
|
EndFrame,
|
||||||
Frame,
|
Frame,
|
||||||
InputDTMFFrame,
|
InputDTMFFrame,
|
||||||
KeypadEntry,
|
|
||||||
StartFrame,
|
StartFrame,
|
||||||
TranscriptionFrame,
|
TranscriptionFrame,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ LLM processing, and text-to-speech components in conversational AI pipelines.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import warnings
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Dict, List, Literal, Optional, Set
|
from typing import Dict, List, Literal, Optional, Set
|
||||||
@@ -326,11 +325,15 @@ class LLMContextResponseAggregator(BaseLLMResponseAggregator):
|
|||||||
Returns:
|
Returns:
|
||||||
LLMContextFrame containing the current context.
|
LLMContextFrame containing the current context.
|
||||||
"""
|
"""
|
||||||
warnings.warn(
|
import warnings
|
||||||
"get_context_frame() is deprecated and will be removed in a future version. To trigger an LLM response, use LLMRunFrame instead.",
|
|
||||||
DeprecationWarning,
|
with warnings.catch_warnings():
|
||||||
stacklevel=2,
|
warnings.simplefilter("always")
|
||||||
)
|
warnings.warn(
|
||||||
|
"get_context_frame() is deprecated and will be removed in a future version. To trigger an LLM response, use LLMRunFrame instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
return self._get_context_frame()
|
return self._get_context_frame()
|
||||||
|
|
||||||
def _get_context_frame(self) -> OpenAILLMContextFrame:
|
def _get_context_frame(self) -> OpenAILLMContextFrame:
|
||||||
@@ -1035,12 +1038,16 @@ class LLMUserResponseAggregator(LLMUserContextAggregator):
|
|||||||
params: Configuration parameters for aggregation behavior.
|
params: Configuration parameters for aggregation behavior.
|
||||||
**kwargs: Additional arguments passed to parent class.
|
**kwargs: Additional arguments passed to parent class.
|
||||||
"""
|
"""
|
||||||
warnings.warn(
|
import warnings
|
||||||
"LLMUserResponseAggregator is deprecated and will be removed in a future version. "
|
|
||||||
"Use LLMUserContextAggregator or another LLM-specific subclass instead.",
|
with warnings.catch_warnings():
|
||||||
DeprecationWarning,
|
warnings.simplefilter("always")
|
||||||
stacklevel=2,
|
warnings.warn(
|
||||||
)
|
"LLMUserResponseAggregator is deprecated and will be removed in a future version. "
|
||||||
|
"Use LLMUserContextAggregator or another LLM-specific subclass instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs)
|
super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs)
|
||||||
|
|
||||||
async def _process_aggregation(self):
|
async def _process_aggregation(self):
|
||||||
@@ -1078,12 +1085,16 @@ class LLMAssistantResponseAggregator(LLMAssistantContextAggregator):
|
|||||||
params: Configuration parameters for aggregation behavior.
|
params: Configuration parameters for aggregation behavior.
|
||||||
**kwargs: Additional arguments passed to parent class.
|
**kwargs: Additional arguments passed to parent class.
|
||||||
"""
|
"""
|
||||||
warnings.warn(
|
import warnings
|
||||||
"LLMAssistantResponseAggregator is deprecated and will be removed in a future version. "
|
|
||||||
"Use LLMAssistantContextAggregator or another LLM-specific subclass instead.",
|
with warnings.catch_warnings():
|
||||||
DeprecationWarning,
|
warnings.simplefilter("always")
|
||||||
stacklevel=2,
|
warnings.warn(
|
||||||
)
|
"LLMAssistantResponseAggregator is deprecated and will be removed in a future version. "
|
||||||
|
"Use LLMAssistantContextAggregator or another LLM-specific subclass instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs)
|
super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs)
|
||||||
|
|
||||||
async def push_aggregation(self):
|
async def push_aggregation(self):
|
||||||
|
|||||||
@@ -452,12 +452,14 @@ class FrameProcessor(BaseObject):
|
|||||||
"""
|
"""
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"`FrameProcessor.wait_for_task()` is deprecated. "
|
warnings.simplefilter("always")
|
||||||
"Use `await task` or `await asyncio.wait_for(task, timeout)` instead.",
|
warnings.warn(
|
||||||
DeprecationWarning,
|
"`FrameProcessor.wait_for_task()` is deprecated. "
|
||||||
stacklevel=2,
|
"Use `await task` or `await asyncio.wait_for(task, timeout)` instead.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
if timeout:
|
if timeout:
|
||||||
await asyncio.wait_for(task, timeout)
|
await asyncio.wait_for(task, timeout)
|
||||||
|
|||||||
@@ -122,11 +122,13 @@ async def configure_with_args(aiohttp_session: aiohttp.ClientSession, parser=Non
|
|||||||
"""
|
"""
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"configure_with_args is deprecated. Use configure() instead.",
|
warnings.simplefilter("always")
|
||||||
DeprecationWarning,
|
warnings.warn(
|
||||||
stacklevel=2,
|
"configure_with_args is deprecated. Use configure() instead.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
room_url, token = await configure(aiohttp_session)
|
room_url, token = await configure(aiohttp_session)
|
||||||
return (room_url, token, None)
|
return (room_url, token, None)
|
||||||
|
|||||||
@@ -13,13 +13,13 @@ from typing import Optional
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry
|
||||||
from pipecat.audio.utils import create_stream_resampler
|
from pipecat.audio.utils import create_stream_resampler
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
AudioRawFrame,
|
AudioRawFrame,
|
||||||
Frame,
|
Frame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
InputDTMFFrame,
|
InputDTMFFrame,
|
||||||
KeypadEntry,
|
|
||||||
StartFrame,
|
StartFrame,
|
||||||
StartInterruptionFrame,
|
StartInterruptionFrame,
|
||||||
TransportMessageFrame,
|
TransportMessageFrame,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from typing import Optional
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry
|
||||||
from pipecat.audio.utils import create_stream_resampler, pcm_to_ulaw, ulaw_to_pcm
|
from pipecat.audio.utils import create_stream_resampler, pcm_to_ulaw, ulaw_to_pcm
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
AudioRawFrame,
|
AudioRawFrame,
|
||||||
@@ -21,7 +22,6 @@ from pipecat.frames.frames import (
|
|||||||
Frame,
|
Frame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
InputDTMFFrame,
|
InputDTMFFrame,
|
||||||
KeypadEntry,
|
|
||||||
StartFrame,
|
StartFrame,
|
||||||
StartInterruptionFrame,
|
StartInterruptionFrame,
|
||||||
TransportMessageFrame,
|
TransportMessageFrame,
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import aiohttp
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry
|
||||||
from pipecat.audio.utils import (
|
from pipecat.audio.utils import (
|
||||||
alaw_to_pcm,
|
alaw_to_pcm,
|
||||||
create_stream_resampler,
|
create_stream_resampler,
|
||||||
@@ -28,7 +29,6 @@ from pipecat.frames.frames import (
|
|||||||
Frame,
|
Frame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
InputDTMFFrame,
|
InputDTMFFrame,
|
||||||
KeypadEntry,
|
|
||||||
StartFrame,
|
StartFrame,
|
||||||
StartInterruptionFrame,
|
StartInterruptionFrame,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from typing import Optional
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry
|
||||||
from pipecat.audio.utils import create_stream_resampler, pcm_to_ulaw, ulaw_to_pcm
|
from pipecat.audio.utils import create_stream_resampler, pcm_to_ulaw, ulaw_to_pcm
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
AudioRawFrame,
|
AudioRawFrame,
|
||||||
@@ -21,7 +22,6 @@ from pipecat.frames.frames import (
|
|||||||
Frame,
|
Frame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
InputDTMFFrame,
|
InputDTMFFrame,
|
||||||
KeypadEntry,
|
|
||||||
StartFrame,
|
StartFrame,
|
||||||
StartInterruptionFrame,
|
StartInterruptionFrame,
|
||||||
TransportMessageFrame,
|
TransportMessageFrame,
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ _warned_modules = set()
|
|||||||
|
|
||||||
|
|
||||||
def _warn_deprecated_access(globals: Dict[str, Any], attr, old: str, new: str):
|
def _warn_deprecated_access(globals: Dict[str, Any], attr, old: str, new: str):
|
||||||
import warnings
|
|
||||||
|
|
||||||
# Only warn once per old->new module pair
|
# Only warn once per old->new module pair
|
||||||
module_key = (old, new)
|
module_key = (old, new)
|
||||||
if module_key not in _warned_modules:
|
if module_key not in _warned_modules:
|
||||||
|
import warnings
|
||||||
|
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.simplefilter("always")
|
warnings.simplefilter("always")
|
||||||
warnings.warn(
|
warnings.warn(
|
||||||
|
|||||||
@@ -271,11 +271,13 @@ class CartesiaTTSService(AudioContextWordTTSService):
|
|||||||
voice_config["id"] = self._voice_id
|
voice_config["id"] = self._voice_id
|
||||||
|
|
||||||
if self._settings["emotion"]:
|
if self._settings["emotion"]:
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"The 'emotion' parameter in __experimental_controls is deprecated and will be removed in a future version.",
|
warnings.simplefilter("always")
|
||||||
DeprecationWarning,
|
warnings.warn(
|
||||||
stacklevel=2,
|
"The 'emotion' parameter in __experimental_controls is deprecated and will be removed in a future version.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
voice_config["__experimental_controls"] = {}
|
voice_config["__experimental_controls"] = {}
|
||||||
if self._settings["emotion"]:
|
if self._settings["emotion"]:
|
||||||
voice_config["__experimental_controls"]["emotion"] = self._settings["emotion"]
|
voice_config["__experimental_controls"]["emotion"] = self._settings["emotion"]
|
||||||
@@ -606,11 +608,13 @@ class CartesiaHttpTTSService(TTSService):
|
|||||||
voice_config = {"mode": "id", "id": self._voice_id}
|
voice_config = {"mode": "id", "id": self._voice_id}
|
||||||
|
|
||||||
if self._settings["emotion"]:
|
if self._settings["emotion"]:
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"The 'emotion' parameter in voice.__experimental_controls is deprecated and will be removed in a future version.",
|
warnings.simplefilter("always")
|
||||||
DeprecationWarning,
|
warnings.warn(
|
||||||
stacklevel=2,
|
"The 'emotion' parameter in voice.__experimental_controls is deprecated and will be removed in a future version.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
voice_config["__experimental_controls"] = {"emotion": self._settings["emotion"]}
|
voice_config["__experimental_controls"] = {"emotion": self._settings["emotion"]}
|
||||||
|
|
||||||
await self.start_ttfb_metrics()
|
await self.start_ttfb_metrics()
|
||||||
|
|||||||
@@ -120,12 +120,14 @@ class FishAudioTTSService(InterruptibleTTSService):
|
|||||||
if model:
|
if model:
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"Parameter 'model' is deprecated and will be removed in a future version. "
|
warnings.simplefilter("always")
|
||||||
"Use 'reference_id' instead.",
|
warnings.warn(
|
||||||
DeprecationWarning,
|
"Parameter 'model' is deprecated and will be removed in a future version. "
|
||||||
stacklevel=2,
|
"Use 'reference_id' instead.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
reference_id = model
|
reference_id = model
|
||||||
|
|
||||||
self._api_key = api_key
|
self._api_key = api_key
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ supporting multiple languages, custom vocabulary, and various audio processing o
|
|||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import warnings
|
|
||||||
from typing import Any, AsyncGenerator, Dict, Literal, Optional
|
from typing import Any, AsyncGenerator, Dict, Literal, Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -173,12 +172,16 @@ class _InputParamsDescriptor:
|
|||||||
"""Descriptor for backward compatibility with deprecation warning."""
|
"""Descriptor for backward compatibility with deprecation warning."""
|
||||||
|
|
||||||
def __get__(self, obj, objtype=None):
|
def __get__(self, obj, objtype=None):
|
||||||
warnings.warn(
|
import warnings
|
||||||
"GladiaSTTService.InputParams is deprecated and will be removed in a future version. "
|
|
||||||
"Import and use GladiaInputParams directly instead.",
|
with warnings.catch_warnings():
|
||||||
DeprecationWarning,
|
warnings.simplefilter("always")
|
||||||
stacklevel=2,
|
warnings.warn(
|
||||||
)
|
"GladiaSTTService.InputParams is deprecated and will be removed in a future version. "
|
||||||
|
"Import and use GladiaInputParams directly instead.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
return GladiaInputParams
|
return GladiaInputParams
|
||||||
|
|
||||||
|
|
||||||
@@ -234,12 +237,14 @@ class GladiaSTTService(STTService):
|
|||||||
|
|
||||||
# Warn about deprecated language parameter if it's used
|
# Warn about deprecated language parameter if it's used
|
||||||
if params.language is not None:
|
if params.language is not None:
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"The 'language' parameter is deprecated and will be removed in a future version. "
|
warnings.simplefilter("always")
|
||||||
"Use 'language_config' instead.",
|
warnings.warn(
|
||||||
DeprecationWarning,
|
"The 'language' parameter is deprecated and will be removed in a future version. "
|
||||||
stacklevel=2,
|
"Use 'language_config' instead.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
self._api_key = api_key
|
self._api_key = api_key
|
||||||
self._region = region
|
self._region = region
|
||||||
|
|||||||
@@ -65,12 +65,14 @@ class GoogleLLMOpenAIBetaService(OpenAILLMService):
|
|||||||
"""
|
"""
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"GoogleLLMOpenAIBetaService is deprecated and will be removed in a future version. "
|
warnings.simplefilter("always")
|
||||||
"Use GoogleLLMService instead for better integration with Google's native API.",
|
warnings.warn(
|
||||||
DeprecationWarning,
|
"GoogleLLMOpenAIBetaService is deprecated and will be removed in a future version. "
|
||||||
stacklevel=2,
|
"Use GoogleLLMService instead for better integration with Google's native API.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs)
|
super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import io
|
|||||||
import json
|
import json
|
||||||
import struct
|
import struct
|
||||||
import uuid
|
import uuid
|
||||||
import warnings
|
|
||||||
from typing import AsyncGenerator, Optional
|
from typing import AsyncGenerator, Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -455,11 +454,15 @@ class PlayHTHttpTTSService(TTSService):
|
|||||||
|
|
||||||
# Warn about deprecated protocol parameter if explicitly provided
|
# Warn about deprecated protocol parameter if explicitly provided
|
||||||
if protocol:
|
if protocol:
|
||||||
warnings.warn(
|
import warnings
|
||||||
"The 'protocol' parameter is deprecated and will be removed in a future version.",
|
|
||||||
DeprecationWarning,
|
with warnings.catch_warnings():
|
||||||
stacklevel=2,
|
warnings.simplefilter("always")
|
||||||
)
|
warnings.warn(
|
||||||
|
"The 'protocol' parameter is deprecated and will be removed in a future version.",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
params = params or PlayHTHttpTTSService.InputParams()
|
params = params or PlayHTHttpTTSService.InputParams()
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import warnings
|
|
||||||
from typing import Any, AsyncGenerator, Mapping, Optional
|
from typing import Any, AsyncGenerator, Mapping, Optional
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
@@ -356,11 +355,15 @@ class SarvamTTSService(InterruptibleTTSService):
|
|||||||
)
|
)
|
||||||
params = params or SarvamTTSService.InputParams()
|
params = params or SarvamTTSService.InputParams()
|
||||||
if aiohttp_session is not None:
|
if aiohttp_session is not None:
|
||||||
warnings.warn(
|
import warnings
|
||||||
"The 'aiohttp_session' parameter is deprecated and will be removed in a future version. ",
|
|
||||||
DeprecationWarning,
|
with warnings.catch_warnings():
|
||||||
stacklevel=2,
|
warnings.simplefilter("always")
|
||||||
)
|
warnings.warn(
|
||||||
|
"The 'aiohttp_session' parameter is deprecated and will be removed in a future version. ",
|
||||||
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
# WebSocket endpoint URL
|
# WebSocket endpoint URL
|
||||||
self._websocket_url = f"{url}?model={model}"
|
self._websocket_url = f"{url}?model={model}"
|
||||||
self._api_key = api_key
|
self._api_key = api_key
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import asyncio
|
|||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import warnings
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, AsyncGenerator
|
from typing import Any, AsyncGenerator
|
||||||
@@ -1107,6 +1106,8 @@ def _check_deprecated_args(kwargs: dict, params: SpeechmaticsSTTService.InputPar
|
|||||||
|
|
||||||
# Show deprecation warnings
|
# Show deprecation warnings
|
||||||
def _deprecation_warning(old: str, new: str | None = None):
|
def _deprecation_warning(old: str, new: str | None = None):
|
||||||
|
import warnings
|
||||||
|
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.simplefilter("always")
|
warnings.simplefilter("always")
|
||||||
if new:
|
if new:
|
||||||
|
|||||||
@@ -276,11 +276,13 @@ class TTSService(AIService):
|
|||||||
"""
|
"""
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
warnings.warn(
|
with warnings.catch_warnings():
|
||||||
"`TTSService.say()` is deprecated. Push a `TTSSpeakFrame` instead.",
|
warnings.simplefilter("always")
|
||||||
DeprecationWarning,
|
warnings.warn(
|
||||||
stacklevel=2,
|
"`TTSService.say()` is deprecated. Push a `TTSSpeakFrame` instead.",
|
||||||
)
|
DeprecationWarning,
|
||||||
|
stacklevel=2,
|
||||||
|
)
|
||||||
|
|
||||||
await self.queue_frame(TTSSpeakFrame(text))
|
await self.queue_frame(TTSSpeakFrame(text))
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from typing import Any, AsyncGenerator, Dict, List, Mapping, Optional
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.utils import load_dtmf_audio
|
||||||
from pipecat.audio.mixers.base_audio_mixer import BaseAudioMixer
|
from pipecat.audio.mixers.base_audio_mixer import BaseAudioMixer
|
||||||
from pipecat.audio.utils import create_stream_resampler, is_silence
|
from pipecat.audio.utils import create_stream_resampler, is_silence
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
@@ -223,7 +224,12 @@ class BaseOutputTransport(FrameProcessor):
|
|||||||
Args:
|
Args:
|
||||||
frame: The DTMF frame to write.
|
frame: The DTMF frame to write.
|
||||||
"""
|
"""
|
||||||
pass
|
dtmf_audio = await load_dtmf_audio(frame.button, sample_rate=self._sample_rate)
|
||||||
|
dtmf_audio_frame = OutputAudioRawFrame(
|
||||||
|
audio=dtmf_audio, sample_rate=self._sample_rate, num_channels=1
|
||||||
|
)
|
||||||
|
dtmf_audio_frame.transport_destination = frame.transport_destination
|
||||||
|
await self.write_audio_frame(dtmf_audio_frame)
|
||||||
|
|
||||||
async def send_audio(self, frame: OutputAudioRawFrame):
|
async def send_audio(self, frame: OutputAudioRawFrame):
|
||||||
"""Send an audio frame downstream.
|
"""Send an audio frame downstream.
|
||||||
|
|||||||
@@ -31,8 +31,6 @@ from pipecat.frames.frames import (
|
|||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
InterimTranscriptionFrame,
|
InterimTranscriptionFrame,
|
||||||
OutputAudioRawFrame,
|
OutputAudioRawFrame,
|
||||||
OutputDTMFFrame,
|
|
||||||
OutputDTMFUrgentFrame,
|
|
||||||
OutputImageRawFrame,
|
OutputImageRawFrame,
|
||||||
SpriteFrame,
|
SpriteFrame,
|
||||||
StartFrame,
|
StartFrame,
|
||||||
@@ -1676,7 +1674,7 @@ class DailyInputTransport(BaseInputTransport):
|
|||||||
class DailyOutputTransport(BaseOutputTransport):
|
class DailyOutputTransport(BaseOutputTransport):
|
||||||
"""Handles outgoing media streams and events to Daily calls.
|
"""Handles outgoing media streams and events to Daily calls.
|
||||||
|
|
||||||
Manages sending audio, video, DTMF tones, and other data to Daily calls,
|
Manages sending audio, video and other data to Daily calls,
|
||||||
including audio destination registration and message transmission.
|
including audio destination registration and message transmission.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1783,19 +1781,6 @@ class DailyOutputTransport(BaseOutputTransport):
|
|||||||
"""
|
"""
|
||||||
await self._client.register_audio_destination(destination)
|
await self._client.register_audio_destination(destination)
|
||||||
|
|
||||||
async def write_dtmf(self, frame: OutputDTMFFrame | OutputDTMFUrgentFrame):
|
|
||||||
"""Write DTMF tones to the call.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
frame: The DTMF frame containing tone information.
|
|
||||||
"""
|
|
||||||
await self._client.send_dtmf(
|
|
||||||
{
|
|
||||||
"sessionId": frame.transport_destination,
|
|
||||||
"tones": frame.button.value,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
async def write_audio_frame(self, frame: OutputAudioRawFrame):
|
async def write_audio_frame(self, frame: OutputAudioRawFrame):
|
||||||
"""Write an audio frame to the Daily call.
|
"""Write an audio frame to the Daily call.
|
||||||
|
|
||||||
@@ -2022,25 +2007,6 @@ class DailyTransport(BaseTransport):
|
|||||||
"""
|
"""
|
||||||
await self._client.stop_dialout(participant_id)
|
await self._client.stop_dialout(participant_id)
|
||||||
|
|
||||||
async def send_dtmf(self, settings):
|
|
||||||
"""Send DTMF tones during a call (deprecated).
|
|
||||||
|
|
||||||
.. deprecated:: 0.0.69
|
|
||||||
Push an `OutputDTMFFrame` or an `OutputDTMFUrgentFrame` instead.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
settings: DTMF settings including tones and target session.
|
|
||||||
"""
|
|
||||||
import warnings
|
|
||||||
|
|
||||||
with warnings.catch_warnings():
|
|
||||||
warnings.simplefilter("always")
|
|
||||||
warnings.warn(
|
|
||||||
"`DailyTransport.send_dtmf()` is deprecated, push an `OutputDTMFFrame` or an `OutputDTMFUrgentFrame` instead.",
|
|
||||||
DeprecationWarning,
|
|
||||||
)
|
|
||||||
await self._client.send_dtmf(settings)
|
|
||||||
|
|
||||||
async def sip_call_transfer(self, settings):
|
async def sip_call_transfer(self, settings):
|
||||||
"""Transfer a SIP call to another destination.
|
"""Transfer a SIP call to another destination.
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from pipecat.audio.dtmf.types import KeypadEntry
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
EndFrame,
|
EndFrame,
|
||||||
InputDTMFFrame,
|
InputDTMFFrame,
|
||||||
KeypadEntry,
|
|
||||||
TranscriptionFrame,
|
TranscriptionFrame,
|
||||||
)
|
)
|
||||||
from pipecat.processors.aggregators.dtmf_aggregator import DTMFAggregator
|
from pipecat.processors.aggregators.dtmf_aggregator import DTMFAggregator
|
||||||
|
|||||||
2
uv.lock
generated
2
uv.lock
generated
@@ -4189,6 +4189,7 @@ wheels = [
|
|||||||
name = "pipecat-ai"
|
name = "pipecat-ai"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "aiofiles" },
|
||||||
{ name = "aiohttp" },
|
{ name = "aiohttp" },
|
||||||
{ name = "audioop-lts", marker = "python_full_version >= '3.13'" },
|
{ name = "audioop-lts", marker = "python_full_version >= '3.13'" },
|
||||||
{ name = "docstring-parser" },
|
{ name = "docstring-parser" },
|
||||||
@@ -4409,6 +4410,7 @@ docs = [
|
|||||||
requires-dist = [
|
requires-dist = [
|
||||||
{ name = "accelerate", marker = "extra == 'moondream'", specifier = "~=1.10.0" },
|
{ name = "accelerate", marker = "extra == 'moondream'", specifier = "~=1.10.0" },
|
||||||
{ name = "aioboto3", marker = "extra == 'aws'", specifier = "~=15.0.0" },
|
{ name = "aioboto3", marker = "extra == 'aws'", specifier = "~=15.0.0" },
|
||||||
|
{ name = "aiofiles", specifier = ">=24.1.0,<25" },
|
||||||
{ name = "aiohttp", specifier = ">=3.11.12,<4" },
|
{ name = "aiohttp", specifier = ">=3.11.12,<4" },
|
||||||
{ name = "aiortc", marker = "extra == 'webrtc'", specifier = "~=1.11.0" },
|
{ name = "aiortc", marker = "extra == 'webrtc'", specifier = "~=1.11.0" },
|
||||||
{ name = "anthropic", marker = "extra == 'anthropic'", specifier = "~=0.49.0" },
|
{ name = "anthropic", marker = "extra == 'anthropic'", specifier = "~=0.49.0" },
|
||||||
|
|||||||
Reference in New Issue
Block a user