You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Twilio Media Streams中借助Deepgram检测语音静音实现非实时转录

解决Twilio音频块聚合与真实静音检测问题

Twilio会每20毫秒持续发送音频块,即使在静音时段也会发送包含静音数据的块,仅通过监测块到达时间无法识别「真实静音」。需求是聚合所有音频块直到检测到真实静音,再将完整音频发送至Deepgram进行语音转写(S2T),后续OpenAI调用需要完整转录,无需实时转写。

当前无效方案

# 此方案无效,因为音频块持续到达
if gap_between_chunks > 1500ms:
    complete_utterance()  # 永远不会触发

已尝试的方法

  • 基于间隔的检测:监测块之间的时间戳间隔,但最大仅100-200ms,无法识别真实静音
  • 实时监测:跟踪上次接收块后的时钟时间,但块从未停止到达
  • 固定时间窗口:每2-3秒处理一次,但会截断完整语句

示例日志

📡 MEDIA INFO: customer - chunk #500, timestamp 10065ms, track inbound, size 160 bytes
📡 MEDIA INFO: customer - chunk #1000, timestamp 20065ms, track inbound, size 160 bytes
📡 MEDIA GAP: 193.6ms for customer (event #15) # 仅存在小间隔
⏱️ Maximum window reached (60000ms) - completing utterance # 仅超时触发

可行实现方案

核心思路:基于音频内容的静音检测

既然无法通过块间隔判断,直接分析音频块的内容,通过计算音频能量判断是否为静音块,再统计连续静音的时长来触发完整音频的转写。

具体步骤

  1. 维护音频缓冲区:接收所有Twilio发来的音频块并暂存
  2. 音频能量计算:对每个音频块解析原始音频数据(比如Twilio常用的mu-law格式),计算RMS(均方根)值判断是否为静音
  3. 连续静音跟踪:统计连续静音块的总时长,当超过设定阈值(比如1.5秒)且缓冲区有有效音频时,触发转写
  4. 超时兜底:保留原有的超时机制(比如60秒),避免因持续噪音或长语音导致无法触发

Python代码示例

import numpy as np
from pydub import AudioSegment

# 配置参数
SILENCE_RMS_THRESHOLD = 0.01  # 静音能量阈值(可根据场景调整)
CONTINUOUS_SILENCE_THRESHOLD = 1.5  # 触发转写的连续静音时长(秒)
CHUNK_DURATION = 0.02  # 每个Twilio音频块的时长(20毫秒)
MAX_TIMEOUT = 60  # 最大超时时长(秒)

# 全局状态
audio_buffer = b""
continuous_silent_time = 0.0
total_recording_time = 0.0

def mulaw_to_pcm(mulaw_chunk):
    # 将Twilio的mu-law格式音频转成PCM
    audio = AudioSegment.from_raw(mulaw_chunk, sample_width=1, frame_rate=16000, channels=1, format="mulaw")
    return audio.raw_data

def calculate_rms(audio_data):
    # 计算音频RMS值(归一化到0-1范围)
    pcm_array = np.frombuffer(audio_data, dtype=np.int16)
    rms = np.sqrt(np.mean(pcm_array ** 2))
    return rms / 32767.0

def send_to_deepgram(audio_data):
    # 将完整音频发送至Deepgram转写的逻辑
    print("发送完整音频至Deepgram进行转写")
    # 这里添加实际的API调用代码

def handle_twilio_audio_chunk(chunk_data):
    global audio_buffer, continuous_silent_time, total_recording_time
    
    total_recording_time += CHUNK_DURATION
    # 转换音频格式并计算RMS
    pcm_data = mulaw_to_pcm(chunk_data)
    rms_value = calculate_rms(pcm_data)
    
    if rms_value < SILENCE_RMS_THRESHOLD:
        continuous_silent_time += CHUNK_DURATION
        # 满足连续静音阈值且有有效音频
        if continuous_silent_time >= CONTINUOUS_SILENCE_THRESHOLD and len(audio_buffer) > 0:
            send_to_deepgram(audio_buffer)
            # 重置状态
            audio_buffer = b""
            continuous_silent_time = 0.0
            total_recording_time = 0.0
        # 超时兜底
        elif total_recording_time >= MAX_TIMEOUT:
            send_to_deepgram(audio_buffer)
            audio_buffer = b""
            continuous_silent_time = 0.0
            total_recording_time = 0.0
    else:
        # 非静音块,加入缓冲区并重置静音计时
        audio_buffer += chunk_data
        continuous_silent_time = 0.0

注意事项

  • 阈值调优:根据实际通话环境(安静/嘈杂)调整SILENCE_RMS_THRESHOLD和CONTINUOUS_SILENCE_THRESHOLD,避免误判
  • 音频格式兼容性:确认Twilio发送的音频格式(通常是mu-law 8-bit、16kHz、单声道),确保格式转换逻辑正确
  • 内存管理:若通话时长较长,可考虑定期清理缓冲区或分批次处理,但需保证语句完整性

内容的提问来源于stack exchange,提问作者Lahfir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 17:23:17