将Deepgram TTS流式传输到Twilio通话时音频出现截断问题
问题分析
你遇到的音频截断、单词生硬分割的问题,核心原因在于当前代码的文本拆分逻辑和音频发送方式:
text_chunker将文本拆分为过小的片段(比如单个词),每个片段单独请求Deepgram生成音频,而Deepgram对短文本生成时会自动添加停顿或标点,最终拼接后出现“Hello. What. is...”的割裂效果。- 直接转发Deepgram返回的原始音频chunk,没有对齐Twilio Media Stream要求的音频帧边界,导致缓冲或截断时出现咔哒声。
解决方案
1. 优化文本拆分逻辑
不要将文本拆分为单个词,而是按完整句子、语义短语拆分,避免破坏语言连贯性。如果text_chunker是自定义工具,修改拆分规则:
- 优先按句号、感叹号、问号等句末标点拆分
- 长句可按逗号、分号拆分,但绝对避免在单词中间断开
- 确保每个拆分后的文本片段至少包含3-5个词,保持语义完整
2. 调整音频缓冲与帧对齐
Twilio Media Stream要求音频为mu-law编码、8kHz采样率,最佳发送单元是20ms的音频帧(160字节)。修改代码,先缓冲Deepgram返回的音频,凑够完整帧后再发送:
async def text_to_speech_input_streaming_deepgram(call_sid, voice_id, model, text_iterator, twilio_ws, stream_sid, listen_task): headers = { "Authorization": f"Token {DEEPGRAM_API_KEY}", "Content-Type": "application/json" } # 合并文本为完整内容,避免多次请求Deepgram导致音频割裂 full_text = "" async for text in text_chunker(text_iterator): full_text += text + " " DEEPGRAM_URL = 'https://api.deepgram.com/v1/speak?model=aura-asteria-en&encoding=mulaw&sample_rate=8000' payload = {"text": full_text.strip()} audio_buffer = bytearray() FRAME_SIZE = 160 # 20ms mu-law 8kHz音频的标准字节数 with requests.post(DEEPGRAM_URL, stream=True, headers=headers, json=payload) as r: for chunk in r: if chunk: audio_buffer.extend(chunk) # 当缓冲足够生成完整帧时,批量发送 while len(audio_buffer) >= FRAME_SIZE: frame = audio_buffer[:FRAME_SIZE] audio_buffer = audio_buffer[FRAME_SIZE:] await stream(frame, twilio_ws, stream_sid) # 发送剩余的不足一帧的音频(如果有的话) if audio_buffer: await stream(audio_buffer, twilio_ws, stream_sid)
3. 避免多次Deepgram请求
当前代码每个文本片段发起一次新的Deepgram请求,这会导致每个片段的音频开头/结尾出现额外停顿。改为将完整文本一次性发送给Deepgram,流式接收连续的音频流,再转发给Twilio,确保音频连贯性。
4. 检查Deepgram API参数
显式关闭自动标点功能,避免Deepgram为短文本添加额外标点:
DEEPGRAM_URL = 'https://api.deepgram.com/v1/speak?model=aura-asteria-en&encoding=mulaw&sample_rate=8000&punctuate=false'
补充说明
如果必须流式处理实时生成的文本(无法提前合并),则需要:
- 调整
text_chunker的拆分策略,只在句子结束时拆分 - 维护一个音频缓冲池,累积Deepgram返回的音频,严格按帧对齐发送,避免频繁发送小chunk
内容的提问来源于stack exchange,提问作者JPSL
相关产品推荐
相关产品推荐

