polite-oil-10264
08/04/2025, 3:30 AMtall-airline-16756
08/04/2025, 3:30 AMtall-airline-16756
08/04/2025, 3:31 AMbefore_tts_cb (before text-to-speech callback) feature. This allows you to modify the text before it is sent to the TTS model. For example, you can use regular expressions to remove numbers from the input text:
from livekit.agents import tokenize
from livekit.agents.pipeline import VoicePipelineAgent
def skip_numbers_and_words(assistant: VoicePipelineAgent, text: str | AsyncIterable[str]):
# Replace numbers with an empty string
modified_text = tokenize.utils.replace_words(
text=text,
replacements={r"\d+": ""} # Regular expression to match numbers
)
return modified_text
agent = VoicePipelineAgent(
...
before_tts_cb=skip_numbers_and_words,
)
You can also create custom text processing logic to remove specific patterns or words before sending the text to the TTS model. If you need further assistance or have a specific use case, let me know!
Sources: Speechify TTS integration guide | LiveKit Docspolite-oil-10264
08/04/2025, 3:33 AMtall-airline-16756
08/04/2025, 3:34 AMbefore_tts_cb callback for a more flexible tts_node system. This gives you the power to tweak the TTS pipeline by adjusting the text before it gets synthesized. Here’s a friendly example to show you how you can skip certain words or numbers:
async def skip_words_tts_node(text: str | AsyncIterable[str]) -> str | AsyncIterable[str]:
if isinstance(text, str):
# Skip specific words or numbers in non-streaming text
return text.replace("specific_word", "").replace("123", "")
else:
# Skip specific words or numbers in streaming text
async def process_stream():
async for chunk in text:
processed_chunk = chunk.replace("specific_word", "").replace("123", "")
yield processed_chunk
return process_stream()
agent = VoicePipelineAgent(
vad=silero.VAD.load(),
stt=openai.STT(),
llm=openai.LLM(),
tts=openai.TTS(),
tts_node=skip_words_tts_node, # Add your TTS node callback here
)
This setup works great with both non-streaming and streaming text inputs. If you want me to walk you through it more or need extra examples, just let me know—I’m here to help!polite-oil-10264
08/04/2025, 3:49 AMtall-airline-16756
08/04/2025, 3:49 AMtts_node logic to spot any errors in how text or audio is being processed.
Here are a few friendly tips to help you troubleshoot:
1. Make sure the skip_numbers_and_symbols function is implemented correctly and isn’t causing any unexpected errors.
2. Check that your TTS provider (like Cartesia) supports the model, voice, and language settings you’ve chosen.
3. Look out for any extra error logs or stack traces—they often give helpful clues about what’s going wrong.
4. Try wrapping your custom tts_node logic in a try-except block to catch and log any surprises during execution.
If you’d like, feel free to share more details about the error or how skip_numbers_and_symbols is set up—I’m here to help you get this sorted out!polite-oil-10264
08/04/2025, 3:50 AMtall-airline-16756
08/04/2025, 3:51 AMimport re
def remove_numbers(text):
"""Remove all digits from the text."""
return re.sub(r'\d+', '', text)
text = "Please send $100 to account 12345."
filtered_text = remove_numbers(text)
After you’ve taken out the numbers, just pass the cleaned-up text to the Cartesia TTS plugin in LiveKit like this:
from livekit.plugins import cartesia
import asyncio
async def main():
tts = cartesia.TTS(model="sonic-2", voice="8832a0b5-47b2-4751-bb22-6a8e2149303d", language="fr")
# Process the text to remove numbers
text = "Please send $100 to account 12345."
filtered_text = remove_numbers(text)
# Send the processed text to TTS
stream = tts.stream()
await stream.push_text(filtered_text)
await stream.flush()
await stream.end_input()
asyncio.run(main())
This way, the TTS will smoothly skip over any numbers when speaking. If you have any questions or need a hand with anything else, just give me a shout!polite-oil-10264
08/04/2025, 3:53 AMtall-airline-16756
08/04/2025, 3:54 AMimport re
from typing import AsyncIterable
async def skip_numbers_and_symbols(text_stream: AsyncIterable[str]) -> AsyncIterable[str]:
"""Filters out numbers and special characters from the TTS streaming output."""
async for chunk in text_stream:
# Remove numbers and special characters, keeping letters, spaces, and accented characters
cleaned = re.sub(r"[\d\|]+|[^\w\sÀ-ÿ]", "", chunk)
yield cleaned
# Example usage in your agent setup
from livekit.plugins import cartesia
from livekit.agents.pipeline import VoicePipelineAgent
from livekit.plugins import deepgram, groq
agent = VoicePipelineAgent(
stt=deepgram.STT(model="nova-2-general", language="fr"),
llm=groq.LLM(model="llama3-8b-8192"),
tts=cartesia.TTS(model="sonic-2", voice="8832a0b5-47b2-4751-bb22-6a8e2149303d", language="fr"),
turn_detection=MultilingualModel(),
tts_node=skip_numbers_and_symbols, # Use the updated TTS node here
)
This way, your TTS output will keep the letters, spaces, and accented characters, but filter out those pesky numbers and special symbols. If you want me to tweak anything else or if you have questions, just let me know—I'm here to help!polite-oil-10264
08/04/2025, 3:55 AMtall-airline-16756
08/04/2025, 3:55 AMAgent class in the latest LiveKit version doesn’t take a tts_node parameter directly. But no worries—you can still use a custom TTS node by subclassing Agent and overriding the tts_node method. Here’s a quick example to help you out:
from livekit.agents import Agent, AgentSession
from livekit.agents.voice import ModelSettings
class CustomTtsAgent(Agent):
async def tts_node(self, text: AsyncIterable[str], model_settings: ModelSettings):
"""Override default TTS node behavior"""
async for chunk in text:
# Example: Remove numbers and special characters
cleaned = re.sub(r"[\d\|]+|[^\w\sÀ-ÿ]", "", chunk)
yield cleaned
async def entrypoint(ctx: JobContext):
session = AgentSession()
await session.start(
agent=CustomTtsAgent(
instructions="Your agent instructions here",
tts=cartesia.TTS(model="sonic-2", voice="8832a0b5-47b2-4751-bb22-6a8e2149303d", language="fr"),
),
room=ctx.room
)
This way, your custom TTS logic fits right in and keeps everything working smoothly with the latest LiveKit version. If you want me to walk you through anything else or have more questions, just let me know—I’m here to help!
Sources: livekit-agents/livekit/agents/voice/agent.py | pipeline-tts/short_replies_only.py