简体   繁体   English

Twilio 嵌套收集输入

[英]Twilio Nested Gather Inputs

I am building a nested Twilio answering machine/app in python with flask and mod_wsgi.我正在使用 flask 和 mod_wsgi 在 python 中构建一个嵌套的 Twilio 应答机/应用程序。 I have it working somewhat, in that if you type any number besides 3 it says not so much and prompts you again.我让它有点工作,因为如果你输入除 3 之外的任何数字,它不会说太多并再次提示你。 3 takes you to the next function, but inputted numbers respond as if still on the first gather function. What am I missing? 3 带你到下一个 function,但输入的数字响应好像仍在第一个集合 function。我错过了什么? Thanks!谢谢!

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")

I think your issue here is likely to do with global variables.我认为您的问题可能与global变量有关。 Which I will come back to.我会回来的。 First I want to explain how you might do this better with TwiML.首先,我想解释一下如何使用 TwiML 更好地完成这项工作。


It's important to note that every time you return a response with a <Gather> in it to Twilio, Twilio makes a new webhook request to your application when it gets an input from the user.请务必注意,每次您向 Twilio 返回一个包含<Gather>的响应时,Twilio 在从用户那里获取输入时都会向您的应用程序发出一个新的 webhook 请求。 The conversation is a series of requests from Twilio to your application and responses from your application to Twilio to say what to do next.对话是从 Twilio 到您的应用程序的一系列请求,以及您的应用程序对 Twilio 的响应,以说明下一步要做什么。

With <Gather> when you get the caller's response Twilio will, by default, call the same URL this time with the Digits or SpeechResult parameter present.使用<Gather>当您获得呼叫者的响应时,默认情况下,Twilio 将在默认情况下调用相同的 URL,此时带有DigitsSpeechResult参数。 You look to have handled that a bit in your existing code, however it also appears that you expect the code to continue running.您看起来已经在现有代码中对此进行了一些处理,但您似乎也希望代码继续运行。 Instead, each new request from Twilio to your endpoint will start at the top of your code again.相反,从 Twilio 到您的端点的每个新请求都将再次从您的代码顶部开始。

I find it is easier to break things apart and handle results with different code by using a different endpoint.我发现通过使用不同的端点来分解事物并使用不同的代码处理结果会更容易。 To do so, you can pass a URL as the action attribute in the <Gather> .为此,您可以将 URL 作为<Gather>中的action属性传递。 The documentation specifically calls this out :该文档特别指出了这一点

Without an action URL, Twilio will re-request the URL that hosts the TwiML you just executed.如果没有action URL,Twilio 将重新请求托管您刚刚执行的 TwiML 的 URL。 This can lead to unwanted looping behavior if you're not careful.如果您不小心,这可能会导致不需要的循环行为。 See our example below for more information.有关更多信息,请参见下面的示例。

So, if you use an action attribute and pass a URL to a different endpoint you can handle the result in a different part of the code to handling the initial message and <Gather> ,.因此,如果您使用action属性并将 URL 传递给不同的端点,您可以在代码的不同部分处理结果以处理初始消息和<Gather>

Check out this example from the documentation for 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)

Back to those global variables though.回到那些全局变量。 In the top of your code, you import request from the Flask package and then you make it global.在代码的顶部,您从 Flask package 导入请求,然后将其设为全局。 The request object in each different Flask endpoint is a representation of the request being made to the web server.每个不同的 Flask 端点中的request object 表示向 web 服务器发出的请求。 Making that global means that running any other Flask endpoint may well overwrite that variable everywhere in the program.使该变量成为全局变量意味着运行任何其他 Flask 端点可能会在程序的任何地方覆盖该变量。

In your program I would definitely avoid making request a global.在您的程序中,我绝对会避免将request设为全局。 You can make the voice v a constant.您可以使语音v保持不变。 And resp should stay local to each endpoint too.并且resp也应该保持在每个端点的本地。

Here is your code rewritten to use different endpoints to deal with different inputs at different times:这是您重写的代码,以使用不同的端点在不同时间处理不同的输入:

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)

In the above code, the first endpoint is called first and returns a TwiML response that asks the caller to "press a button".在上面的代码中,第一个端点首先被调用并返回一个 TwiML 响应,要求调用者“按下按钮”。 When the user does press the button, Twilio then calls the second endpoint /gather1 .当用户确实按下按钮时, Twilio 然后调用第二个端点/gather1 This checks if the Digit they pressed was 3. If it was, it asks them to "select an option".这将检查他们按下的数字是否为 3。如果是,它会要求他们“选择一个选项”。 If it wasn't 3 then it responds "not so much" and then hangs up.如果不是 3,则它会响应“不多”,然后挂断。 Finally, if the user first pressed 3 and then presses another Digit, Twilio makes a request to the third endpoint /gather2 .最后,如果用户先按 3 然后再按另一个数字,则 Twilio 向第三个端点/gather2发出请求。 This checks the Digit again, if it is 3 it responds with "Wahoo" and if not "BOOHOOO".这将再次检查数字,如果是 3,则响应“Wahoo”,如果不是“BOOHOOO”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Twilio 简单的集合动作 - Twilio Simple Gather Action Twilio PCI 兼容<gather>在带有 Studio 的函数小部件中</gather> - Twilio PCI Compliant <Gather> in Function Widget with Studio Twilio 使用 Gather 获取用户 ID 和密码 - Twilio using Gather to get UserID and Password Twilio “随叫随到”暂停 - Twilio "Gather input on call" is having pauses Twilio语音<gather> - DotNetCore - 数字参数始终为 null</gather> - Twilio Voice <Gather> - DotNetCore - Digits parameter always null 如何在出站呼叫中从呼叫接收者收集 Twilio DTMF 输入 - How to gather Twilio DTMF input from call recipient on outbound call Twilio Studio - 从一个访问 DTMF 数字<gather>由函数返回?</gather> - Twilio Studio - Access DTMF Digits from a <gather> returned by a function? Twilio可编程语音-如何防止<gather>如果电话被答录机接听,则提示播放</gather> - Twilio Programmable Voice - How to prevent <Gather> prompt from playing if the call is picked up by an answering machine Twilio Studio IVR - 输入无效数字时,是否有办法播放默认错误消息并返回最新的 Gather 小部件? - Twilio Studio IVR - Is there a way to play a default error message and return to the most recent Gather widget when invalid digits are entered? Twilio:将呼叫转移到 Twilio 中的流 - Twilio: forward a call to a flow in Twilio
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM