소스 검색

外呼流程调试

刘威 5 달 전
부모
커밋
97694f43c5

+ 33 - 112
src/core/callcenter/api.py

@@ -186,7 +186,7 @@ class CheckInCallRequest(BaseApi):
 class MakeCallContext(BaseApi):
 
     def __init__(self,
-                 pbx_server=SIP_SERVER,
+                 sip_server=SIP_SERVER,
                  route_gateway_name="gateway-fxo",
                  display: Optional[str] = None,
                  caller: Optional[str] = None,
@@ -202,7 +202,7 @@ class MakeCallContext(BaseApi):
                  service_id: Optional[str] = None,
                  call_type: Optional[int] = None):
         # fs 地址
-        self.pbx_server = pbx_server
+        self.sip_server = sip_server
         # 线路名(非必传)
         self.route_gateway_name = route_gateway_name
         # 外显号(必传)
@@ -260,15 +260,15 @@ class MakeCallContext(BaseApi):
         if self.service_id:
             headers.append(f"{SIP_HEADER}service_id={self.service_id}")
 
-        # if self.device_type == DeviceType.CUSTOMER:
-        #     headers += [
-        #         "RECORD_STEREO_SWAP=true"
-        #     ]
-        # else:
-        #     headers += [
-        #         "RECORD_STEREO_SWAP=false",
-        #         "continue_on_fail=true"
-        #     ]
+        if self.device_type == DeviceType.CUSTOMER.code:
+            headers += [
+                "RECORD_STEREO_SWAP=true"
+            ]
+        else:
+            headers += [
+                "RECORD_STEREO_SWAP=false",
+                "continue_on_fail=true"
+            ]
 
         if self.sip_header_map:
             headers.extend([f"{SIP_HEADER}{k}={v}" for k, v in self.sip_header_map.items()])
@@ -276,10 +276,14 @@ class MakeCallContext(BaseApi):
         return SPLIT.join(headers)
 
     def get_called(self) -> str:
-        if self.called_prefix and self.device_type == DeviceType.CUSTOMER:
+        if self.called_prefix and self.device_type == DeviceType.CUSTOMER.code:
             return f"{self.called_prefix}{self.called}"
         return self.called
 
+    def get_realm(self):
+        sip_uri = SipURI(self.sip_server)
+        return sip_uri.get_host()
+
 
 class SipURI:
     DEFAULT_PORT = -1
@@ -423,7 +427,7 @@ class CallInfo(BaseApi):
     def __init__(self, core_uuid=None, call_id=None, conference=None, saas_id=None, group_id=None,
                  hidden_customer=0, caller_display=None, caller=None, called_display=None, called=None,
                  number_location=None, agent_key=None, agent_name=None, login_type=None, ivr_id=None, task_id=None,
-                 media_host=None, cti_host=None, client_host=None, record=None, record2=None, record_time=None,
+                 media_host=None, sip_server=None, client_host=None, record=None, record2=None, record_time=None,
                  call_time=None, call_type=None, direction=None, answer_flag=None, wait_time=None, answer_count=0,
                  hangup_dir=None, sdk_hangup=0, hangup_code=None, answer_time=None, end_time=None, talk_time=None,
                  frist_queue_time=None, queue_start_time=None, queue_end_time=None, overflow_count=0,
@@ -447,7 +451,7 @@ class CallInfo(BaseApi):
         self.ivr_id = ivr_id  # ivr
         self.task_id = task_id  # 任务ID
         self.media_host = media_host  # 媒体
-        self.cti_host = cti_host  # 服务地址
+        self.sip_server = sip_server  # 服务地址
         self.client_host = client_host  # 客户服务地址
         self.record = record  # 录音地址
         self.record2 = record2  # 第三方存储地址
@@ -482,8 +486,6 @@ class CallInfo(BaseApi):
     @classmethod
     def from_json(cls, json_string):
         data = get_json_dict(json_string)
-        call_type = CallType.get_by_code(data.get('call_type'))
-        direction = Direction.get_by_code(data.get('direction'))
         device_list = [DeviceInfo(**x) for x in data.get('device_list', [])]
         device_info_map: Dict[str, Any] = {key: DeviceInfo(**value) for key, value in data.get('device_info_map', {}).items()}
         follow_data: Dict[str, Any] = {key: value for key, value in data.get('follow_data', {}).items()}
@@ -497,10 +499,10 @@ class CallInfo(BaseApi):
                    caller=data.get('caller'), called_display=data.get('called_display'), called=data.get('called'),
                    number_location=data.get('number_location'), agent_key=data.get('agent_key'),
                    agent_name=data.get('agent_name'), login_type=data.get('login_type'), ivr_id=data.get('ivr_id'),
-                   task_id=data.get('task_id'), media_host=data.get('media_host'), cti_host=data.get('cti_host'),
+                   task_id=data.get('task_id'), media_host=data.get('media_host'), sip_server=data.get('sip_server'),
                    client_host=data.get('client_host'), record=data.get('record'), record2=data.get('record2'),
                    record_time=data.get('record_time'), call_time=data.get('call_time'),
-                   call_type=call_type, direction=direction,
+                   call_type=data.get('call_type'), direction=data.get('direction'),
                    answer_flag=data.get('answer_flag'), wait_time=data.get('wait_time'),
                    answer_count=data.get('answer_count'), hangup_dir=data.get('hangup_dir'),
                    sdk_hangup=data.get('sdk_hangup'), hangup_code=data.get('hangup_code'),
@@ -512,6 +514,9 @@ class CallInfo(BaseApi):
                    device_info_map=device_info_map, follow_data=follow_data, process_data=process_data,
                    next_commands=next_commands, call_details=call_details)
 
+    def __str__(self):
+        return self.to_json_string()
+
     def to_json_string(self):
         new_dict = {
             "core_uuid": self.core_uuid,
@@ -531,14 +536,14 @@ class CallInfo(BaseApi):
             "ivr_id": self.ivr_id,
             "task_id": self.task_id,
             "media_host": self.media_host,
-            "cti_host": self.cti_host,
+            "sip_server": self.sip_server,
             "client_host": self.client_host,
             "record": self.record,
             "record2": self.record2,
             "record_time": self.record_time,
             "call_time": self.call_time,
-            "call_type": self.call_type.code if self.call_type else None,
-            "direction": self.direction.code if self.direction else None,
+            "call_type": self.call_type,
+            "direction": self.direction,
             "answer_flag": self.answer_flag,
             "wait_time": self.wait_time,
             "answer_count": self.answer_count,
@@ -556,13 +561,14 @@ class CallInfo(BaseApi):
             "uuid2": self.uuid2,
             "cdr_notify_url": self.cdr_notify_url,
             "queue_level": self.queue_level,
-            "device_list": [x for x in self.device_list],
-            "device_info_map": {key: value for key, value in self.device_info_map.items()},
-            "follow_data": {key: value for key, value in self.follow_data.items()},
-            "process_data": {key: value for key, value in self.process_data.items()},
-            "next_commands": [x for x in self.next_commands],
-            "call_details": [x for x in self.call_details],
+            "device_list": [vars(x) for x in self.device_list],
+            "device_info_map": {key: vars(value) for key, value in self.device_info_map.items()},
+            "follow_data": {key: vars(value) for key, value in self.follow_data.items()},
+            "process_data": {key: vars(value) for key, value in self.process_data.items()},
+            "next_commands": [vars(x) for x in self.next_commands],
+            "call_details": [vars(x) for x in self.call_details],
         }
+        print(new_dict)
         return json.dumps(new_dict, default=lambda x: x.__dict__, ensure_ascii=False)
 
 
@@ -605,77 +611,6 @@ class DeviceInfo(BaseApi):
         self.apparent_number = apparent_number  # 外显号
         self.caller_display = caller_display  # 主叫号
 
-    @classmethod
-    def from_json(cls, json_string):
-        data = get_json_dict(json_string)
-        device_type = DeviceType.get_by_code(data.get("device_type"))
-        cdr_type = CdrType.get_by_code(data.get("cdr_type"))
-        return cls(call_id=data.get("call_id"),
-                   conference=data.get("conference"),
-                   device_id=data.get("device_id"),
-                   agent_key=data.get("agent_key"),
-                   agent_name=data.get("agent_name"),
-                   device_type=device_type,
-                   cdr_type=cdr_type,
-                   from_agent=data.get("from_agent"),
-                   caller=data.get("caller"),
-                   called=data.get("called"),
-                   display=data.get("display"),
-                   called_location=data.get("called_location"),
-                   caller_location=data.get("caller_location"),
-                   call_time=data.get("call_time"),
-                   ring_start_time=data.get("ring_start_time"),
-                   ring_end_time=data.get("ring_end_time"),
-                   answer_time=data.get("answer_time"),
-                   bridge_time=data.get("bridge_time"),
-                   end_time=data.get("end_time"),
-                   talk_time=data.get("talk_time"),
-                   sip_protocol=data.get("sip_protocol"),
-                   channel_name=data.get("channel_name"),
-                   hangup_cause=data.get("hangup_cause"),
-                   ring_cause=data.get("ring_cause"),
-                   sip_status=data.get("sip_status"),
-                   record=data.get("record"),
-                   record_time=data.get("record_time"),
-                   record_start_time=data.get("record_start_time"),
-                   state=data.get("state"),
-                   apparent_number=data.get("apparent_number"),
-                   caller_display=data.get("caller_display"))
-
-    def to_json_string(self):
-        new_dict = {"call_id": self.call_id,
-                    "conference": self.conference,
-                    "device_id": self.device_id,
-                    "agent_key": self.agent_key,
-                    "agent_name": self.agent_name,
-                    "device_type": self.device_type.code if self.device_type else None,
-                    "cdr_type": self.cdr_type.code if self.cdr_type else None,
-                    "from_agent": self.from_agent,
-                    "caller": self.caller,
-                    "called": self.called,
-                    "display": self.display,
-                    "called_location": self.called_location,
-                    "caller_location": self.caller_location,
-                    "call_time": self.call_time,
-                    "ring_start_time": self.ring_start_time,
-                    "ring_end_time": self.ring_end_time,
-                    "answer_time": self.answer_time,
-                    "bridge_time": self.bridge_time,
-                    "end_time": self.end_time,
-                    "talk_time": self.talk_time,
-                    "sip_protocol": self.sip_protocol,
-                    "channel_name": self.channel_name,
-                    "hangup_cause": self.hangup_cause,
-                    "ring_cause": self.ring_cause,
-                    "sip_status": self.sip_status,
-                    "record": self.record,
-                    "record_time": self.record_time,
-                    "record_start_time": self.record_start_time,
-                    "state": self.state,
-                    "apparent_number": self.apparent_number,
-                    "caller_display": self.caller_display}
-        return json.dumps(new_dict, default=lambda x: x.__dict__, ensure_ascii=False)
-
 
 class NextCommand(BaseApi):
 
@@ -687,20 +622,6 @@ class NextCommand(BaseApi):
         # 执行参数
         self.next_value = next_value
 
-    @classmethod
-    def from_json(cls, json_string):
-        data = get_json_dict(json_string)
-        next_type = NextType.get_by_code(data.get("next_type"))
-        return cls(device_id=data.get("device_id"), next_type=next_type, next_value=data.get("next_value"))
-
-    def to_json_string(self):
-        new_dict = {
-            "device_id": self.device_id,
-            "next_type": self.next_type.code,
-            "next_value": self.next_value
-        }
-        return json.dumps(new_dict, default=lambda x: x.__dict__, ensure_ascii=False)
-
 
 class CallDetail(BaseApi):
     def __init__(self, id=None, cts=None, start_time=None, end_time=None, call_id=None,

+ 13 - 11
src/core/callcenter/call.py

@@ -2,7 +2,7 @@
 # encoding:utf-8
 
 import time
-
+from datetime import datetime
 import src.core.callcenter.cache as Cache
 from src.core.callcenter.constant import saasId, HOLD_MUSIC_PATH
 from src.core.callcenter.enumeration import CallCause, Direction, NextType, DeviceType, CdrType
@@ -22,25 +22,26 @@ class CallService:
     def call(self, request: AgentCallRequest):
         call_id = 'C' + str(self.snowflake.next_id())
         device_id = 'D' + str(self.snowflake.next_id())
-        now = lambda: int(round(time.time() * 1000))
+        # now = lambda: int(round(time.time() * 1000))
+        now = datetime.utcnow().timestamp()
 
         agent = Cache.get_agent_info(request.saas_id, request.agent_id)
         route_gateway = Cache.get_route_gateway(request.saas_id)
-        call_info = CallInfo(call_id=call_id, agent_key=agent.agent_number, cti_host=agent.sip_server,
-                             caller=agent.agent_number, called=request.called, direction=Direction.INBOUND,
+        call_info = CallInfo(call_id=call_id, agent_key=agent.agent_number, sip_server=agent.sip_server,
+                             caller=agent.agent_number, called=request.called, direction=Direction.INBOUND.code,
                              caller_display=request.caller_display, called_display=request.called_display,
-                             call_type=request.call_type, call_time=now, follow_data=request.follow_data,
+                             call_type=request.call_type.code, call_time=now, follow_data=request.follow_data,
                              uuid1=request.uuid1, uuid2=request.uuid2, saas_id=saasId)
-        device_info = DeviceInfo(device_id=device_id, call_time=now, call_id=call_id, device_type=DeviceType.AGENT,
+        device_info = DeviceInfo(device_id=device_id, call_time=now, call_id=call_id, device_type=DeviceType.AGENT.code,
                                  agent_key=agent.agent_number, caller_display=route_gateway.name)
         call_info.device_list.append(device_info)
-        call_info.next_commands.append(NextCommand(device_id, NextType.NEXT_CALL_OTHER))
+        call_info.next_commands.append(NextCommand(device_id, NextType.NEXT_CALL_OTHER.code))
         call_info.device_info_map = {device_id: device_info}
         Cache.add_call_info(call_info)
 
         context = MakeCallContext(display=request.called, caller=request.called, called=request.caller,
                                   call_id=call_id, device_id=device_id, device_type=device_info.device_type,
-                                  call_type=call_info.call_type)
+                                  call_type=call_info.call_type, sip_server=call_info.sip_server)
 
         self.client.make_call_new(context)
         return call_id
@@ -59,15 +60,16 @@ class CallService:
         call_id = call_info.call_id
         agent = Cache.get_agent_info(call_info.saas_id, call_info.agent_key)
         device_id = 'D' + str(self.snowflake.next_id())
-        now = lambda: int(round(time.time() * 1000))
+        # now = lambda: int(round(time.time() * 1000))
+        now = datetime.utcnow().timestamp()
 
         device_info = DeviceInfo(device_id=device_id, caller=caller, display=caller, called=agent_number, call_id=call_id,
-                            call_time=now, cdr_type=CdrType.TRANSFER.code, device_type=DeviceType.AGENT)
+                            call_time=now, cdr_type=CdrType.TRANSFER.code, device_type=DeviceType.AGENT.code)
         call_info.device_list.append(device_id)
 
         call_info.caller = agent_number
         call_info.device_info_map[device_id] = device_info
-        call_info.next_commands.append(NextCommand(device_info.device_id, NextType.NEXT_TRANSFER_CALL, call_info.device_list[0]))
+        call_info.next_commands.append(NextCommand(device_info.device_id, NextType.NEXT_TRANSFER_CALL.code, call_info.device_list[0]))
         call_info.agent_key = agent_number
         # agent.sip_server
         Cache.add_call_info(call_info)

+ 6 - 7
src/core/callcenter/esl/client.py

@@ -40,8 +40,6 @@ class InboundClient:
         self.executors = {x: concurrent.futures.ThreadPoolExecutor(max_workers=1) for x in range(self.thread_num)}
 
         threading.Thread(target=self.start, args=()).start()
-        # gw = CacheUtil.getRouteGetway(saasId)
-        # self.make_call(gw, '63366692', '13241676588', 'C111111111', 'D1111111')
 
     def scan_esl_event_handlers(self):
         import inspect
@@ -115,21 +113,22 @@ class InboundClient:
 
     def make_call_new(self, context: MakeCallContext):
         called = context.get_called()
-        params = {'gateway': context.route_gateway_name, 'called': called, 'realm': context.pbx_server}
+        params = {'gateway': context.route_gateway_name, 'called': called, 'realm': context.get_realm()}
 
         builder = [
             '{', context.get_sip_header(), '}'
         ]
 
-        if context.device_type == DeviceType.CUSTOMER:
+        if context.device_type == DeviceType.CUSTOMER.code:
             profile = self.expression(profile1, params)
             builder.append(f"{SOFIA}{SK}{profile}{SK}{called}{PARK}")
         else:
             profile = self.expression(profile2, params)
-            builder.append(f"{SOFIA}{SK}{profile}{SK}{called}{PARK}")
+            builder.append(f"{profile}{PARK}")
         cmd = "".join(builder)
-        self.logger.info(cmd)
-        # self.con.bgapi(ORIGINATE, cmd)
+        print(cmd)
+        # self.logger.info(cmd)
+        self.con.bgapi(ORIGINATE, cmd)
 
     def make_call(self, route_gateway, display, called, call_id, device_id, timeout=30, originate_timeout=30, *sip_headers):
 

+ 12 - 10
src/core/callcenter/esl/handler/channel_answer_handler.py

@@ -2,6 +2,7 @@
 # encoding:utf-8
 
 import time
+from datetime import datetime
 from src.core.callcenter.constant import saasId, get_record_prefix
 import src.core.callcenter.cache as Cache
 from src.core.callcenter.enumeration import NextType, AnswerFlag, Direction, DeviceType
@@ -35,13 +36,13 @@ class ChannelAnswerHandler(EslEventHandler):
         call_info.answer_count = call_info.answer_count + 1
         call_info.next_commands.remove(next_command)
 
-        if NextType.NEXT_CALL_OTHER == next_command.next_type:
+        if NextType.NEXT_CALL_OTHER.code == next_command.next_type.code:
             self.call_other(call_info, device_info)
-        elif NextType.NEXT_CALL_BRIDGE == next_command.next_type:
+        elif NextType.NEXT_CALL_BRIDGE.code == next_command.next_type.code:
             self.call_bridge(call_info, device_info, next_command, event)
-        elif NextType.NEXT_TRANSFER_CALL == next_command.next_type:
+        elif NextType.NEXT_TRANSFER_CALL.code == next_command.next_type.code:
             self.transfer_call(call_info, next_command, event)
-        elif NextType.NEXT_LISTEN_CALL == next_command.next_type:
+        elif NextType.NEXT_LISTEN_CALL.code == next_command.next_type.code:
             self.listen(call_info, device_info, next_command, event)
         else:
             self.logger.warn("can not match command :%s, callId :%s", next_command.next_type, call_id)
@@ -57,8 +58,8 @@ class ChannelAnswerHandler(EslEventHandler):
         # device.record = record
         # device.record_start_time = device.answer_time
 
-        call.direction = Direction.OUTBOUND
-        call.answer_flag = AnswerFlag.AGENT_ANSWER
+        call.direction = Direction.OUTBOUND.code
+        call.answer_flag = AnswerFlag.AGENT_ANSWER.code
 
         new_device_id = 'D' + str(self.snowflake.next_id())
         call.device_list.append(new_device_id)
@@ -67,12 +68,13 @@ class ChannelAnswerHandler(EslEventHandler):
         self.logger.info("呼另外一侧电话: callId: %s, display:%s, called:%s, deviceId: %s ",
                          call_id, call.called_display, called, device_id)
 
-        now = lambda: int(round(time.time() * 1000))
+        # now = lambda: int(round(time.time() * 1000))
+        now = datetime.utcnow().timestamp()
         route_gateway = Cache.get_route_gateway(call.saas_id)
         new_device = DeviceInfo(device_id=new_device_id, call_id=call_id, agent_key=call.agent_key,
                                 called=called, display=call.called_display, caller=call.called_display,
-                                call_time=now, device_type=DeviceType.CUSTOMER, caller_display=route_gateway.name)
-        call.next_commands.append(NextCommand(device_id=device_id, next_type=NextType.NEXT_CALL_BRIDGE, next_value=new_device_id))
+                                call_time=now, device_type=DeviceType.CUSTOMER.code, caller_display=route_gateway.name)
+        call.next_commands.append(NextCommand(device_id=device_id, next_type=NextType.NEXT_CALL_BRIDGE.code, next_value=new_device_id))
         call.device_info_map[new_device_id] = new_device
         Cache.add_call_info(call)
         Cache.add_agent_info(call_info=call, call_id=call_id, device_id=device_id)
@@ -100,7 +102,7 @@ class ChannelAnswerHandler(EslEventHandler):
         # 转接电话 deviceInfo为被转接设备
         from_device_id = next_command.device_id
         device_id = EslEventUtil.getDeviceId(event)
-        call.next_commands.append(NextCommand(device_id, NextType.NEXT_TRANSFER_SUCCESS, call.device_list[1]))
+        call.next_commands.append(NextCommand(device_id, NextType.NEXT_TRANSFER_SUCCESS.code, call.device_list[1]))
         self.logger.info("转接电话中 callId:%s, from:%s, to:%s ", call.call_id, from_device_id, device_id)
         self.inbound_client.transfer_call(device_id, next_command.next_value)
 

+ 7 - 7
src/core/callcenter/esl/handler/channel_hangup_handler.py

@@ -70,8 +70,8 @@ class ChannelHangupHandler(EslEventHandler):
         call.device_info_map[device.device_id] = device
 
         # 如果是转人工
-        if 'transferToAgent' == hangup_reason and DeviceType.ROBOT == device.device_type:
-            call.answer_flag = AnswerFlag.TRANSFER_TO_AGENT
+        if 'transferToAgent' == hangup_reason and DeviceType.ROBOT.code == device.device_type.code:
+            call.answer_flag = AnswerFlag.TRANSFER_TO_AGENT.code
             service_id = EslEventUtil.getLIBRAServiceId(event)
             Cache.add_call_info(call)
             self.acd_service.transfer_to_agent(call, device, service_id)
@@ -100,14 +100,14 @@ class ChannelHangupHandler(EslEventHandler):
 
     def next_cmd(self, call: CallInfo, device: DeviceInfo, next_command: NextCommand, cause):
         # 呼入转到坐席,坐席拒接和坐席sip呼不通的时候,都需要再次转回来到技能组排队。
-        if NextType.NEXT_CALL_BRIDGE == next_command.next_type or NextType.NEXT_LISTEN_CALL == next_command.next_type:
+        if NextType.NEXT_CALL_BRIDGE.code == next_command.next_type.code or NextType.NEXT_LISTEN_CALL.code == next_command.next_type.code:
             pass
-        elif NextType.NEXT_TRANSFER_CALL:
+        elif NextType.NEXT_TRANSFER_CALL.code:
             pass
         else:
             pass
 
-        if not next_command or NextType.NEXT_HANGUP != next_command.next_type:
+        if not next_command or NextType.NEXT_HANGUP.code != next_command.next_type.code:
             call.next_commands.remove(next_command)
 
         # 判断挂机方向 && 更新缓存
@@ -118,9 +118,9 @@ class ChannelHangupHandler(EslEventHandler):
         if call.hangup_dir or device.cdr_type > CdrType.CONSULT.code:
             self.logger.info("hangup_dir::hangup_dir :%s, cdr_type :%s", call.hangup_dir, device.cdr_type)
             return
-        if DeviceType.AGENT == device.device_type:
+        if DeviceType.AGENT.code == device.device_type.code:
             call.hangup_dir = HangupDir.HOST_HANGUP.code
-        elif DeviceType.CUSTOMER == device.device_type:
+        elif DeviceType.CUSTOMER.code == device.device_type.code:
             call.hangup_dir = HangupDir.CUSTOMER_HANGUP.code
 
         if not call.end_time:

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
src/core/callcenter/test.py


+ 1 - 1
src/core/datasource.py

@@ -15,7 +15,7 @@ from src.core import singleton
 from redis import StrictRedis, ConnectionPool
 
 SERVE_HOST = os.environ.get("SERVE_HOST")
-# SERVE_HOST = "192.168.100.195"
+SERVE_HOST = "192.168.124.6"
 MYSQL_PASSWORD = 'EKoAe3H8xybQKrFPApXM'
 
 if SERVE_HOST != "192.168.100.159":

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.