Twilio 嵌套收集输入

Twilio Nested Gather Inputs

我正在使用 flask 和 mod_wsgi 在 python 中构建一个嵌套的 Twilio 来回答 machine/app。我让它有点工作,因为如果你输入除 3 之外的任何数字,它不会说太多并再次提示你。 3 将您带到下一个函数,但输入的数字响应就像仍在第一个收集函数上一样。我错过了什么?谢谢!

from .customer_details import *
from flask import Flask, request
from twilio.twiml.voice_response import VoiceResponse, Gather
import os,sys
from twilio.rest import Client
global request, v, resp
v = "Polly.Ayanda-Neural"

def listener():
        global request, v, resp
        Call = "SmsSid" not in request.form.keys()
        resp = VoiceResponse()
        sender = request.form['From']
        if Call:
                if sender==sender: #actual code checks for valid phone
                        resp = VoiceResponse()
                        t="hi"
                        resp.say(t, voice=v)
                else:
                        resp.say("Goodbye")
                        return str(resp)
                print(getmerged2())
        elif not Call:
                message_body = request.form['Body']
                pass

        return str(resp)

def getmerged2():
        global request, v, resp
        if 'Digits' in request.values:
                choice = request.values['Digits']
                if choice == '3':
                        resp = VoiceResponse()
                        resp.say("bonjour", voice=v)
                        waitforagent()
                else:
                        resp=VoiceResponse()
                        resp.say("not so much", voice=v)
        with resp.gather(numDigits=1, timeout="60") as g:
                g.say("press a button")
        return resp

def waitforagent2():
        global request, v, resp
        if len(request.values['Digits']) >1:
                choice = request.values['Digits'][:1]
                if choice == '3':
                        resp = VoiceResponse()
                        resp.say("Wahoo")
                else:
                        resp = VoiceResponse()
                        resp.say ("BOOHOOO")
        with resp.gather (numDigits=1, timeout="60") as g:
                g.say ("select an option")

我认为您的问题可能与 global 变量有关。我会回来的。首先,我想解释一下如何使用 TwiML 更好地做到这一点。


请务必注意,每次您 return 对 Twilio 的响应中包含 <Gather> 时,Twilio 都会在收到用户输入时向您的应用程序发出新的 webhook 请求。对话是 Twilio 对您的应用程序的一系列请求以及您的应用程序对 Twilio 的响应,以说明下一步要做什么。

With <Gather> 当您收到调用者的响应时,默认情况下,Twilio 这次将调用相同的 URL,并带有 DigitsSpeechResult 参数。您看起来已经在现有代码中对此进行了一些处理,但是您似乎也希望代码继续 运行。相反,从 Twilio 到端点的每个新请求都将再次从代码的顶部开始。

我发现使用不同的端点可以更轻松地分解事物并使用不同的代码处理结果。为此,您可以将 URL 作为 action attribute in the <Gather>. The documentation specifically calls this out:

Without an action URL, Twilio will re-request the URL that hosts the TwiML you just executed. This can lead to unwanted looping behavior if you're not careful. See our example below for more information.

因此,如果您使用 action 属性并将 URL 传递给不同的端点,您可以在代码的不同部分处理结果以处理初始消息和 <Gather>,.

how to handle the incoming request and then gather result with different endpoints 的文档中查看此示例:

@app.route("/voice", methods=['GET', 'POST'])
def voice():
    """Respond to incoming phone calls with a menu of options"""
    # Start our TwiML response
    resp = VoiceResponse()

    # Start our <Gather> verb
    gather = Gather(num_digits=1, action='/gather')
    gather.say('For sales, press 1. For support, press 2.')
    resp.append(gather)

    # If the user doesn't select an option, redirect them into a loop
    resp.redirect('/voice')

    return str(resp)

@app.route('/gather', methods=['GET', 'POST'])
def gather():
    """Processes results from the <Gather> prompt in /voice"""
    # Start our TwiML response
    resp = VoiceResponse()

    # If Twilio's request to our app included already gathered digits,
    # process them
    if 'Digits' in request.values:
        # Get which digit the caller chose
        choice = request.values['Digits']

        # <Say> a different message depending on the caller's choice
        if choice == '1':
            resp.say('You selected sales. Good for you!')
            return str(resp)
        elif choice == '2':
            resp.say('You need support. We will help!')
            return str(resp)
        else:
            # If the caller didn't choose 1 or 2, apologize and ask them again
            resp.say("Sorry, I don't understand that choice.")

    # If the user didn't choose 1 or 2 (or anything), send them back to /voice
    resp.redirect('/voice')

    return str(resp)

回到那些全局变量。在代码的顶部,您从 Flask 包中导入请求,然后将其设为全局。每个不同 Flask 端点中的 request 对象表示对 Web 服务器发出的请求。使该变量成为全局变量意味着 运行 任何其他 Flask 端点可能会在程序的任何地方覆盖该变量。

在您的程序中,我绝对会避免将 request 设为全局。您可以使语音 v 成为常量。 resp 也应该保持在每个端点的本地。

您的代码重写为使用不同端点在不同时间处理不同输入:

from .customer_details import *
from flask import Flask, request
from twilio.twiml.voice_response import VoiceResponse, Gather
import os,sys
VOICE = "Polly.Ayanda-Neural"

@app.route("/voice", methods=['GET', 'POST'])
def listener():
        global request, v, resp
        Call = "SmsSid" not in request.form.keys()
        resp = VoiceResponse()
        sender = request.form['From']
        if Call:
                if sender==sender: #actual code checks for valid phone
                        resp = VoiceResponse()
                        t="hi"
                        resp.say(t, voice=VOICE)
                else:
                        resp.say("Goodbye")
                        return str(resp)
                # Add the first gather here, but give it an action URL
                with resp.gather(numDigits=1, timeout="60", action="/gather1") as g:
                        g.say("press a button")
        elif not Call:
                message_body = request.form['Body']
                pass

        return str(resp)

@app.route("/gather1", methods=['GET', 'POST'])
def gather1(request, resp):
        if 'Digits' in request.values:
                choice = request.values['Digits']
                if choice == '3':
                        resp.say("bonjour", voice=VOICE)
                        with resp.gather (numDigits=1, timeout="60", action="/gather2") as g:
                                g.say ("select an option")
                else:
                        resp=VoiceResponse()
                        resp.say("not so much", voice=VOICE)
        return str(resp)

@app.route("/gather2", methods=['GET', 'POST'])
def gather2():
        if len(request.values['Digits']) >1:
                choice = request.values['Digits'][:1]
                if choice == '3':
                        resp = VoiceResponse()
                        resp.say("Wahoo")
                else:
                        resp = VoiceResponse()
                        resp.say ("BOOHOOO")
        return str(resp)

在上面的代码中,第一个端点首先被调用,return是一个要求调用者“按下按钮”的 TwiML 响应。当用户按下按钮时,Twilio 会调用第二个端点 /gather1。这将检查他们按下的数字是否为 3。如果是,它会要求他们“select 一个选项”。如果不是 3,则它会响应“不多”,然后挂断。最后,如果用户先按 3 然后再按另一个 Digit,Twilio 会向第三个端点 /gather2 发出请求。这将再次检查数字,如果是 3,则返回“Wahoo”,如果不是,则返回“BOOHOOO”。