基于Twilio的Python Flask应用实现边听边说及中断重述功能求助
解决Twilio中同时实现语音播报与持续监听的方案
Twilio的TwiML确实是线性执行,但可以通过两种方式实现你要的“播报时监听打断”需求:
方案一:利用<Gather>嵌套<Say>实现原生打断支持
Twilio的<Gather>标签允许嵌套<Say>,结合默认开启的interruptible参数,就能在播报文本的同时监听用户语音输入,用户一说话就会立即停止播报并触发action回调。
Flask代码示例
from flask import Flask, request from twilio.twiml.voice_response import VoiceResponse, Gather, Say app = Flask(__name__) # 初始路由:处理来电或启动对话 @app.route("/voice", methods=['GET', 'POST']) def voice(): # 这里假设已经获取到用户之前的语音转写文本(实际可从数据库/会话中读取) user_transcript = "你刚才说的是:明天一起去爬山" response = VoiceResponse() # 创建Gather,同时监听语音输入,打断后跳转到handle_interruption路由 gather = Gather( input='speech', action='/handle_interruption', speech_model='phone_call', # 适合通话场景的语音模型 timeout=10 # 播报结束后等待用户输入的超时时间 ) # 在Gather中嵌套Say,实现播报+监听并行 gather.say(user_transcript, voice='alice') response.append(gather) # 如果用户没打断,播报完成后回到监听状态 response.redirect('/voice') return str(response) # 处理用户打断的路由 @app.route("/handle_interruption", methods=['GET', 'POST']) def handle_interruption(): # 获取用户打断时的语音转写结果 interruption_text = request.values.get('SpeechResult', '') response = VoiceResponse() if interruption_text: # 处理用户的打断内容,比如转写后准备后续重述 response.say(f"你打断说的是:{interruption_text}") # 回到持续监听状态 response.redirect('/voice') return str(response) if __name__ == "__main__": app.run(debug=True)
核心逻辑说明
<Gather>嵌套<Say>后,Twilio会在播报的同时启动语音监听。- 用户说话时,
interruptible=True会立即终止播报,将转写结果发送到action指定的路由。 - 播报完成后,
Gather会继续监听用户输入,超时后自动重定向回到监听状态。
方案二:使用Media Stream API实现自定义实时控制
如果需要更精细的控制(比如自定义语音检测阈值、实时处理音频数据),可以用Twilio Media Stream API,通过WebSocket实时获取用户音频流,同时控制TTS播放。
核心步骤与代码示例
- 启动Media Stream的TwiML路由
@app.route("/start_stream", methods=['GET', 'POST']) def start_stream(): response = VoiceResponse() # 指向你的WebSocket处理端点(需使用HTTPS/WSS) response.stream(url='wss://your-server-domain/stream_handler') return str(response)
- 用Flask-SocketIO处理WebSocket连接
from flask_socketio import SocketIO, emit import webrtcvad # 用于语音活动检测 socketio = SocketIO(app, cors_allowed_origins="*") vad = webrtcvad.Vad(3) # 3代表高灵敏度 @socketio.on('connect') def on_stream_connect(): print("媒体流连接成功") # 发送TTS播报指令到Twilio(需结合Twilio TTS API或自定义TTS服务) emit('play_tts', {'text': '你刚才说的是:周末去海边'}) @socketio.on('media') def on_media_receive(data): # 解析Twilio发送的音频 payload(PCM格式) audio_payload = bytearray.fromhex(data['media']['payload']) # 用webrtcvad检测是否有语音活动,适配Twilio的8kHz采样率 is_speaking = vad.is_speech(audio_payload, 8000) if is_speaking: # 立即停止TTS播报 emit('stop_tts') # 调用语音转写API处理用户输入(比如Twilio Speech-to-Text) transcribed_text = transcribe_audio(audio_payload) print(f"用户打断内容:{transcribed_text}") def transcribe_audio(audio_data): # 实现语音转写逻辑,可调用Twilio或第三方语音服务 return "我不想听你重述了" if __name__ == "__main__": socketio.run(app, debug=True)
核心逻辑说明
- 通过Media Stream获取实时音频流,用语音活动检测库(如webrtcvad)判断用户是否说话。
- 检测到语音后,立即停止当前TTS播报,处理用户的新输入。
- 这种方式灵活性更高,但需要处理WebSocket通信、音频解析和第三方服务集成。
内容的提问来源于stack exchange,提问作者Tbertin
相关产品推荐
相关产品推荐

