Twilio语音机器人如何在TwiML Say播报完成后触发Media Stream的WebSocket服务
解决方案
你遇到的问题由两个核心原因导致,按以下步骤修复即可:
1. 先修复基础错误
你的代码里存在两处低级拼写错误,会直接导致Twilio收到错误响应无法执行后续指令:
- 呼叫端点里你定义的响应变量是
voice_respond,返回时错误写为voice_response say方法的voice参数有效值是woman,你错误写为women
2. 解决呼叫状态错误问题
ringing是呼叫尚未接通的临时状态,只有当呼叫正式接通后,状态才会变为in-progress,此时才能执行修改通话、启动媒体流等操作。
把你呼叫端点的状态判断逻辑修改为:
@app.route("/twilio_call", methods=['POST']) def voice(request): """Respond to incoming phone calls with a greet message""" call_status = request.form.get("CallStatus") # 仅在通话正式接通后返回业务TwiML if call_status == "in-progress": voice_response = VoiceResponse() # 给say添加action属性,播报完成后Twilio会自动请求该地址 voice_response.say("hello! how can I help!", voice='woman', action='/start_stream', method='POST') return response.text(str(voice_response), content_type="text/xml") # 其他状态返回空响应即可 return Response(status=200)
3. 实现问候语播报完成后自动启动媒体流
你之前将Say和Stream放在同一份TwiML里无法生效,是因为<Start><Stream>指令会被Twilio优先异步执行,和Say的播放时序冲突。
新增一个专门启动媒体流的端点,等问候语播报完成后Twilio会自动调用该端点,此时返回带Stream的TwiML即可:
@app.route("/start_stream", methods=['POST']) def start_stream(request): voice_response = VoiceResponse() start = Start() start.stream(url='wss://<NGROK_IP>.ngrok.io/webhooks/twilio_voice/media') voice_response.append(start) # 可以在这里加一个空的<Pause>保证流连接稳定,也可以不加 voice_response.pause(length=1) return response.text(str(voice_response), content_type="text/xml")
4. 修复修改通话的报错
你之前调用client.calls.update报错,是因为调用时机过早,呼叫还没进入in-progress状态。
你可以等媒体流WebSocket端点收到第一次event为media的消息后,再调用修改通话的接口,此时通话状态一定是可修改的:
@app.websockets('/media') def transcribe_media(request, ws): client = Client(ACCOUNT_SID, AUTH_TOKEN) while True: message = ws.recv() if message is None: continue data = json.loads(message) if data['event'] == "media": # 此处发送数据到Google STT获取转写结果 msg_text = "你的转写后响应内容" # 拿到转写结果后再修改通话,此时状态一定是in-progress call_sid = data['start']['callSid'] call = client.calls(call_sid).update( twiml=f'<Response><Say voice="woman" language="de-DE">{msg_text}</Say></Response>' )
内容的提问来源于stack exchange,提问作者busy
相关产品推荐
相关产品推荐

