cool-doctor-14149
03/30/2026, 11:57 AMtall-airline-16756
03/30/2026, 11:58 AMtall-airline-16756
03/30/2026, 11:58 AM<break>, <prosody>, <say-as>, phonemes via <phoneme>)?
If you want a generic starting example while you reply: here’s a safe, minimal pattern you can adapt once you tell me which integration method you use.
1. Create the TTS request body including SSML in the text field (place SSML as the text payload).
2. Send the request to the TTS endpoint or SDK method that accepts text input for Chirp3 HD.
3. Receive audio (stream or file) and either:
◦ Stream into a LiveKit Room as an audio track, or
◦ Save the audio file and play/upload it into LiveKit.
Once you tell me your integration method and language, I’ll provide a precise, copy-pastable example with SSML that uses Chirp3 HD and shows how to stream or play the result in LiveKit.
, with interactive elementscool-doctor-14149
03/30/2026, 12:06 PMimport logging
from dotenv import load_dotenv
from livekit.agents import JobContext, WorkerOptions, cli
from livekit.agents.voice import Agent, AgentSession
from livekit.plugins import google
from livekit.plugins.turn_detector.multilingual import MultilingualModel
load_dotenv()
logger = logging.getLogger("chirp3-chat-agent")
logger.setLevel(<http://logging.INFO|logging.INFO>)
async def entrypoint(ctx: JobContext):
await ctx.connect()
agent = Agent(
instructions="You are a friendly and helpful chat assistant. Keep your responses concise and natural.",
)
session = AgentSession(
stt=google.STT(
model="chirp_2",
languages=["en-US"],
spoken_punctuation=False,
),
llm=google.LLM(
model="gemini-2.5-flash",
temperature=0.8,
),
tts=google.TTS(
voice_name="en-us-Chirp3-HD-Leda",
language="en-US",
),
turn_detection=MultilingualModel(),
)
await session.start(agent=agent, room=ctx.room)
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint, agent_name="chirp3-chat-agent"))tall-airline-16756
03/30/2026, 12:07 PMgoogle.TTS plugin with the Chirp3 HD voice (en-us-Chirp3-HD-Leda). You want to include SSML tags in the TTS output and an example showing how to do it. Good news: Chirp3 HD supports SSML; you can enable SSML parsing in the google.TTS configuration and have your LLM (or any text source) emit SSML wrapped in <speak> tags.
Below is a concise, copy-pasteable update to your code plus an example of how the LLM or agent can produce SSML output.
1) Enable SSML in your TTS config
• Set enable_ssml=True on google.TTS.
2) Ensure the text sent to TTS is valid SSML
• Wrap markup in a top-level <speak>...</speak> tag.
• Use supported tags such as <break>, <emphasis>, <prosody>, and <say-as>.
Updated code (only the changed/added parts shown for brevity):
# in your session definition
session = AgentSession(
stt=google.STT(
model="chirp_2",
languages=["en-US"],
spoken_punctuation=False,
),
llm=google.LLM(
model="gemini-2.5-flash",
temperature=0.8,
),
tts=google.TTS(
voice_name="en-us-Chirp3-HD-Leda",
language="en-US",
enable_ssml=True, # <-- enable SSML parsing
),
turn_detection=MultilingualModel(),
)
Example SSML output your LLM or agent should produce (this string becomes the TTS input):
<speak>
Hello — welcome back!
<break time="400ms"/>
<emphasis level="moderate">Here’s your summary:</emphasis>
<prosody rate="slow">One new message, three notifications.</prosody>
<say-as interpret-as="characters">OK</say-as>
<break time="200ms"/>
Thank you.
</speak>
Notes and tips
• Make sure the LLM is instructed to output SSML when appropriate (for example, include a prompt guideline to wrap speech in <speak> and only use allowed SSML tags).
• Validate SSML if you’re programmatically constructing it to avoid malformed tags — malformed SSML can cause synthesis errors.
• Common useful tags:
◦ <break time="500ms"/> — insert pauses
◦ <emphasis level="strong">...</emphasis> — emphasize words
◦ <prosody rate="slow">...</prosody> — adjust speaking rate/volume/pitch
◦ <say-as interpret-as="characters">...</say-as> — control interpretation
• If you need to switch voices inside SSML, some systems support <voice name="...">...</voice>, but behavior may vary by voice availability.
If you’d like, I can:
• Show a full runnable example that demonstrates the LLM generating SSML within your Agent pipeline, or
• Help craft an LLM prompt that reliably emits valid SSML for different response types (pauses, emphasis, numeric formats, etc.).
Which would be most helpful to you next?
Sources: Google Cloud TTS integration guide | LiveKit Documentation, with interactive elementscool-doctor-14149
03/30/2026, 12:07 PMcool-doctor-14149
03/30/2026, 12:08 PMtall-airline-16756
03/30/2026, 12:08 PMenable_ssml=True), plus a crafted LLM prompt you can use so the LLM reliably emits valid SSML. I’ll keep the example minimal and focused so you can drop it into your environment.
Prerequisites
• Your environment variables and LiveKit/Google plugin credentials are already configured (same as your current setup).
• You have the same imports and packages as in your original script.
Full runnable example
• This example uses your existing structure and adds:
◦ A small LLM prompt template that instructs the LLM to output SSML.
◦ A simple Agent that returns SSML text as its reply.
◦ enable_ssml=True on google.TTS.
• Save this as a Python file and run it the same way you ran your original agent CLI.
import logging
import asyncio
from dotenv import load_dotenv
from livekit.agents import JobContext, WorkerOptions, cli
from livekit.agents.voice import Agent, AgentSession
from livekit.plugins import google
from livekit.plugins.turn_detector.multilingual import MultilingualModel
load_dotenv()
logger = logging.getLogger("chirp3-chat-agent")
logger.setLevel(logging.INFO)
# --- LLM prompt template that asks the model to emit SSML ---
SSML_PROMPT_INSTRUCTIONS = """
You are a helpful assistant that MUST return spoken responses wrapped in valid SSML.
Only return the SSML response — do not include extra commentary or analysis.
Wrap all output inside a single top-level <speak>...</speak> element.
Use the following guidance when producing SSML:
- Use <break time="Xms"/> to add brief pauses.
- Use <emphasis level="moderate">...</emphasis> for emphasis.
- Use <prosody rate="slow">...</prosody> to slow down short phrases.
- Use <say-as interpret-as="characters">...</say-as> for initialisms or acronyms.
- Avoid unsupported or custom tags.
Output example:
<speak>
Hello. <break time="400ms"/>
<emphasis level="moderate">Here is the update:</emphasis>
<prosody rate="slow">Two new messages.</prosody>
</speak>
"""
class SSMLAgent(Agent):
"""
Simple agent that formats a reply using the SSML prompt instructions.
In production you'd combine LLM output + post-processing to ensure valid SSML.
"""
async def act(self, ctx):
# Use the built-in LLM interface via ctx.llm (AgentSession.llm) to request SSML.
user_text = ctx.last_user_message or "Hello"
# Compose a prompt that asks the LLM to respond in SSML describing the user's input.
prompt = SSML_PROMPT_INSTRUCTIONS + f"\nUser asked: \"{user_text}\"\nPlease respond now with SSML only:"
# Request the LLM to generate the SSML response
llm_response = await ctx.llm.generate(prompt=prompt, max_tokens=200, temperature=0.7)
# llm_response.text should contain the SSML string (wrapped in <speak>...</speak>)
ssml_text = llm_response.text.strip()
# It's good practice to validate or sanitize here; for brevity, we assume the LLM follows instructions.
await ctx.send_text(ssml_text, speak=True) # send_text will feed the text into TTS
async def entrypoint(ctx: JobContext):
await ctx.connect()
agent = SSMLAgent(
instructions="You are a friendly chat assistant that replies in SSML when asked for speech.",
)
session = AgentSession(
stt=google.STT(
model="chirp_2",
languages=["en-US"],
spoken_punctuation=False,
),
llm=google.LLM(
model="gemini-2.5-flash",
temperature=0.8,
),
tts=google.TTS(
voice_name="en-us-Chirp3-HD-Leda",
language="en-US",
enable_ssml=True, # Enable SSML parsing
),
turn_detection=MultilingualModel(),
)
await session.start(agent=agent, room=ctx.room)
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint, agent_name="chirp3-chat-agent"))
How this works
• The agent asks the LLM to return only SSML, wrapped in speak.
• ctx.send_text(ssml_text, speak=True) hands the SSML to the TTS plugin; with enable_ssml=True, the Google TTS plugin will parse SSML and synthesize accordingly.
• If you need to stream audio into the LiveKit room instead of letting the agent handle it automatically, you can capture the generated audio and publish it as an audio track — I can show that if you want.
LLM prompt guidance (ready-to-use)
• Use this prompt to reliably get SSML from the LLM. It focuses the model and prevents extra commentary.
Prompt: """ You are a voice assistant that must return a single valid SSML response only.
• Return ONLY SSML content wrapped in one top-level speak.../speak tag.
• Do not add any explanation, stage directions, or code blocks.
• Use break time="Xms"/ for pauses, emphasis for emphasis, prosody to change rate/pitch, and say-as for special formats.
• Keep the response concise (one to three sentences).
Example format: speak Hello. break time="300ms"/ emphasis level="moderate"I have one new notification./emphasis /speak Now respond to the user text below with SSML only: {user_text} """
Tips to make the LLM more reliable
• Provide a concise example in the prompt (as shown). Models follow explicit format examples closely.
• If your LLM sometimes adds extra text, strip everything except the first speak.../speak block before sending to the TTS.
• Optionally run a quick SSML validation step (simple checks: presence of one speak root, no unclosed tags).
• Limit LLM tokens and temperature when you need consistent output (lower temperature reduces creativity and extra commentary).
Would you like:
• A small helper function to extract/validate the first speak.../speak block from LLM output before sending to TTS, or
• An example that saves the synthesized audio to a file (instead of streaming to the room)?
Which next step helps you most?
, with interactive elementscool-doctor-14149
03/30/2026, 12:16 PMtall-airline-16756
03/30/2026, 12:17 PMenable_ssml=True while using the plugin’s streaming mode, the plugin rejects it because SSML requires processing the whole XML structure and can’t be handled incrementally in the current streaming implementation.
• Short-term options:
◦ Disable SSML for streaming: remove enable_ssml=True and use plain text TTS in streaming mode. Influence prosody with prompt wording (e.g., “speak slowly,” “pause briefly”).
◦ Use a non-streaming workflow with SSML: generate the full audio from SSML offline (request a complete audio file from Google TTS), then play or publish that audio into the LiveKit room as a pre-recorded track.
◦ Switch to a TTS provider that supports SSML in streaming mode (for example, ElevenLabs and other providers have streamable SSML support in LiveKit plugins).
Quick fixes you can try now 1) If you want to keep streaming (minimal change)
• Remove the enable_ssml flag (or set it False) in your google.TTS(...) call:
tts=google.TTS(
voice_name="en-us-Chirp3-HD-Leda",
language="en-US",
# enable_ssml=True, <-- remove or set to False for streaming
),
2) If you need SSML features (generate audio file, then play it)
• Use Google TTS non-streaming API to synthesize SSML to an audio file (offline). Then publish that file into the LiveKit room as an audio track (or play it locally into the session).
• I can provide a full example showing how to:
a. Send SSML to Google TTS and save the returned audio (e.g., WAV/MP3).
b. Publish that audio file into your LiveKit Room.
3) If you want SSML in-stream without switching to offline flow
• Consider switching your session’s TTS plugin to a provider that supports streaming SSML (e.g., ElevenLabs). I can show how to configure that provider in your AgentSession if you want.
Would you like one of the following next?
• I’ll show a runnable example that synthesizes SSML offline with Google TTS, saves audio, and then publishes it into the LiveKit room.
• I’ll show how to switch to ElevenLabs (or another provider) that supports SSML in streaming mode.
• I’ll show a small helper that strips non-SSML text and uses plain streaming TTS with prompt-based prosody adjustments.
Tell me which path you prefer and I’ll provide the corresponding code sample.
Sources: Google Cloud TTS integration guide | LiveKit Documentation | Realtime models overview | LiveKit Documentation | ElevenLabs TTS | LiveKit Documentation | Resemble AI TTS plugin guide | LiveKit Documentation | Azure Speech TTS plugin guide | LiveKit Documentation, with interactive elements