twilio / python / flask:呼叫转移,但是如果没有及时回答,则重定向到语音邮件

时间:2018-09-16 00:38:25

标签: python-3.x flask twilio

我编写了一个flask应用程序(使用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/voicemail?Email=USER@DOMAIN.COM&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中实现这一目标。

2 个答案:

答案 0 :(得分:2)

您应该为forward()函数的动词定义一个动作URL。然后,对该操作URL的请求(它将转回到您的Flask应用程序的URL)上的DialCallStatus将让您知道调用是否成功。如果调用未成功“完成”,则将路由到VM逻辑,否则。动词的默认超时为30秒,因此效果不错。

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

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

因此,基本上对于上述功能,如果DialCallStatus完成,则要挂断电话,否则路由到VM / Twimlet。

答案 1 :(得分:0)

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

现在,基于REST的应用将白名单批准的号码并阻止不需要的号码。任何批准的或未阻止的号码都将转发到目标电话号码。如果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')