在环形系统中处理忙/无应答

时间:2016-03-08 14:20:15

标签: python flask twilio ivr

我已经围绕这个主题进行了一些搜索,并参考了相关的API参考资料,但我仍然在努力完全实现这一点。

我尝试使用python-twilio库在Python / Flask中构建一个系统,该系统将执行以下操作:

  1. 用户来电,听到消息
  2. 应用程序同时拨出n组中的第一组,其中组是带有元信息(如名称)的数字列表。在代码中表示为具有数字列表值的字典。 (k [v] = [0,1,n])
  3. 如果小组中的某个人(代理人)回答,请他们输入确认数字以继续。确认后,将它们连接到用户。
  4. 如果该组中的代理没有接听,请尝试该组中的下一个代理(响铃号码)并返回步骤3.
  5. 是的,等等代码。这已被剥离为基本逻辑。不幸的是,我还没能完全掌握Flask应用程序状态,所以我一直在使用Python全局变量访问。我想摆脱这种情况,因为如果向应用发出两个电话,应用可能会无法正常工作。

    # excluding flask import/setup
    from twilio import twiml
    from twilio.rest import TwilioRestClient
    
    agents = OrderedDict()
    agents['Foo'] = ["+440000000000", "+440000000001"]
    agents['Bar'] = ["+440000000002", "+440000000003"]
    
    caller = None
    @app.route('/notify', methods=['POST'])
    def notify():
        """Log all call status callbacks"""
        global caller
        called = request.values.get('Called')
        call_status = request.values.get('CallStatus') 
        timestamp = request.values.get('Timestamp') # e.g. Wed, 02 Mar 2016 15:42:30 +0000
        call_statuses = {
            "initiated": "[%s@%s] INITIATED",
            "ringing": "[%s@%s] RINGING",
            "in-progress": "[%s@%s] IN-PROGRESS",
            "answered": "[%s@%s] ANSWERED",
            "failed": "[%s@%s] CALL FAILED",
            "no-answer": "[%s@%s] NO ANSWER",
            "busy": "[%s@%s] BUSY",
            "completed": "[%s@%s] COMPLETED"
            }
        called_name = [i for i in agents.items() if called in i][0][0]
        print("--%s-- %s" % (timestamp, call_statuses[call_status] % (called_name, called)))
    
        return jsonify({"status": 200})
    
    def new_twilio_client():
        _ = TwilioRestClient(app.config['TWILIO_ACCOUNT_SID'], app.config['TWILIO_AUTH_TOKEN'])
        return _
    
    @app.route('/welcome', methods=['GET'])
    def welcome():
        global caller
        response = twiml.Response()
        response.say("Welcome message", voice="alice")
        caller = request.values.get("Caller")
        # log the call/caller here
        response.redirect(url_for(".start"), _external=True, method="GET")
        return str(response)
    
    @app.route('/start', methods=['GET'])
    def start():
        response = twiml.Response()
        response.say("Trying first agent")
        response.enqueue("q")
        client = new_twilio_client()
        for number in agents['Foo']:
            client.calls.create(to=number, Timeout=12, ifMachine="Hangup", statusCallbackEvent="initiated ringing answered completed", StatusCallback=url_for(".notify", _external=True), from_=app.config['TWILIO_CALLER_ID'], url=url_for(".whisper", _external=True), method="GET")        
        return str(response)
    
    @app.route("/whisper", methods=['GET'])
    def whisper():
        """Ask agent if they want to accept the call"""
        global call_sid
        response = twiml.Response()
        client = new_twilio_client()
        response.say("Press 1 to accept this call")
        response.gather(action=url_for(".did_agent_accept", _external=True), numDigits=1, timeout=3)
        return str(response)
    
    @app.route("/did_agent_accept", methods=['POST'])
    def did_agent_accept():
        """Determine if the agent accepted the call"""
        response = twiml.Response()
        digit = request.values.get('Digits', None)
        if digit == "1":
            with response.dial() as dial:
                # drop the agent into the queue we made earlier
                dial.queue("q", url=url_for(".thanks_for_waiting", _external=True))
        else:
            response.reject()
        return str(response)
    
    @app.route("/thanks_for_waiting", methods=['GET'])
    def thanks_for_waiting():
        """Thank the user"""
        response = twiml.Response()
        response.say("Thanks for waiting. You will now be connected.")
        return str(response)
    
    @app.route('/sorry', methods=['GET'])
    def sorry():
        response = twiml.Response()
        response.say("Sorry, trying again")
        response.redirect(url=url_for(".start", _external=True), method="GET")
        return str(response)
    

    因此,我在这里使用了Twilio的排队功能将调用者放入队列,然后我使用REST API将调用发送到第一个代理的相关号码。当他们拿起并回复聚集动词时,他们就会被放入队列中。

    我遇到的障碍:

    • 管理忙碌无应答(或其他非应答)状态,以确定应用程序是否应该尝试下一组数字很困难,因为异步性质回调功能。我已经尝试了一种解决方案,其中我维护一个全局列表,每当调用notify()时都会更新,并且将给出非应答状态的最后一个数字添加到所述列表中。然后我将代理[代理]列表的长度与此全局列表进行比较,如果匹配,我会修改调用以尝试下一个组,但最终会出现幻像/错误调用。

    我的问题是,我该如何进行这样的实时通话修改,这样我就可以清除以前任何现有的振铃来电?如何改进此代码的设计?有什么明显的东西我错过了吗?任何指针都会受到赞赏。

0 个答案:

没有答案