Merge pull request #1857 from pipecat-ai/aleix/avoid-mutable-default-values

avoid mutable default constructor values
This commit is contained in:
Aleix Conchillo Flaqué
2025-05-20 13:10:24 -07:00
committed by GitHub
51 changed files with 209 additions and 124 deletions

View File

@@ -93,6 +93,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Fixed an issue that would cause multiple instances of the same class to behave
incorrectly if any of the given constructor arguments defaulted to a mutable
value (e.g. lists, dictionaries, objects).
- Fixed an issue with `CartesiaTTSService` where `TTSTextFrame` messages weren't - Fixed an issue with `CartesiaTTSService` where `TTSTextFrame` messages weren't
being emitted when the model was set to `sonic`. This resulted in the being emitted when the model was set to `sonic`. This resulted in the
assistant context not being updated with assistant messages. assistant context not being updated with assistant messages.

View File

@@ -5,7 +5,7 @@
# #
from enum import Enum from enum import Enum
from typing import Any, Dict, List from typing import Any, Dict, List, Optional
from pipecat.adapters.schemas.function_schema import FunctionSchema from pipecat.adapters.schemas.function_schema import FunctionSchema
@@ -18,7 +18,7 @@ class ToolsSchema:
def __init__( def __init__(
self, self,
standard_tools: List[FunctionSchema], standard_tools: List[FunctionSchema],
custom_tools: Dict[AdapterType, List[Dict[str, Any]]] = None, custom_tools: Optional[Dict[AdapterType, List[Dict[str, Any]]]] = None,
) -> None: ) -> None:
""" """
A schema for tools that includes both standardized function schemas A schema for tools that includes both standardized function schemas

View File

@@ -36,10 +36,10 @@ class SmartTurnTimeoutException(Exception):
class BaseSmartTurn(BaseTurnAnalyzer): class BaseSmartTurn(BaseTurnAnalyzer):
def __init__( def __init__(
self, *, sample_rate: Optional[int] = None, params: SmartTurnParams = SmartTurnParams() self, *, sample_rate: Optional[int] = None, params: Optional[SmartTurnParams] = None
): ):
super().__init__(sample_rate=sample_rate) super().__init__(sample_rate=sample_rate)
self._params = params self._params = params or SmartTurnParams()
# Configuration # Configuration
self._stop_ms = self._params.stop_secs * 1000 # silence threshold in ms self._stop_ms = self._params.stop_secs * 1000 # silence threshold in ms
# Inference state # Inference state

View File

@@ -6,7 +6,7 @@
import asyncio import asyncio
import io import io
from typing import Any, Dict from typing import Any, Dict, Optional
import aiohttp import aiohttp
import numpy as np import numpy as np
@@ -21,12 +21,12 @@ class HttpSmartTurnAnalyzer(BaseSmartTurn):
*, *,
url: str, url: str,
aiohttp_session: aiohttp.ClientSession, aiohttp_session: aiohttp.ClientSession,
headers: Dict[str, str] = {}, headers: Optional[Dict[str, str]] = None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
self._url = url self._url = url
self._headers = headers self._headers = headers or {}
self._aiohttp_session = aiohttp_session self._aiohttp_session = aiohttp_session
def _serialize_array(self, audio_array: np.ndarray) -> bytes: def _serialize_array(self, audio_array: np.ndarray) -> bytes:

View File

@@ -105,7 +105,7 @@ class SileroOnnxModel:
class SileroVADAnalyzer(VADAnalyzer): class SileroVADAnalyzer(VADAnalyzer):
def __init__(self, *, sample_rate: Optional[int] = None, params: VADParams = VADParams()): def __init__(self, *, sample_rate: Optional[int] = None, params: Optional[VADParams] = None):
super().__init__(sample_rate=sample_rate, params=params) super().__init__(sample_rate=sample_rate, params=params)
logger.debug("Loading Silero VAD model...") logger.debug("Loading Silero VAD model...")

View File

@@ -34,10 +34,10 @@ class VADParams(BaseModel):
class VADAnalyzer(ABC): class VADAnalyzer(ABC):
def __init__(self, *, sample_rate: Optional[int] = None, params: VADParams): def __init__(self, *, sample_rate: Optional[int] = None, params: Optional[VADParams] = None):
self._init_sample_rate = sample_rate self._init_sample_rate = sample_rate
self._sample_rate = 0 self._sample_rate = 0
self._params = params self._params = params or VADParams()
self._num_channels = 1 self._num_channels = 1
self._vad_buffer = b"" self._vad_buffer = b""

View File

@@ -188,9 +188,9 @@ class PipelineTask(BaseTask):
self, self,
pipeline: BasePipeline, pipeline: BasePipeline,
*, *,
params: PipelineParams = PipelineParams(), params: Optional[PipelineParams] = None,
observers: List[BaseObserver] = [], observers: Optional[List[BaseObserver]] = None,
clock: BaseClock = SystemClock(), clock: Optional[BaseClock] = None,
task_manager: Optional[BaseTaskManager] = None, task_manager: Optional[BaseTaskManager] = None,
check_dangling_tasks: bool = True, check_dangling_tasks: bool = True,
idle_timeout_secs: Optional[float] = 300, idle_timeout_secs: Optional[float] = 300,
@@ -205,8 +205,8 @@ class PipelineTask(BaseTask):
): ):
super().__init__() super().__init__()
self._pipeline = pipeline self._pipeline = pipeline
self._clock = clock self._clock = clock or SystemClock()
self._params = params self._params = params or PipelineParams()
self._check_dangling_tasks = check_dangling_tasks self._check_dangling_tasks = check_dangling_tasks
self._idle_timeout_secs = idle_timeout_secs self._idle_timeout_secs = idle_timeout_secs
self._idle_timeout_frames = idle_timeout_frames self._idle_timeout_frames = idle_timeout_frames
@@ -224,6 +224,7 @@ class PipelineTask(BaseTask):
DeprecationWarning, DeprecationWarning,
) )
observers = self._params.observers observers = self._params.observers
observers = observers or []
if self._enable_turn_tracking: if self._enable_turn_tracking:
self._turn_tracking_observer = TurnTrackingObserver() self._turn_tracking_observer = TurnTrackingObserver()
observers = [self._turn_tracking_observer] + list(observers) observers = [self._turn_tracking_observer] + list(observers)

View File

@@ -6,7 +6,7 @@
import asyncio import asyncio
import inspect import inspect
from typing import List from typing import List, Optional
from attr import dataclass from attr import dataclass
@@ -39,8 +39,10 @@ class TaskObserver(BaseObserver):
""" """
def __init__(self, *, observers: List[BaseObserver] = [], task_manager: BaseTaskManager): def __init__(
self._observers = observers self, *, observers: Optional[List[BaseObserver]] = None, task_manager: BaseTaskManager
):
self._observers = observers or []
self._task_manager = task_manager self._task_manager = task_manager
self._proxies: List[Proxy] = [] self._proxies: List[Proxy] = []

View File

@@ -7,7 +7,7 @@
import asyncio import asyncio
from abc import abstractmethod from abc import abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict, List, Literal, Set from typing import Dict, List, Literal, Optional, Set
from loguru import logger from loguru import logger
@@ -243,11 +243,11 @@ class LLMUserContextAggregator(LLMContextResponseAggregator):
self, self,
context: OpenAILLMContext, context: OpenAILLMContext,
*, *,
params: LLMUserAggregatorParams = LLMUserAggregatorParams(), params: Optional[LLMUserAggregatorParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(context=context, role="user", **kwargs) super().__init__(context=context, role="user", **kwargs)
self._params = params self._params = params or LLMUserAggregatorParams()
if "aggregation_timeout" in kwargs: if "aggregation_timeout" in kwargs:
import warnings import warnings
@@ -446,11 +446,11 @@ class LLMAssistantContextAggregator(LLMContextResponseAggregator):
self, self,
context: OpenAILLMContext, context: OpenAILLMContext,
*, *,
params: LLMAssistantAggregatorParams = LLMAssistantAggregatorParams(), params: Optional[LLMAssistantAggregatorParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(context=context, role="assistant", **kwargs) super().__init__(context=context, role="assistant", **kwargs)
self._params = params self._params = params or LLMAssistantAggregatorParams()
if "expect_stripped_words" in kwargs: if "expect_stripped_words" in kwargs:
import warnings import warnings
@@ -640,9 +640,9 @@ class LLMAssistantContextAggregator(LLMContextResponseAggregator):
class LLMUserResponseAggregator(LLMUserContextAggregator): class LLMUserResponseAggregator(LLMUserContextAggregator):
def __init__( def __init__(
self, self,
messages: List[dict] = [], messages: Optional[List[dict]] = None,
*, *,
params: LLMUserAggregatorParams = LLMUserAggregatorParams(), params: Optional[LLMUserAggregatorParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs) super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs)
@@ -662,9 +662,9 @@ class LLMUserResponseAggregator(LLMUserContextAggregator):
class LLMAssistantResponseAggregator(LLMAssistantContextAggregator): class LLMAssistantResponseAggregator(LLMAssistantContextAggregator):
def __init__( def __init__(
self, self,
messages: List[dict] = [], messages: Optional[List[dict]] = None,
*, *,
params: LLMAssistantAggregatorParams = LLMAssistantAggregatorParams(), params: Optional[LLMAssistantAggregatorParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs) super().__init__(context=OpenAILLMContext(messages), params=params, **kwargs)

View File

@@ -7,6 +7,7 @@
import re import re
import time import time
from enum import Enum from enum import Enum
from typing import List
from loguru import logger from loguru import logger
@@ -31,7 +32,7 @@ class WakeCheckFilter(FrameProcessor):
self.wake_timer = 0.0 self.wake_timer = 0.0
self.accumulator = "" self.accumulator = ""
def __init__(self, wake_phrases: list[str], keepalive_timeout: float = 3): def __init__(self, wake_phrases: List[str], keepalive_timeout: float = 3):
super().__init__() super().__init__()
self._participant_states = {} self._participant_states = {}
self._keepalive_timeout = keepalive_timeout self._keepalive_timeout = keepalive_timeout

View File

@@ -22,7 +22,7 @@ class WakeNotifierFilter(FrameProcessor):
self, self,
notifier: BaseNotifier, notifier: BaseNotifier,
*, *,
types: Tuple[Type[Frame]], types: Tuple[Type[Frame], ...],
filter: Callable[[Frame], Awaitable[bool]], filter: Callable[[Frame], Awaitable[bool]],
**kwargs, **kwargs,
): ):

View File

@@ -437,10 +437,10 @@ class RTVIObserver(BaseObserver):
params (RTVIObserverParams): Settings to enable/disable specific messages. params (RTVIObserverParams): Settings to enable/disable specific messages.
""" """
def __init__(self, rtvi: "RTVIProcessor", *, params: RTVIObserverParams = RTVIObserverParams()): def __init__(self, rtvi: "RTVIProcessor", *, params: Optional[RTVIObserverParams] = None):
super().__init__() super().__init__()
self._rtvi = rtvi self._rtvi = rtvi
self._params = params self._params = params or RTVIObserverParams()
self._bot_transcription = "" self._bot_transcription = ""
self._frames_seen = set() self._frames_seen = set()
rtvi.set_errors_enabled(self._params.errors_enabled) rtvi.set_errors_enabled(self._params.errors_enabled)
@@ -632,12 +632,12 @@ class RTVIProcessor(FrameProcessor):
def __init__( def __init__(
self, self,
*, *,
config: RTVIConfig = RTVIConfig(config=[]), config: Optional[RTVIConfig] = None,
transport: Optional[BaseTransport] = None, transport: Optional[BaseTransport] = None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
self._config = config self._config = config or RTVIConfig(config=[])
self._bot_ready = False self._bot_ready = False
self._client_ready = False self._client_ready = False

View File

@@ -43,10 +43,10 @@ class GStreamerPipelineSource(FrameProcessor):
audio_channels: int = 1 audio_channels: int = 1
clock_sync: bool = True clock_sync: bool = True
def __init__(self, *, pipeline: str, out_params: OutputParams = OutputParams(), **kwargs): def __init__(self, *, pipeline: str, out_params: Optional[OutputParams] = None, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self._out_params = out_params self._out_params = out_params or GStreamerPipelineSource.OutputParams()
self._sample_rate = 0 self._sample_rate = 0
Gst.init() Gst.init()

View File

@@ -5,7 +5,7 @@
# #
import asyncio import asyncio
from typing import Awaitable, Callable, List from typing import Awaitable, Callable, List, Optional
from pipecat.frames.frames import Frame, StartFrame from pipecat.frames.frames import Frame, StartFrame
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
@@ -22,14 +22,14 @@ class IdleFrameProcessor(FrameProcessor):
*, *,
callback: Callable[["IdleFrameProcessor"], Awaitable[None]], callback: Callable[["IdleFrameProcessor"], Awaitable[None]],
timeout: float, timeout: float,
types: List[type] = [], types: Optional[List[type]] = None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
self._callback = callback self._callback = callback
self._timeout = timeout self._timeout = timeout
self._types = types self._types = types or []
self._idle_task = None self._idle_task = None
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):

View File

@@ -4,11 +4,17 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
from typing import Optional from typing import Optional, Tuple, Type
from loguru import logger from loguru import logger
from pipecat.frames.frames import AudioRawFrame, BotSpeakingFrame, Frame, TransportMessageFrame from pipecat.frames.frames import (
BotSpeakingFrame,
Frame,
InputAudioRawFrame,
OutputAudioRawFrame,
TransportMessageFrame,
)
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
logger = logger.opt(ansi=True) logger = logger.opt(ansi=True)
@@ -19,16 +25,17 @@ class FrameLogger(FrameProcessor):
self, self,
prefix="Frame", prefix="Frame",
color: Optional[str] = None, color: Optional[str] = None,
ignored_frame_types: Optional[list] = [ ignored_frame_types: Tuple[Type[Frame], ...] = (
BotSpeakingFrame, BotSpeakingFrame,
AudioRawFrame, InputAudioRawFrame,
OutputAudioRawFrame,
TransportMessageFrame, TransportMessageFrame,
], ),
): ):
super().__init__() super().__init__()
self._prefix = prefix self._prefix = prefix
self._color = color self._color = color
self._ignored_frame_types = tuple(ignored_frame_types) if ignored_frame_types else None self._ignored_frame_types = ignored_frame_types
async def process_frame(self, frame: Frame, direction: FrameDirection): async def process_frame(self, frame: Frame, direction: FrameDirection):
await super().process_frame(frame, direction) await super().process_frame(frame, direction)

View File

@@ -79,7 +79,7 @@ class TelnyxFrameSerializer(FrameSerializer):
inbound_encoding: str, inbound_encoding: str,
call_control_id: Optional[str] = None, call_control_id: Optional[str] = None,
api_key: Optional[str] = None, api_key: Optional[str] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
): ):
"""Initialize the TelnyxFrameSerializer. """Initialize the TelnyxFrameSerializer.
@@ -92,11 +92,11 @@ class TelnyxFrameSerializer(FrameSerializer):
params: Configuration parameters. params: Configuration parameters.
""" """
self._stream_id = stream_id self._stream_id = stream_id
params.outbound_encoding = outbound_encoding
params.inbound_encoding = inbound_encoding
self._call_control_id = call_control_id self._call_control_id = call_control_id
self._api_key = api_key self._api_key = api_key
self._params = params self._params = params or TelnyxFrameSerializer.InputParams()
self._params.outbound_encoding = outbound_encoding
self._params.inbound_encoding = inbound_encoding
self._telnyx_sample_rate = self._params.telnyx_sample_rate self._telnyx_sample_rate = self._params.telnyx_sample_rate
self._sample_rate = 0 # Pipeline input rate self._sample_rate = 0 # Pipeline input rate

View File

@@ -69,7 +69,7 @@ class TwilioFrameSerializer(FrameSerializer):
call_sid: Optional[str] = None, call_sid: Optional[str] = None,
account_sid: Optional[str] = None, account_sid: Optional[str] = None,
auth_token: Optional[str] = None, auth_token: Optional[str] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
): ):
"""Initialize the TwilioFrameSerializer. """Initialize the TwilioFrameSerializer.
@@ -84,7 +84,7 @@ class TwilioFrameSerializer(FrameSerializer):
self._call_sid = call_sid self._call_sid = call_sid
self._account_sid = account_sid self._account_sid = account_sid
self._auth_token = auth_token self._auth_token = auth_token
self._params = params self._params = params or TwilioFrameSerializer.InputParams()
self._twilio_sample_rate = self._params.twilio_sample_rate self._twilio_sample_rate = self._params.twilio_sample_rate
self._sample_rate = 0 # Pipeline input rate self._sample_rate = 0 # Pipeline input rate

View File

@@ -91,11 +91,12 @@ class AnthropicLLMService(LLMService):
*, *,
api_key: str, api_key: str,
model: str = "claude-3-7-sonnet-20250219", model: str = "claude-3-7-sonnet-20250219",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
client=None, client=None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
params = params or AnthropicLLMService.InputParams()
self._client = client or AsyncAnthropic( self._client = client or AsyncAnthropic(
api_key=api_key api_key=api_key
) # if the client is provided, use it and remove it, otherwise create a new one ) # if the client is provided, use it and remove it, otherwise create a new one

View File

@@ -38,12 +38,13 @@ class AssemblyAISTTService(STTService):
*, *,
api_key: str, api_key: str,
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
encoding: AudioEncoding = AudioEncoding("pcm_s16le"), encoding: Optional[AudioEncoding] = None,
language=Language.EN, # Only English is supported for Realtime language=Language.EN, # Only English is supported for Realtime
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
encoding = encoding or AudioEncoding("pcm_s16le")
aai.settings.api_key = api_key aai.settings.api_key = api_key
self._transcriber: Optional[aai.RealtimeTranscriber] = None self._transcriber: Optional[aai.RealtimeTranscriber] = None

View File

@@ -530,17 +530,19 @@ class AWSBedrockLLMService(LLMService):
def __init__( def __init__(
self, self,
*, *,
model: str,
aws_access_key: Optional[str] = None, aws_access_key: Optional[str] = None,
aws_secret_key: Optional[str] = None, aws_secret_key: Optional[str] = None,
aws_session_token: Optional[str] = None, aws_session_token: Optional[str] = None,
aws_region: str = "us-east-1", aws_region: str = "us-east-1",
model: str, params: Optional[InputParams] = None,
params: InputParams = InputParams(),
client_config: Optional[Config] = None, client_config: Optional[Config] = None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
params = params or AWSBedrockLLMService.InputParams()
# Initialize the AWS Bedrock client # Initialize the AWS Bedrock client
if not client_config: if not client_config:
client_config = Config( client_config = Config(

View File

@@ -125,11 +125,13 @@ class AWSPollyTTSService(TTSService):
region: Optional[str] = None, region: Optional[str] = None,
voice_id: str = "Joanna", voice_id: str = "Joanna",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or AWSPollyTTSService.InputParams()
self._polly_client = boto3.client( self._polly_client = boto3.client(
"polly", "polly",
aws_access_key_id=aws_access_key_id, aws_access_key_id=aws_access_key_id,

View File

@@ -142,7 +142,7 @@ class AWSNovaSonicLLMService(LLMService):
region: str, region: str,
model: str = "amazon.nova-sonic-v1:0", model: str = "amazon.nova-sonic-v1:0",
voice_id: str = "matthew", # matthew, tiffany, amy voice_id: str = "matthew", # matthew, tiffany, amy
params: Params = Params(), params: Optional[Params] = None,
system_instruction: Optional[str] = None, system_instruction: Optional[str] = None,
tools: Optional[ToolsSchema] = None, tools: Optional[ToolsSchema] = None,
send_transcription_frames: bool = True, send_transcription_frames: bool = True,
@@ -155,7 +155,7 @@ class AWSNovaSonicLLMService(LLMService):
self._model = model self._model = model
self._client: Optional[BedrockRuntimeClient] = None self._client: Optional[BedrockRuntimeClient] = None
self._voice_id = voice_id self._voice_id = voice_id
self._params = params self._params = params or Params()
self._system_instruction = system_instruction self._system_instruction = system_instruction
self._tools = tools self._tools = tools
self._send_transcription_frames = send_transcription_frames self._send_transcription_frames = send_transcription_frames

View File

@@ -68,11 +68,13 @@ class AzureBaseTTSService(TTSService):
region: str, region: str,
voice="en-US-SaraNeural", voice="en-US-SaraNeural",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or AzureBaseTTSService.InputParams()
self._settings = { self._settings = {
"emphasis": params.emphasis, "emphasis": params.emphasis,
"language": self.language_to_service_language(params.language) "language": self.language_to_service_language(params.language)

View File

@@ -11,7 +11,7 @@ import warnings
from typing import AsyncGenerator, List, Optional, Union from typing import AsyncGenerator, List, Optional, Union
from loguru import logger from loguru import logger
from pydantic import BaseModel from pydantic import BaseModel, Field
from pipecat.frames.frames import ( from pipecat.frames.frames import (
CancelFrame, CancelFrame,
@@ -90,7 +90,7 @@ class CartesiaTTSService(AudioContextWordTTSService):
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
encoding: str = "pcm_s16le", encoding: str = "pcm_s16le",
container: str = "raw", container: str = "raw",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
text_aggregator: Optional[BaseTextAggregator] = None, text_aggregator: Optional[BaseTextAggregator] = None,
**kwargs, **kwargs,
): ):
@@ -113,6 +113,8 @@ class CartesiaTTSService(AudioContextWordTTSService):
**kwargs, **kwargs,
) )
params = params or CartesiaTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._cartesia_version = cartesia_version self._cartesia_version = cartesia_version
self._url = url self._url = url
@@ -317,7 +319,7 @@ class CartesiaHttpTTSService(TTSService):
class InputParams(BaseModel): class InputParams(BaseModel):
language: Optional[Language] = Language.EN language: Optional[Language] = Language.EN
speed: Optional[Union[str, float]] = "" speed: Optional[Union[str, float]] = ""
emotion: Optional[List[str]] = [] emotion: Optional[List[str]] = Field(default_factory=list)
def __init__( def __init__(
self, self,
@@ -330,11 +332,13 @@ class CartesiaHttpTTSService(TTSService):
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
encoding: str = "pcm_s16le", encoding: str = "pcm_s16le",
container: str = "raw", container: str = "raw",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or CartesiaHttpTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._base_url = base_url self._base_url = base_url
self._cartesia_version = cartesia_version self._cartesia_version = cartesia_version

View File

@@ -184,7 +184,7 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
model: str = "eleven_flash_v2_5", model: str = "eleven_flash_v2_5",
url: str = "wss://api.elevenlabs.io", url: str = "wss://api.elevenlabs.io",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
# Aggregating sentences still gives cleaner-sounding results and fewer # Aggregating sentences still gives cleaner-sounding results and fewer
@@ -210,6 +210,8 @@ class ElevenLabsTTSService(AudioContextWordTTSService):
**kwargs, **kwargs,
) )
params = params or ElevenLabsTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._url = url self._url = url
self._settings = { self._settings = {
@@ -512,7 +514,7 @@ class ElevenLabsHttpTTSService(WordTTSService):
model: str = "eleven_flash_v2_5", model: str = "eleven_flash_v2_5",
base_url: str = "https://api.elevenlabs.io", base_url: str = "https://api.elevenlabs.io",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(
@@ -523,6 +525,8 @@ class ElevenLabsHttpTTSService(WordTTSService):
**kwargs, **kwargs,
) )
params = params or ElevenLabsHttpTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._base_url = base_url self._base_url = base_url
self._params = params self._params = params

View File

@@ -173,7 +173,7 @@ class FalSTTService(SegmentedSTTService):
*, *,
api_key: Optional[str] = None, api_key: Optional[str] = None,
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(
@@ -181,6 +181,8 @@ class FalSTTService(SegmentedSTTService):
**kwargs, **kwargs,
) )
params = params or FalSTTService.InputParams()
if api_key: if api_key:
os.environ["FAL_KEY"] = api_key os.environ["FAL_KEY"] = api_key
elif "FAL_KEY" not in os.environ: elif "FAL_KEY" not in os.environ:

View File

@@ -52,7 +52,7 @@ class FishAudioTTSService(InterruptibleTTSService):
model: str, # This is the reference_id model: str, # This is the reference_id
output_format: FishAudioOutputFormat = "pcm", output_format: FishAudioOutputFormat = "pcm",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(
@@ -62,6 +62,8 @@ class FishAudioTTSService(InterruptibleTTSService):
**kwargs, **kwargs,
) )
params = params or FishAudioTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._base_url = "wss://api.fish.audio/v1/tts/live" self._base_url = "wss://api.fish.audio/v1/tts/live"
self._websocket = None self._websocket = None

View File

@@ -341,11 +341,14 @@ class GeminiMultimodalLiveLLMService(LLMService):
start_video_paused: bool = False, start_video_paused: bool = False,
system_instruction: Optional[str] = None, system_instruction: Optional[str] = None,
tools: Optional[Union[List[dict], ToolsSchema]] = None, tools: Optional[Union[List[dict], ToolsSchema]] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
inference_on_context_initialization: bool = True, inference_on_context_initialization: bool = True,
**kwargs, **kwargs,
): ):
super().__init__(base_url=base_url, **kwargs) super().__init__(base_url=base_url, **kwargs)
params = params or InputParams()
self._last_sent_time = 0 self._last_sent_time = 0
self._api_key = api_key self._api_key = api_key
self._base_url = base_url self._base_url = base_url

View File

@@ -194,7 +194,7 @@ class GladiaSTTService(STTService):
confidence: float = 0.5, confidence: float = 0.5,
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
model: str = "solaria-1", model: str = "solaria-1",
params: GladiaInputParams = GladiaInputParams(), params: Optional[GladiaInputParams] = None,
**kwargs, **kwargs,
): ):
"""Initialize the Gladia STT service. """Initialize the Gladia STT service.
@@ -211,6 +211,8 @@ class GladiaSTTService(STTService):
""" """
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or GladiaInputParams()
# 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( warnings.warn(

View File

@@ -10,7 +10,7 @@ import os
# Suppress gRPC fork warnings # Suppress gRPC fork warnings
os.environ["GRPC_ENABLE_FORK_SUPPORT"] = "false" os.environ["GRPC_ENABLE_FORK_SUPPORT"] = "false"
from typing import AsyncGenerator from typing import AsyncGenerator, Optional
from loguru import logger from loguru import logger
from PIL import Image from PIL import Image
@@ -32,19 +32,19 @@ class GoogleImageGenService(ImageGenService):
class InputParams(BaseModel): class InputParams(BaseModel):
number_of_images: int = Field(default=1, ge=1, le=8) number_of_images: int = Field(default=1, ge=1, le=8)
model: str = Field(default="imagen-3.0-generate-002") model: str = Field(default="imagen-3.0-generate-002")
negative_prompt: str = Field(default=None) negative_prompt: Optional[str] = Field(default=None)
def __init__( def __init__(
self, self,
*, *,
params: InputParams = InputParams(),
api_key: str, api_key: str,
params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
self.set_model_name(params.model) self._params = params or GoogleImageGenService.InputParams()
self._params = params
self._client = genai.Client(api_key=api_key) self._client = genai.Client(api_key=api_key)
self.set_model_name(self._params.model)
def can_generate_metrics(self) -> bool: def can_generate_metrics(self) -> bool:
return True return True

View File

@@ -467,13 +467,16 @@ class GoogleLLMService(LLMService):
*, *,
api_key: str, api_key: str,
model: str = "gemini-2.0-flash", model: str = "gemini-2.0-flash",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
system_instruction: Optional[str] = None, system_instruction: Optional[str] = None,
tools: Optional[List[Dict[str, Any]]] = None, tools: Optional[List[Dict[str, Any]]] = None,
tool_config: Optional[Dict[str, Any]] = None, tool_config: Optional[Dict[str, Any]] = None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
params = params or GoogleLLMService.InputParams()
self.set_model_name(model) self.set_model_name(model)
self._api_key = api_key self._api_key = api_key
self._system_instruction = system_instruction self._system_instruction = system_instruction

View File

@@ -52,7 +52,7 @@ class GoogleVertexLLMService(OpenAILLMService):
credentials: Optional[str] = None, credentials: Optional[str] = None,
credentials_path: Optional[str] = None, credentials_path: Optional[str] = None,
model: str = "google/gemini-2.0-flash-001", model: str = "google/gemini-2.0-flash-001",
params: InputParams = OpenAILLMService.InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
"""Initializes the VertexLLMService. """Initializes the VertexLLMService.
@@ -64,6 +64,7 @@ class GoogleVertexLLMService(OpenAILLMService):
params (InputParams): Vertex AI input parameters. params (InputParams): Vertex AI input parameters.
**kwargs: Additional arguments for OpenAILLMService. **kwargs: Additional arguments for OpenAILLMService.
""" """
params = params or OpenAILLMService.InputParams()
base_url = self._get_base_url(params) base_url = self._get_base_url(params)
self._api_key = self._get_api_token(credentials, credentials_path) self._api_key = self._get_api_token(credentials, credentials_path)

View File

@@ -412,7 +412,7 @@ class GoogleSTTService(STTService):
credentials_path: Optional[str] = None, credentials_path: Optional[str] = None,
location: str = "global", location: str = "global",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
"""Initialize the Google STT service. """Initialize the Google STT service.
@@ -431,6 +431,8 @@ class GoogleSTTService(STTService):
""" """
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or GoogleSTTService.InputParams()
self._location = location self._location = location
self._stream = None self._stream = None
self._config = None self._config = None

View File

@@ -219,11 +219,13 @@ class GoogleTTSService(TTSService):
credentials_path: Optional[str] = None, credentials_path: Optional[str] = None,
voice_id: str = "en-US-Neural2-A", voice_id: str = "en-US-Neural2-A",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or GoogleTTSService.InputParams()
self._settings = { self._settings = {
"pitch": params.pitch, "pitch": params.pitch,
"rate": params.rate, "rate": params.rate,

View File

@@ -34,7 +34,7 @@ class GroqTTSService(TTSService):
*, *,
api_key: str, api_key: str,
output_format: str = "wav", output_format: str = "wav",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
model_name: str = "playai-tts", model_name: str = "playai-tts",
voice_id: str = "Celeste-PlayAI", voice_id: str = "Celeste-PlayAI",
sample_rate: Optional[int] = GROQ_SAMPLE_RATE, sample_rate: Optional[int] = GROQ_SAMPLE_RATE,
@@ -42,12 +42,15 @@ class GroqTTSService(TTSService):
): ):
if sample_rate != self.GROQ_SAMPLE_RATE: if sample_rate != self.GROQ_SAMPLE_RATE:
logger.warning(f"Groq TTS only supports {self.GROQ_SAMPLE_RATE}Hz sample rate. ") logger.warning(f"Groq TTS only supports {self.GROQ_SAMPLE_RATE}Hz sample rate. ")
super().__init__( super().__init__(
pause_frame_processing=True, pause_frame_processing=True,
sample_rate=sample_rate, sample_rate=sample_rate,
**kwargs, **kwargs,
) )
params = params or GroqTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._model_name = model_name self._model_name = model_name
self._output_format = output_format self._output_format = output_format

View File

@@ -4,7 +4,7 @@
# SPDX-License-Identifier: BSD 2-Clause License # SPDX-License-Identifier: BSD 2-Clause License
# #
from typing import Any, Dict, List from typing import Any, Dict, List, Optional
from loguru import logger from loguru import logger
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
@@ -49,16 +49,19 @@ class Mem0MemoryService(FrameProcessor):
def __init__( def __init__(
self, self,
*, *,
api_key: str = None, api_key: Optional[str] = None,
local_config: Dict[str, Any] = {}, local_config: Optional[Dict[str, Any]] = None,
user_id: str = None, user_id: Optional[str] = None,
agent_id: str = None, agent_id: Optional[str] = None,
run_id: str = None, run_id: Optional[str] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
): ):
# Important: Call the parent class __init__ first # Important: Call the parent class __init__ first
super().__init__() super().__init__()
local_config = local_config or {}
params = params or Mem0MemoryService.InputParams()
if local_config: if local_config:
self.memory_client = Memory.from_config(local_config) self.memory_client = Memory.from_config(local_config)
else: else:

View File

@@ -114,11 +114,13 @@ class MiniMaxHttpTTSService(TTSService):
voice_id: str = "Calm_Woman", voice_id: str = "Calm_Woman",
aiohttp_session: aiohttp.ClientSession, aiohttp_session: aiohttp.ClientSession,
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or MiniMaxHttpTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._group_id = group_id self._group_id = group_id
self._base_url = f"https://api.minimaxi.chat/v1/t2a_v2?GroupId={group_id}" self._base_url = f"https://api.minimaxi.chat/v1/t2a_v2?GroupId={group_id}"

View File

@@ -80,7 +80,7 @@ class NeuphonicTTSService(InterruptibleTTSService):
url: str = "wss://api.neuphonic.com", url: str = "wss://api.neuphonic.com",
sample_rate: Optional[int] = 22050, sample_rate: Optional[int] = 22050,
encoding: str = "pcm_linear", encoding: str = "pcm_linear",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(
@@ -92,6 +92,8 @@ class NeuphonicTTSService(InterruptibleTTSService):
**kwargs, **kwargs,
) )
params = params or NeuphonicTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._url = url self._url = url
self._settings = { self._settings = {
@@ -293,11 +295,13 @@ class NeuphonicHttpTTSService(TTSService):
url: str = "https://api.neuphonic.com", url: str = "https://api.neuphonic.com",
sample_rate: Optional[int] = 22050, sample_rate: Optional[int] = 22050,
encoding: str = "pcm_linear", encoding: str = "pcm_linear",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or NeuphonicHttpTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._url = url self._url = url
self._settings = { self._settings = {

View File

@@ -77,11 +77,14 @@ class BaseOpenAILLMService(LLMService):
base_url=None, base_url=None,
organization=None, organization=None,
project=None, project=None,
default_headers: Mapping[str, str] | None = None, default_headers: Optional[Mapping[str, str]] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(**kwargs) super().__init__(**kwargs)
params = params or BaseOpenAILLMService.InputParams()
self._settings = { self._settings = {
"frequency_penalty": params.frequency_penalty, "frequency_penalty": params.frequency_penalty,
"presence_penalty": params.presence_penalty, "presence_penalty": params.presence_penalty,

View File

@@ -6,7 +6,7 @@
import json import json
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any from typing import Any, Optional
from pipecat.frames.frames import ( from pipecat.frames.frames import (
FunctionCallCancelFrame, FunctionCallCancelFrame,
@@ -41,7 +41,7 @@ class OpenAILLMService(BaseOpenAILLMService):
self, self,
*, *,
model: str = "gpt-4.1", model: str = "gpt-4.1",
params: BaseOpenAILLMService.InputParams = BaseOpenAILLMService.InputParams(), params: Optional[BaseOpenAILLMService.InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(model=model, params=params, **kwargs) super().__init__(model=model, params=params, **kwargs)

View File

@@ -8,6 +8,7 @@ import base64
import json import json
import time import time
from dataclasses import dataclass from dataclasses import dataclass
from typing import Optional
from loguru import logger from loguru import logger
@@ -89,17 +90,20 @@ class OpenAIRealtimeBetaLLMService(LLMService):
api_key: str, api_key: str,
model: str = "gpt-4o-realtime-preview-2024-12-17", model: str = "gpt-4o-realtime-preview-2024-12-17",
base_url: str = "wss://api.openai.com/v1/realtime", base_url: str = "wss://api.openai.com/v1/realtime",
session_properties: events.SessionProperties = events.SessionProperties(), session_properties: Optional[events.SessionProperties] = None,
start_audio_paused: bool = False, start_audio_paused: bool = False,
send_transcription_frames: bool = True, send_transcription_frames: bool = True,
**kwargs, **kwargs,
): ):
full_url = f"{base_url}?model={model}" full_url = f"{base_url}?model={model}"
super().__init__(base_url=full_url, **kwargs) super().__init__(base_url=full_url, **kwargs)
self.api_key = api_key self.api_key = api_key
self.base_url = full_url self.base_url = full_url
self._session_properties: events.SessionProperties = session_properties self._session_properties: events.SessionProperties = (
session_properties or events.SessionProperties()
)
self._audio_input_paused = start_audio_paused self._audio_input_paused = start_audio_paused
self._send_transcription_frames = send_transcription_frames self._send_transcription_frames = send_transcription_frames
self._websocket = None self._websocket = None

View File

@@ -110,7 +110,7 @@ class PlayHTTTSService(InterruptibleTTSService):
voice_engine: str = "Play3.0-mini", voice_engine: str = "Play3.0-mini",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
output_format: str = "wav", output_format: str = "wav",
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(
@@ -119,6 +119,8 @@ class PlayHTTTSService(InterruptibleTTSService):
**kwargs, **kwargs,
) )
params = params or PlayHTTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._user_id = user_id self._user_id = user_id
self._websocket_url = None self._websocket_url = None
@@ -328,11 +330,13 @@ class PlayHTHttpTTSService(TTSService):
voice_engine: str = "Play3.0-mini", voice_engine: str = "Play3.0-mini",
protocol: str = "http", # Options: http, ws protocol: str = "http", # Options: http, ws
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or PlayHTHttpTTSService.InputParams()
self._user_id = user_id self._user_id = user_id
self._api_key = api_key self._api_key = api_key

View File

@@ -80,7 +80,7 @@ class RimeTTSService(AudioContextWordTTSService):
url: str = "wss://users.rime.ai/ws2", url: str = "wss://users.rime.ai/ws2",
model: str = "mistv2", model: str = "mistv2",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
text_aggregator: Optional[BaseTextAggregator] = None, text_aggregator: Optional[BaseTextAggregator] = None,
**kwargs, **kwargs,
): ):
@@ -105,6 +105,8 @@ class RimeTTSService(AudioContextWordTTSService):
**kwargs, **kwargs,
) )
params = params or RimeTTSService.InputParams()
# Store service configuration # Store service configuration
self._api_key = api_key self._api_key = api_key
self._url = url self._url = url
@@ -364,11 +366,13 @@ class RimeHttpTTSService(TTSService):
aiohttp_session: aiohttp.ClientSession, aiohttp_session: aiohttp.ClientSession,
model: str = "mistv2", model: str = "mistv2",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or RimeHttpTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._session = aiohttp_session self._session = aiohttp_session
self._base_url = "https://users.rime.ai/v1/rime-tts" self._base_url = "https://users.rime.ai/v1/rime-tts"

View File

@@ -99,10 +99,13 @@ class RivaSTTService(STTService):
"model_name": "parakeet-ctc-1.1b-asr", "model_name": "parakeet-ctc-1.1b-asr",
}, },
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or RivaSTTService.InputParams()
self._api_key = api_key self._api_key = api_key
self._profanity_filter = False self._profanity_filter = False
self._automatic_punctuation = True self._automatic_punctuation = True
@@ -322,11 +325,13 @@ class RivaSegmentedSTTService(SegmentedSTTService):
"model_name": "canary-1b-asr", "model_name": "canary-1b-asr",
}, },
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or RivaSegmentedSTTService.InputParams()
# Set model name # Set model name
self.set_model_name(model_function_map.get("model_name")) self.set_model_name(model_function_map.get("model_name"))
@@ -533,7 +538,7 @@ class ParakeetSTTService(RivaSTTService):
"model_name": "parakeet-ctc-1.1b-asr", "model_name": "parakeet-ctc-1.1b-asr",
}, },
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
params: RivaSTTService.InputParams = RivaSTTService.InputParams(), # Use parent class's type params: Optional[RivaSTTService.InputParams] = None, # Use parent class's type
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(

View File

@@ -44,7 +44,7 @@ class RivaTTSService(TTSService):
def __init__( def __init__(
self, self,
*, *,
api_key: str = None, api_key: str,
server: str = "grpc.nvcf.nvidia.com:443", server: str = "grpc.nvcf.nvidia.com:443",
voice_id: str = "Magpie-Multilingual.EN-US.Ray", voice_id: str = "Magpie-Multilingual.EN-US.Ray",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
@@ -52,10 +52,13 @@ class RivaTTSService(TTSService):
"function_id": "877104f7-e885-42b9-8de8-f6e4c6303969", "function_id": "877104f7-e885-42b9-8de8-f6e4c6303969",
"model_name": "magpie-tts-multilingual", "model_name": "magpie-tts-multilingual",
}, },
params: InputParams = InputParams(), params: Optional[InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__(sample_rate=sample_rate, **kwargs) super().__init__(sample_rate=sample_rate, **kwargs)
params = params or RivaTTSService.InputParams()
self._api_key = api_key self._api_key = api_key
self._voice_id = voice_id self._voice_id = voice_id
self._language_code = params.language self._language_code = params.language
@@ -136,14 +139,10 @@ class RivaTTSService(TTSService):
class FastPitchTTSService(RivaTTSService): class FastPitchTTSService(RivaTTSService):
class InputParams(BaseModel):
language: Optional[Language] = Language.EN_US
quality: Optional[int] = 20
def __init__( def __init__(
self, self,
*, *,
api_key: str = None, api_key: str,
server: str = "grpc.nvcf.nvidia.com:443", server: str = "grpc.nvcf.nvidia.com:443",
voice_id: str = "English-US.Female-1", voice_id: str = "English-US.Female-1",
sample_rate: Optional[int] = None, sample_rate: Optional[int] = None,
@@ -151,11 +150,12 @@ class FastPitchTTSService(RivaTTSService):
"function_id": "0149dedb-2be8-4195-b9a0-e57e0e14f972", "function_id": "0149dedb-2be8-4195-b9a0-e57e0e14f972",
"model_name": "fastpitch-hifigan-tts", "model_name": "fastpitch-hifigan-tts",
}, },
params: InputParams = InputParams(), params: Optional[RivaTTSService.InputParams] = None,
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(
api_key=api_key, api_key=api_key,
server=server,
voice_id=voice_id, voice_id=voice_id,
sample_rate=sample_rate, sample_rate=sample_rate,
model_function_map=model_function_map, model_function_map=model_function_map,

View File

@@ -64,7 +64,7 @@ class TTSService(AIService):
# Text aggregator to aggregate incoming tokens and decide when to push to the TTS. # Text aggregator to aggregate incoming tokens and decide when to push to the TTS.
text_aggregator: Optional[BaseTextAggregator] = None, text_aggregator: Optional[BaseTextAggregator] = None,
# Text filter executed after text has been aggregated. # Text filter executed after text has been aggregated.
text_filters: Sequence[BaseTextFilter] = [], text_filters: Optional[Sequence[BaseTextFilter]] = None,
text_filter: Optional[BaseTextFilter] = None, text_filter: Optional[BaseTextFilter] = None,
# Audio transport destination of the generated frames. # Audio transport destination of the generated frames.
transport_destination: Optional[str] = None, transport_destination: Optional[str] = None,
@@ -83,7 +83,7 @@ class TTSService(AIService):
self._voice_id: str = "" self._voice_id: str = ""
self._settings: Dict[str, Any] = {} self._settings: Dict[str, Any] = {}
self._text_aggregator: BaseTextAggregator = text_aggregator or SimpleTextAggregator() self._text_aggregator: BaseTextAggregator = text_aggregator or SimpleTextAggregator()
self._text_filters: Sequence[BaseTextFilter] = text_filters self._text_filters: Sequence[BaseTextFilter] = text_filters or []
self._transport_destination: Optional[str] = transport_destination self._transport_destination: Optional[str] = transport_destination
if text_filter: if text_filter:

View File

@@ -79,10 +79,13 @@ async def run_test(
expected_down_frames: Optional[Sequence[type]] = None, expected_down_frames: Optional[Sequence[type]] = None,
expected_up_frames: Optional[Sequence[type]] = None, expected_up_frames: Optional[Sequence[type]] = None,
ignore_start: bool = True, ignore_start: bool = True,
observers: List[BaseObserver] = [], observers: Optional[List[BaseObserver]] = None,
start_metadata: Dict[str, Any] = {}, start_metadata: Optional[Dict[str, Any]] = None,
send_end_frame: bool = True, send_end_frame: bool = True,
) -> Tuple[Sequence[Frame], Sequence[Frame]]: ) -> Tuple[Sequence[Frame], Sequence[Frame]]:
observers = observers or []
start_metadata = start_metadata or {}
received_up = asyncio.Queue() received_up = asyncio.Queue()
received_down = asyncio.Queue() received_down = asyncio.Queue()
source = QueuedFrameProcessor( source = QueuedFrameProcessor(

View File

@@ -250,11 +250,11 @@ class WebsocketClientTransport(BaseTransport):
def __init__( def __init__(
self, self,
uri: str, uri: str,
params: WebsocketClientParams = WebsocketClientParams(), params: Optional[WebsocketClientParams] = None,
): ):
super().__init__() super().__init__()
self._params = params self._params = params or WebsocketClientParams()
callbacks = WebsocketClientCallbacks( callbacks = WebsocketClientCallbacks(
on_connected=self._on_connected, on_connected=self._on_connected,
@@ -262,7 +262,7 @@ class WebsocketClientTransport(BaseTransport):
on_message=self._on_message, on_message=self._on_message,
) )
self._session = WebsocketClientSession(uri, params, callbacks, self.name) self._session = WebsocketClientSession(uri, self._params, callbacks, self.name)
self._input: Optional[WebsocketClientInputTransport] = None self._input: Optional[WebsocketClientInputTransport] = None
self._output: Optional[WebsocketClientOutputTransport] = None self._output: Optional[WebsocketClientOutputTransport] = None

View File

@@ -95,7 +95,7 @@ class WebRTCVADAnalyzer(VADAnalyzer):
params: VAD configuration parameters (VADParams). params: VAD configuration parameters (VADParams).
""" """
def __init__(self, *, sample_rate: Optional[int] = None, params: VADParams = VADParams()): def __init__(self, *, sample_rate: Optional[int] = None, params: Optional[VADParams] = None):
super().__init__(sample_rate=sample_rate, params=params) super().__init__(sample_rate=sample_rate, params=params)
self._webrtc_vad = Daily.create_native_vad( self._webrtc_vad = Daily.create_native_vad(
@@ -1223,7 +1223,7 @@ class DailyTransport(BaseTransport):
room_url: str, room_url: str,
token: Optional[str], token: Optional[str],
bot_name: str, bot_name: str,
params: DailyParams = DailyParams(), params: Optional[DailyParams] = None,
input_name: Optional[str] = None, input_name: Optional[str] = None,
output_name: Optional[str] = None, output_name: Optional[str] = None,
): ):
@@ -1256,9 +1256,11 @@ class DailyTransport(BaseTransport):
on_recording_stopped=self._on_recording_stopped, on_recording_stopped=self._on_recording_stopped,
on_recording_error=self._on_recording_error, on_recording_error=self._on_recording_error,
) )
self._params = params self._params = params or DailyParams()
self._client = DailyTransportClient(room_url, token, bot_name, params, callbacks, self.name) self._client = DailyTransportClient(
room_url, token, bot_name, self._params, callbacks, self.name
)
self._input: Optional[DailyInputTransport] = None self._input: Optional[DailyInputTransport] = None
self._output: Optional[DailyOutputTransport] = None self._output: Optional[DailyOutputTransport] = None

View File

@@ -499,7 +499,7 @@ class LiveKitTransport(BaseTransport):
url: str, url: str,
token: str, token: str,
room_name: str, room_name: str,
params: LiveKitParams = LiveKitParams(), params: Optional[LiveKitParams] = None,
input_name: Optional[str] = None, input_name: Optional[str] = None,
output_name: Optional[str] = None, output_name: Optional[str] = None,
): ):
@@ -515,7 +515,7 @@ class LiveKitTransport(BaseTransport):
on_data_received=self._on_data_received, on_data_received=self._on_data_received,
on_first_participant_joined=self._on_first_participant_joined, on_first_participant_joined=self._on_first_participant_joined,
) )
self._params = params self._params = params or LiveKitParams()
self._client = LiveKitTransportClient( self._client = LiveKitTransportClient(
url, token, room_name, self._params, callbacks, self.name url, token, room_name, self._params, callbacks, self.name

View File

@@ -26,9 +26,9 @@ class MarkdownTextFilter(BaseTextFilter):
filter_code: Optional[bool] = False filter_code: Optional[bool] = False
filter_tables: Optional[bool] = False filter_tables: Optional[bool] = False
def __init__(self, params: InputParams = InputParams(), **kwargs): def __init__(self, params: Optional[InputParams] = None, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self._settings = params self._settings = params or MarkdownTextFilter.InputParams()
self._in_code_block = False self._in_code_block = False
self._in_table = False self._in_table = False
self._interrupted = False self._interrupted = False