twilio / python / flask:如果没有及时回答,请转发但重定向到语音邮件

问题描述 投票:0回答:2

我已经写了一个烧瓶应用程序(使用python3),我已经注册了twilio来响应来自我的twilio提供的电话号码的来电。我可以让它路由到语音邮件,挂机,忽略通话,转发到另一个电话号码,我在这里称之为target号码。

但是有一个功能我无法弄清楚如何在这个twilio / python / flask应用程序中实现。如果我的应用程序的逻辑没有拒绝传入的号码,我希望将呼叫转发到目标号码。但如果没有人在30秒内回答这个号码,我希望将呼叫定向到我通过twimlets建立的语音邮件。我不知道如何在这里实现这种条件转发/语音邮件逻辑。

这必须发生在以下代码底部附近的answer_call方法中:

import re

from flask import Flask, Response, redirect, request, send_file
from twilio.twiml.voice_response import VoiceResponse

app = Flask(__name__)

ngrokurl = 'http://XXXXXXXX.ngrok.io'
vmbase   = 'http://twimlets.com/[email protected]&Transcribe=False'
vmpath   = '/path/to/voicemessage.mp3'
vmurl    = os.path.join(ngrokurl, 'vm')
fwd      = '+1-111-111-11111'

def num(n):
    return re.compile(n)

whitelist = [
    num(r'^[+]11100000000$'),
    num(r'^[+]11111100000$'),
    num(r'^[+]11111111100$'),
]

ignorelist = [
    num(r'^[+]2000'),
]

hanguplist = [
    num(r'^[+]3000'),
]

def number_in(n, numlist):
    if not n or not numlist:
        return False
    for item in numlist:
        if item.search(n):
            return True
    return False

def voicemail():
    return redirect(
        '{}&Message={}'.format(vmbase, vmurl),
        302
    )

def ignore():
    resp = VoiceResponse()
    resp.play(vmurl, loop=1)
    return Response(str(resp), 200, mimetype='application/xml')

def hangup():
    resp = VoiceResponse()
    resp.hangup()
    return Response(str(resp), 200, mimetype='application/xml')

def forward():
    resp = VoiceResponse()
    resp.dial(fwd)
    return Response(str(resp), 200, mimetype='application/xml')

@app.route('/answer', methods=['GET', 'POST'])
def answer_call():
    '''
    Main flask route for answering phone calls.
    '''
    number = request.args.get('From', None)
    if not number:
        return hangup()
    if number_in(number, whitelist):
        # Whitelisted numbers are directly forwarded.
        #
        # However, what I want to do here is forward to
        # the target number, but then to redirect
        # to voicemail if the call isn't answered
        # after, say, 30 seconds. Don't know how ... ???
        #
        return forward()
##        return voicemail()
    elif number_in(number, ignorelist):
        return ignore()
    elif number_in(number, hanguplist):
        return hangup()
    else:
        #
        # Same question here: how do I forward
        # to the target but then redirect
        # to voicemail if the call isn't answered?
        #
        return forward()
##        return voicemail()

@app.route('/vm', methods=['GET', 'POST'])
def vm():
    '''
    URL for the voicemail recording used within the
    twimlets voicemail call. See `vmurl`, above.
    '''
    return send_file(vmpath, 'audio/mpeg')

if __name__ == "__main__":
    app.run(debug=True)

提前感谢您提供的任何指示或建议。

PS:我知道有关于如何在python / flask环境之外执行此操作的文档。但是,我无法弄清楚如何在python / flask中实现这一点。

python-3.x flask twilio
2个回答
2
投票

您应该为forward()函数定义动词的动作URL。对该操作URL的请求上的DialCallStatus(它将返回到Flask应用程序的URL)将告诉您调用是否成功。如果呼叫未成功“完成”,则将路由到VM逻辑,否则。动词的默认超时是30秒,所以你很好。

关键逻辑在下面的函数中,将逻辑移植到Python应该不难。

在函数https://www.twilio.com/docs/wireless/tutorials/communications-guides/implement-voicemail#create-voicemail-action-in-functions中创建语音邮件操作

所以基本上对于上面的函数,如果DialCallStatus完成,你想要挂断电话,否则路由到VM / Twimlet。


0
投票

感谢Alan的帮助,我解决了它。下面的代码替换了我的初始示例中的forwardanswer_call,并添加了一个新的call_result方法。关于我的例子的其他所有内容保持不变。

现在,REST-ful应用程序会将已批准的号码列入白名单并阻止不需要的号码。任何已批准或未阻止的号码都将转发到目标电话号码。如果20秒后没有人回答,应用程序会将呼叫路由到我的twimlet实施的语音邮件。

显然,这个示例应用程序包含硬编码的过滤器,它只包含虚拟数据。在现实生活中,每次调用时我都会从数据存储区加载这些文件。这样,我可以从REST-ful应用程序外部修改这些过滤器,而无需重新编译甚至重新启动该应用程序。

到目前为止,我的初始编码运行良好。

def forward():
    resp = VoiceResponse()
    resp.dial(
        fwd,
        action=url_for('call_result'),
        method='GET',
        timeout=20
    )
    return Response(str(resp), 200, mimetype='application/xml')

@app.route('/answer', methods=['GET', 'POST'])
def answer_call():
    number = request.args.get('From', None)
    if not number:
        return hangup()
    elif number_in(number, whitelist):
        return forward()
    elif number_in(number, ignorelist):
        return ignore()
    elif number_in(number, hanguplist):
        return hangup()
    else:
        return forward()

@app.route('/call', methods=['GET', 'POST'])
def call_result():
    status = request.args.get('DialCallStatus', None)
    if not status or status != 'completed':
        return voicemail()
    else:
        return Response(str(resp), 200, mimetype='application/xml')
© www.soinside.com 2019 - 2024. All rights reserved.