Remove deprecated text_aggregator and text_filter params from TTS
Remove the deprecated text_aggregator parameter from TTSService, CartesiaTTSService, and RimeTTSService, and the deprecated text_filter parameter from TTSService. Users should use LLMTextProcessor before the TTS service instead. Update the voice-switching example to use LLMTextProcessor with PatternPairAggregator.
This commit is contained in:
@@ -45,7 +45,7 @@ from dotenv import load_dotenv
|
||||
from loguru import logger
|
||||
|
||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||
from pipecat.frames.frames import LLMRunFrame
|
||||
from pipecat.frames.frames import LLMRunFrame, TTSUpdateSettingsFrame
|
||||
from pipecat.pipeline.pipeline import Pipeline
|
||||
from pipecat.pipeline.runner import PipelineRunner
|
||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||
@@ -54,6 +54,7 @@ from pipecat.processors.aggregators.llm_response_universal import (
|
||||
LLMContextAggregatorPair,
|
||||
LLMUserAggregatorParams,
|
||||
)
|
||||
from pipecat.processors.aggregators.llm_text_processor import LLMTextProcessor
|
||||
from pipecat.runner.types import RunnerArguments
|
||||
from pipecat.runner.utils import create_transport
|
||||
from pipecat.services.cartesia.tts import CartesiaTTSService
|
||||
@@ -100,39 +101,43 @@ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
|
||||
logger.info(f"Starting bot")
|
||||
|
||||
# Create pattern pair aggregator for voice switching
|
||||
pattern_aggregator = PatternPairAggregator()
|
||||
llm_text_aggregator = PatternPairAggregator()
|
||||
|
||||
# Add pattern for voice switching
|
||||
pattern_aggregator.add_pattern(
|
||||
llm_text_aggregator.add_pattern(
|
||||
type="voice",
|
||||
start_pattern="<voice>",
|
||||
end_pattern="</voice>",
|
||||
action=MatchAction.REMOVE, # Remove tags from final text
|
||||
action=MatchAction.AGGREGATE,
|
||||
)
|
||||
|
||||
# Register handler for voice switching
|
||||
async def on_voice_tag(match: PatternMatch):
|
||||
voice_name = match.text.strip().lower()
|
||||
if voice_name in VOICE_IDS:
|
||||
# First flush any existing audio to finish the current context
|
||||
await tts.flush_audio()
|
||||
# Then set the new voice
|
||||
await tts.set_voice(VOICE_IDS[voice_name])
|
||||
await llm_text_processor.push_frame(
|
||||
TTSUpdateSettingsFrame(
|
||||
delta=CartesiaTTSService.Settings(voice=VOICE_IDS[voice_name])
|
||||
)
|
||||
)
|
||||
logger.info(f"Switched to {voice_name} voice")
|
||||
else:
|
||||
logger.warning(f"Unknown voice: {voice_name}")
|
||||
|
||||
pattern_aggregator.on_pattern_match("voice", on_voice_tag)
|
||||
llm_text_aggregator.on_pattern_match("voice", on_voice_tag)
|
||||
|
||||
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
||||
|
||||
# Process LLM text through the pattern aggregator before TTS
|
||||
llm_text_processor = LLMTextProcessor(text_aggregator=llm_text_aggregator)
|
||||
|
||||
# Initialize TTS with narrator voice as default
|
||||
tts = CartesiaTTSService(
|
||||
api_key=os.getenv("CARTESIA_API_KEY"),
|
||||
settings=CartesiaTTSService.Settings(
|
||||
voice=VOICE_IDS["narrator"],
|
||||
),
|
||||
text_aggregator=pattern_aggregator,
|
||||
skip_aggregator_types=["voice"], # Skip voice tags in TTS speech
|
||||
)
|
||||
|
||||
# System prompt for storytelling with voice switching
|
||||
@@ -204,7 +209,8 @@ Remember: Use narrator voice for EVERYTHING except the actual quoted dialogue.""
|
||||
stt,
|
||||
user_aggregator,
|
||||
llm,
|
||||
tts, # TTS with pattern aggregator
|
||||
llm_text_processor,
|
||||
tts,
|
||||
transport.output(),
|
||||
assistant_aggregator,
|
||||
]
|
||||
|
||||
@@ -28,7 +28,6 @@ from pipecat.frames.frames import (
|
||||
from pipecat.services.settings import NOT_GIVEN, TTSSettings, _NotGiven
|
||||
from pipecat.services.tts_service import TextAggregationMode, TTSService, WebsocketTTSService
|
||||
from pipecat.transcriptions.language import Language, resolve_language
|
||||
from pipecat.utils.text.base_text_aggregator import BaseTextAggregator
|
||||
from pipecat.utils.text.skip_tags_aggregator import SkipTagsAggregator
|
||||
from pipecat.utils.tracing.service_decorators import traced_tts
|
||||
|
||||
@@ -240,7 +239,6 @@ class CartesiaTTSService(WebsocketTTSService):
|
||||
container: str = "raw",
|
||||
params: Optional[InputParams] = None,
|
||||
settings: Optional[Settings] = None,
|
||||
text_aggregator: Optional[BaseTextAggregator] = None,
|
||||
text_aggregation_mode: Optional[TextAggregationMode] = None,
|
||||
aggregate_sentences: Optional[bool] = None,
|
||||
**kwargs,
|
||||
@@ -271,11 +269,6 @@ class CartesiaTTSService(WebsocketTTSService):
|
||||
|
||||
settings: Runtime-updatable settings. When provided alongside deprecated
|
||||
parameters, ``settings`` values take precedence.
|
||||
text_aggregator: Custom text aggregator for processing input text.
|
||||
|
||||
.. deprecated:: 0.0.95
|
||||
Use an LLMTextProcessor before the TTSService for custom text aggregation.
|
||||
|
||||
text_aggregation_mode: How to aggregate incoming text before synthesis.
|
||||
aggregate_sentences: Whether to aggregate sentences within the TTSService.
|
||||
|
||||
@@ -337,20 +330,18 @@ class CartesiaTTSService(WebsocketTTSService):
|
||||
pause_frame_processing=False,
|
||||
sample_rate=sample_rate,
|
||||
push_start_frame=True,
|
||||
text_aggregator=text_aggregator,
|
||||
settings=default_settings,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
if not text_aggregator:
|
||||
# Always skip tags added for spelled-out text
|
||||
# Note: This is primarily to support backwards compatibility.
|
||||
# The preferred way of taking advantage of Cartesia SSML Tags is
|
||||
# to use an LLMTextProcessor and/or a text_transformer to identify
|
||||
# and insert these tags for the purpose of the TTS service alone.
|
||||
self._text_aggregator = SkipTagsAggregator(
|
||||
[("<spell>", "</spell>")], aggregation_type=self._text_aggregation_mode
|
||||
)
|
||||
# Always skip tags added for spelled-out text
|
||||
# Note: This is primarily to support backwards compatibility.
|
||||
# The preferred way of taking advantage of Cartesia SSML Tags is
|
||||
# to use an LLMTextProcessor and/or a text_transformer to identify
|
||||
# and insert these tags for the purpose of the TTS service alone.
|
||||
self._text_aggregator = SkipTagsAggregator(
|
||||
[("<spell>", "</spell>")], aggregation_type=self._text_aggregation_mode
|
||||
)
|
||||
|
||||
self._api_key = api_key
|
||||
self._cartesia_version = cartesia_version
|
||||
|
||||
@@ -37,7 +37,6 @@ from pipecat.services.tts_service import (
|
||||
WebsocketTTSService,
|
||||
)
|
||||
from pipecat.transcriptions.language import Language, resolve_language
|
||||
from pipecat.utils.text.base_text_aggregator import BaseTextAggregator
|
||||
from pipecat.utils.text.skip_tags_aggregator import SkipTagsAggregator
|
||||
from pipecat.utils.tracing.service_decorators import traced_tts
|
||||
|
||||
@@ -176,7 +175,6 @@ class RimeTTSService(WebsocketTTSService):
|
||||
sample_rate: Optional[int] = None,
|
||||
params: Optional[InputParams] = None,
|
||||
settings: Optional[Settings] = None,
|
||||
text_aggregator: Optional[BaseTextAggregator] = None,
|
||||
text_aggregation_mode: Optional[TextAggregationMode] = None,
|
||||
aggregate_sentences: Optional[bool] = None,
|
||||
**kwargs,
|
||||
@@ -204,11 +202,6 @@ class RimeTTSService(WebsocketTTSService):
|
||||
|
||||
settings: Runtime-updatable settings. When provided alongside deprecated
|
||||
parameters, ``settings`` values take precedence.
|
||||
text_aggregator: Custom text aggregator for processing input text.
|
||||
|
||||
.. deprecated:: 0.0.95
|
||||
Use an LLMTextProcessor before the TTSService for custom text aggregation.
|
||||
|
||||
text_aggregation_mode: How to aggregate incoming text before synthesis.
|
||||
aggregate_sentences: Deprecated. Use text_aggregation_mode instead.
|
||||
|
||||
@@ -282,15 +275,14 @@ class RimeTTSService(WebsocketTTSService):
|
||||
self._audio_format = "pcm"
|
||||
self._sampling_rate = 0 # updated in start()
|
||||
|
||||
if not text_aggregator:
|
||||
# Always skip tags added for spelled-out text
|
||||
# Note: This is primarily to support backwards compatibility.
|
||||
# The preferred way of taking advantage of Rime spelling is
|
||||
# to use an LLMTextProcessor and/or a text_transformer to identify
|
||||
# and insert these tags for the purpose of the TTS service alone.
|
||||
self._text_aggregator = SkipTagsAggregator(
|
||||
[("spell(", ")")], aggregation_type=self._text_aggregation_mode
|
||||
)
|
||||
# Always skip tags added for spelled-out text
|
||||
# Note: This is primarily to support backwards compatibility.
|
||||
# The preferred way of taking advantage of Rime spelling is
|
||||
# to use an LLMTextProcessor and/or a text_transformer to identify
|
||||
# and insert these tags for the purpose of the TTS service alone.
|
||||
self._text_aggregator = SkipTagsAggregator(
|
||||
[("spell(", ")")], aggregation_type=self._text_aggregation_mode
|
||||
)
|
||||
|
||||
# Store service configuration
|
||||
self._api_key = api_key
|
||||
|
||||
@@ -58,7 +58,6 @@ from pipecat.services.ai_service import AIService
|
||||
from pipecat.services.settings import TTSSettings, is_given
|
||||
from pipecat.services.websocket_service import WebsocketService
|
||||
from pipecat.transcriptions.language import Language
|
||||
from pipecat.utils.text.base_text_aggregator import BaseTextAggregator
|
||||
from pipecat.utils.text.base_text_filter import BaseTextFilter
|
||||
from pipecat.utils.text.simple_text_aggregator import SimpleTextAggregator
|
||||
from pipecat.utils.time import seconds_to_nanoseconds
|
||||
@@ -168,8 +167,6 @@ class TTSService(AIService):
|
||||
append_trailing_space: bool = False,
|
||||
# TTS output sample rate
|
||||
sample_rate: Optional[int] = None,
|
||||
# Text aggregator to aggregate incoming tokens and decide when to push to the TTS.
|
||||
text_aggregator: Optional[BaseTextAggregator] = None,
|
||||
# Types of text aggregations that should not be spoken.
|
||||
skip_aggregator_types: Optional[List[str]] = [],
|
||||
# A list of callables to transform text before just before sending it to TTS.
|
||||
@@ -182,7 +179,6 @@ class TTSService(AIService):
|
||||
] = None,
|
||||
# Text filter executed after text has been aggregated.
|
||||
text_filters: Optional[Sequence[BaseTextFilter]] = None,
|
||||
text_filter: Optional[BaseTextFilter] = None,
|
||||
# Audio transport destination of the generated frames.
|
||||
transport_destination: Optional[str] = None,
|
||||
settings: Optional[TTSSettings] = None,
|
||||
@@ -215,11 +211,6 @@ class TTSService(AIService):
|
||||
append_trailing_space: Whether to append a trailing space to text before sending to TTS.
|
||||
This helps prevent some TTS services from vocalizing trailing punctuation (e.g., "dot").
|
||||
sample_rate: Output sample rate for generated audio.
|
||||
text_aggregator: Custom text aggregator for processing incoming text.
|
||||
|
||||
.. deprecated:: 0.0.95
|
||||
Use an LLMTextProcessor before the TTSService for custom text aggregation.
|
||||
|
||||
skip_aggregator_types: List of aggregation types that should not be spoken.
|
||||
text_transforms: A list of callables to transform text before just before sending it
|
||||
to TTS. Each callable takes the aggregated text and its type, and returns the
|
||||
@@ -227,11 +218,6 @@ class TTSService(AIService):
|
||||
(aggregation_type | '*', transform_function).
|
||||
|
||||
text_filters: Sequence of text filters to apply after aggregation.
|
||||
text_filter: Single text filter (deprecated, use text_filters).
|
||||
|
||||
.. deprecated:: 0.0.59
|
||||
Use `text_filters` instead, which allows multiple filters.
|
||||
|
||||
transport_destination: Destination for generated audio frames.
|
||||
settings: The runtime-updatable settings for the TTS service.
|
||||
reuse_context_id_within_turn: Whether the service should reuse context IDs within the
|
||||
@@ -300,18 +286,7 @@ class TTSService(AIService):
|
||||
self._append_trailing_space: bool = append_trailing_space
|
||||
self._init_sample_rate = sample_rate
|
||||
self._sample_rate = 0
|
||||
self._text_aggregator: BaseTextAggregator = text_aggregator or SimpleTextAggregator(
|
||||
aggregation_type=self._text_aggregation_mode
|
||||
)
|
||||
if text_aggregator:
|
||||
import warnings
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("always")
|
||||
warnings.warn(
|
||||
"Parameter 'text_aggregator' is deprecated. Use an LLMTextProcessor before the TTSService for custom text aggregation.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
self._text_aggregator = SimpleTextAggregator(aggregation_type=self._text_aggregation_mode)
|
||||
|
||||
self._skip_aggregator_types: List[str] = skip_aggregator_types or []
|
||||
self._text_transforms: List[
|
||||
@@ -320,16 +295,6 @@ class TTSService(AIService):
|
||||
# TODO: Deprecate _text_filters when added to LLMTextProcessor
|
||||
self._text_filters: Sequence[BaseTextFilter] = text_filters or []
|
||||
self._transport_destination: Optional[str] = transport_destination
|
||||
if text_filter:
|
||||
import warnings
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("always")
|
||||
warnings.warn(
|
||||
"Parameter 'text_filter' is deprecated, use 'text_filters' instead.",
|
||||
DeprecationWarning,
|
||||
)
|
||||
self._text_filters = [text_filter]
|
||||
|
||||
self._resampler = create_stream_resampler()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user