Guide · 使用教程
Cartesia 实时 TTS 教程:给语音 Agent 接入流式合成、打断与成本验收
用 Cartesia Sonic 3.6 WebSocket 把增量文本转成逐块音频,完成 Python 演示、中文声线替换、用户插话取消、密钥保护及延迟与费用验收。
这篇教程把 Cartesia Sonic 3.6 当作语音 Agent 的“说话层”:上游可以是任意 LLM,本文先用三段固定文本模拟增量输出,确认 WebSocket、音频格式和播放器能正常工作,再接真实模型。最终目标是得到可播放的逐块音频,并建立延迟、打断和费用验收表。示例不需要上传真实用户录音。
开始前准备
- 创建 Cartesia 账户和 API key。在本机环境变量中设置
CARTESIA_API_KEY,不要写进网页代码、Git 仓库或截图。 - 安装 Python 3、
ffplay(FFmpeg 提供),以及官方 Python SDK:python3 -m pip install 'cartesia[websockets]'。 - 先选一个官方语音 ID。下面用官方 Sonic 3.6 文档中的英文示例声线 Skylar 测链路;做中文产品时,去 Voice Library 挑支持中文的声线,并把业务语料换成中文。Sonic 3.6 官方语言表包含
zh,但某个具体声线的实际效果仍需试听。
第一步:发出分段文本并播放音频
把下面内容保存为 cartesia_demo.py。这段代码由官方 WebSocket 模式改写,重点是 push、no_more_inputs 与逐块接收。服务器没有扬声器时,可把音频块写到文件后用同一采样率转换。
import os
import subprocess
from cartesia import Cartesia
api_key = os.environ.get("CARTESIA_API_KEY")
if not api_key:
raise RuntimeError("请先设置 CARTESIA_API_KEY")
client = Cartesia(api_key=api_key)
player = subprocess.Popen(
["ffplay", "-f", "f32le", "-ar", "44100", "-nodisp",
"-autoexit", "-loglevel", "error", "-"],
stdin=subprocess.PIPE,
bufsize=0,
)
try:
with client.tts.websocket_connect() as connection:
speech = connection.context(
model_id="sonic-3.6",
voice="db6b0ed5-d5d3-463d-ae85-518a07d3c2b4",
output_format={
"container": "raw",
"encoding": "pcm_f32le",
"sample_rate": 44100,
},
)
for part in ["Hello! ", "I can speak ", "while text is arriving."]:
speech.push(part)
speech.no_more_inputs()
for event in speech.receive():
if event.type == "chunk" and event.audio:
player.stdin.write(event.audio)
elif event.type == "done":
break
finally:
if player.stdin:
player.stdin.close()
player.wait()
运行 python3 cartesia_demo.py。如果听不到声音,先检查本机 ffplay 和音量,再确认 API key、声线 ID、账户额度、输出编码与采样率一致。代码中的 44.1 kHz 浮点 PCM 必须和 ffplay 参数对应;电话网关常用 8 kHz μ-law,不能不转换就直接转发。
第二步:接入真实 LLM
上面的 for part 可换成上游 LLM 的增量输出,但不要把每个 token 都立即送到 TTS。先缓存到自然的词组或句子边界,避免断词和不自然停顿;缓存越久,首音频越晚。将“LLM 开始输出→首个可播放音频”作为关键指标,用 5 到 20 条真实回复调节分块策略,而不是凭一个演示句决定。
第三步:处理插话和取消
用户再次说话时,要同时停止三个地方:上游 LLM 当前输出、Cartesia 当前 context、播放器或电话网关已排队的音频。只取消服务端 context,用户仍可能听到缓冲中的旧回答。为每轮分配请求 ID,标记已取消的音频块并拒绝播放;只有当前轮的音频可进入播放队列。发生断线时,明确该句是重播、跳过还是从下一轮开始。
第四步:验收质量和成本
做一份固定样本表:中文人名、金额、日期、地址、英文缩写、混合语言、长句、用户在前 500 毫秒插话。逐条记录首可播放时间、整句完成时间、错读、卡顿、音量、重复播报和取消后的残留。冷连接与复用连接分别测,至少在目标地区跑一轮。账单按实际 credits 与成功会话计算;Free 仅适合试验,商业许可和并发按当前套餐核对。
安全与合规
API key 放服务端。若浏览器直接连接 Cartesia,使用官方文档建议的短期访问令牌,不把长期 key 交给客户端。对真实用户明确告知使用 AI 合成声音;声音克隆需取得声音所有者授权。日志避免保留完整敏感对话;设置超时、并发与费用上限。
何时改用别的方案
如果你的文本一开始就完整,Cartesia 的 HTTP bytes 更简单。若团队还需要音色创作工作流,可并测 ElevenLabs;已经用 Deepgram STT,且目标语言在 Aura-2 官方 TTS 支持列表中,才并测 Aura;中文语音合成目前不要把 Aura-2 作为备选。决策以自己的中文语料和完整电话/浏览器链路为准。
官方资料
常见问题
- Cartesia 的 API key 可以放在浏览器吗?
- 长期 API key 不应放浏览器。官方建议客户端使用短期访问令牌,并由服务端控制签发和权限。
- 为什么示例用英文语音?
- 这是为了用官方列出的声线先验证音频链路。做中文产品时应从 Voice Library 选择合适声线,并用中文数字、人名和混合语料盲测。
- 每个 LLM token 都要马上送入 TTS 吗?
- 通常不需要。按词组或句子边界分块,平衡首音频延迟与发音自然度。
- 用户插话时只关闭 Cartesia context 够吗?
- 不够。还要停止上游 LLM,并清理播放器或电话网关中排队的旧音频。
- 为什么电话里听到杂音?
- 可能是输出编码或采样率与电话网关不一致。示例是 44.1 kHz 浮点 PCM,接 8 kHz μ-law 链路要正确转换。
- 怎么比较 Cartesia 和其他 TTS 的费用?
- 用相同业务样本统计每次成功会话的字符、credits、重试和通话链路成本,别只比较公开月费。