DavidLiu 3 månader sedan
förälder
incheckning
e674842c1f

+ 2 - 1
.gitignore

@@ -1,3 +1,4 @@
+logs
 .vscode
 .vscode
 *.mar
 *.mar
 *.zip
 *.zip
@@ -33,4 +34,4 @@ output/*
 config/*.xlsx
 config/*.xlsx
 **.log
 **.log
 **.ipynb
 **.ipynb
-*.pyc
+*.pyc

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 22
logs/flask.log.1


+ 7 - 0
src/core/__init__.py

@@ -1,4 +1,11 @@
+from functools import wraps
 
 
+def with_app_context(func):
+    @wraps(func)
+    def wrapper(self, *args, **kwargs):
+        with self.app.app_context():
+            return func(self, *args, **kwargs)
+    return wrapper
 
 
 def singleton(cls):
 def singleton(cls):
     _instance = {}
     _instance = {}

+ 2 - 2
src/core/callcenter/acd.py

@@ -22,8 +22,8 @@ class AcdService:
         self.app = app
         self.app = app
         self.logger = app.logger
         self.logger = app.logger
         self.cache = Cache(app)
         self.cache = Cache(app)
-        self.call_service = CallService(client, app.logger)
-        self.agent_service = AgentOperService(client, app.logger)
+        self.call_service = CallService(client, app)
+        self.agent_service = AgentOperService(app)
         self.holdsQueue: Dict[str, Queue] = {}
         self.holdsQueue: Dict[str, Queue] = {}
         self.pool = ThreadPoolExecutor(max_workers=4)
         self.pool = ThreadPoolExecutor(max_workers=4)
         self.checkIdleScheduler = BackgroundScheduler()
         self.checkIdleScheduler = BackgroundScheduler()

+ 311 - 108
src/core/callcenter/agent.py

@@ -1,46 +1,251 @@
 #!/usr/bin/env python3
 #!/usr/bin/env python3
 # encoding:utf-8
 # encoding:utf-8
 
 
-import traceback
-from typing import List
+import threading
 from collections import defaultdict
 from collections import defaultdict
-from src.core.callcenter.constant import START_AGENT_NUM
-from src.core.callcenter.enumeration import AgentState, AgentCheck, AgentHeartState, AgentServiceState, AgentLogState, \
-    AgentScene, BizErrorCode, WorkStatus, DownEvent, HumanState
+from concurrent.futures import ThreadPoolExecutor
+from typing import List
+
 from sqlalchemy import or_
 from sqlalchemy import or_
+
+import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
+from src.core import with_app_context
+from src.core.callcenter.api import AgentActionRequest, AgentQueryRequest, AgentRequest, AgentEventData, \
+    AgentStateData, HumanServiceQueryRequest, AgentMonitorData, CallInfo, DeviceInfo, AgentDelayStateData
+from src.core.callcenter.cache import Cache
 from src.core.callcenter.dao import *
 from src.core.callcenter.dao import *
+from src.core.callcenter.data_handler import DataHandleServer
+from src.core.callcenter.enumeration import AgentState, AgentCheck, AgentHeartState, AgentServiceState, AgentLogState, \
+    AgentScene, BizErrorCode, WorkStatus, DownEvent, HumanState, DeviceType, ServiceDirect
+from src.core.callcenter.esl.constant.event_names import *
 from src.core.callcenter.exception import BizException
 from src.core.callcenter.exception import BizException
-from src.core.callcenter.api import AgentActionRequest, AgentInfo, AgentQueryRequest, AgentRequest, AgentEventData, \
-    AgentStateData, HumanServiceQueryRequest, AgentMonitorData
 from src.core.callcenter.push import PushHandler
 from src.core.callcenter.push import PushHandler
 from src.core.datasource import RedisHandler
 from src.core.datasource import RedisHandler
 
 
-from concurrent.futures import ThreadPoolExecutor
-import threading
+
+class AgentEventService:
+    def __init__(self, app):
+        self.app = app
+        self.logger = app.logger
+        self.cache = Cache(app)
+        self.push_handler = PushHandler(app.logger)
+        self.data_handle_server = DataHandleServer(app)
+        self.agent_monitor_service = AgentMonitorService(app)
+        self.agent_state_service = AgentStateService(app)
+        self.agent_actionlog_service = AgentActionLogService(app)
+
+    def delay_state(self, state_data: AgentDelayStateData):
+        agent = self.data_handle_server.get_agent(state_data.saas_id, state_data.agent_num)
+        if not agent:
+            return
+        agent_monitor = self.data_handle_server.get_agent_monitor(state_data.saas_id, state_data.agent_num)
+        if not agent_monitor:
+            return
+
+        #TODO 非最新通话的延迟事件,忽略.
+
+        agent_scene = AgentScene.get_by_code(state_data.scene)
+        self.logger.info("agent event delay state %s %s %s %s", state_data.saas_id, state_data.agent_num, state_data.service_state, agent_monitor.service_state)
+        if AgentServiceState.REPROCESSING.code == state_data.service_state and AgentServiceState.REPROCESSING.code == agent_monitor.service_state:
+            self.reprocessing_idle(state_data)
+
+        if AgentServiceState.DIALING.code == state_data.service_state and AgentServiceState.DIALING.code == agent_monitor.service_state:
+            if self.cache.get_call_is_answer(state_data.saas_id, state_data.agent_num):
+                return
+            self.agent_monitor_service.update_idle(agent_monitor)
+
+            self.push_handler.push_on_call_end(state_data.saas_id, state_data.flow_id, state_data.agent_num, agent_scene, ServiceDirect.MANUAL_CALL.service_direct, '0')
+            self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_REPROCESSING)
+            self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_IDLE)
+
+            self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.IDLE, AgentLogState.BIZ_DIALING_IDLE)
+
+        if AgentServiceState.HANGING.code == state_data.service_state \
+                and (AgentServiceState.DIALING.code == agent_monitor.service_state
+                     or AgentServiceState.CALLING.code == agent_monitor.service_state):
+            self.agent_monitor_service.update_idle(agent_monitor)
+
+            if AgentServiceState.DIALING.code == agent_monitor.service_state:
+                self.push_handler.push_on_call_end(state_data.saas_id, state_data.flow_id, state_data.agent_num, agent_scene, ServiceDirect.MANUAL_CALL.service_direct, '0')
+                self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_REPROCESSING)
+
+            self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, '', agent_scene, WorkStatus.AGENT_HANG_IDLE)
+            self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.IDLE, AgentLogState.MANUAL_HANG_UP)
+
+
+    def agent_event_channel(self, event, call_info: CallInfo, device_info: DeviceInfo):
+        event_name = EslEventUtil.getEventName(event)
+        saas_id = call_info.saas_id if call_info else None
+        flow_id = call_info.cti_flow_id if call_info else None
+        call_id = call_info.call_id if call_info else None
+        device_id = device_info.device_id if device_info else None
+        agent_num = device_info.agent_key if device_info else None
+        caller = device_info.caller if device_info else None
+        called = device_info.called if device_info else None
+        is_agent = (device_info and DeviceType.AGENT.code == device_info.device_type) if device_info else False
+
+        self.logger.info('agent_event_channel, event_name=%s, call_id=%s, device_id=%s, is_agent=%s', event_name, call_id, device_id, is_agent)
+        agent = self.data_handle_server.get_agent(saas_id, agent_num)
+        if not agent:
+            # self.logger.warn("event service channel agent is null %s %s %s %s %s", saas_id, event_name, caller, called, json.loads(event.serialize('json')))
+            return
+        agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_num)
+        if not agent_monitor:
+            # self.logger.warn("event service channel agentMonitor is null %s %s %s %s %s", saas_id, event_name, caller, called, json.loads(event.serialize('json')))
+            return
+
+        # 信道发起事件,触发完成发起(或桥)&& 坐席侧
+        if CHANNEL_ORIGINATE == event_name and is_agent:
+            self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_RINGING)
+
+        # 进度事件,外呼时对方提醒。或者入呼时提醒 && 坐席侧
+        if CHANNEL_PROGRESS == event_name and is_agent:
+            self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.DIALING)
+            self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_CALLING)
+
+        # 媒体进度事件,外呼时对方提醒。或者入呼时提醒 && 用户侧
+        if CHANNEL_PROGRESS_MEDIA == event_name and not is_agent:
+            self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_CALLING_RINGING)
+
+        #应答
+        if CHANNEL_ANSWER == event_name:
+            if call_id:
+                if self.cache.get_call_is_end(call_id):
+                    # self.logger.warn("event service channel call is end {} {} {} {} {} {}", saas_id, event_name, caller, called, call_id, json.dumps(event.serialize('json')))
+                    return
+
+            self.agent_state_service.busy(saas_id, agent.agent_num, agent.phone_num)
+            if is_agent:
+                # 坐席接起
+                self.cache.set_call_is_answer(saas_id, flow_id)
+                self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.ANSWER_COMPENSATE)
+                self.push_handler.push_answer_call(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, ServiceDirect.MANUAL_CALL.service_direct, WorkStatus.AGENT_HANG_REPROCESSING)
+
+                self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.CALLING, AgentLogState.CHANNEL_TURN_ON)
+            else:
+                # 用户侧接起
+                self.agent_monitor_service.update_calling(agent_monitor)
+                self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_ANSWER_OUTGOING)
+                self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.CALLING)
+
+        #挂断
+        if CHANNEL_HANGUP == event_name:
+            # 坐席侧挂断
+            if is_agent:
+                if call_id:
+                    self.cache.set_call_is_end(call_id)
+
+            self.agent_monitor_service.update_processing(agent_monitor)
+            self.reprocessing_idle(AgentDelayStateData(saas_id, flow_id, agent_num, AgentServiceState.REPROCESSING, AgentScene.MANUAL))
+            self.push_handler.push_on_call_end(saas_id, flow_id, agent_num, AgentScene.MANUAL, ServiceDirect.MANUAL_CALL.service_direct, '0')
+            self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_HANG_REPROCESSING)
+            self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.REPROCESSING)
+
+            self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.REPROCESSING, AgentLogState.CHANNEL_HANG_UP)
+
+            # 同步处理后处理置闲
+            # reprocessingIdle(statusDto);
+            # agentProducer.pushDelayedStatus(statusDto, reprocessingTimeout);
+
+        if (CHANNEL_BRIDGE == event_name or PLAYBACK_START == event_name) and is_agent:
+            self.push_handler.push_on_ring_start(saas_id, flow_id, agent_num, AgentScene.MANUAL, call_id)
+            # self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.MANUAL, WorkStatus.AGENT_ANSWER_OUTGOING)
+            # self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.MANUAL, AgentServiceState.CALLING)
+
+        if DETECTED_TONE == event_name and not is_agent:
+            self.push_handler.push_on_detected_tone(saas_id, flow_id, call_id, AgentScene.MANUAL, call_id)
+
+        if (CHANNEL_UNBRIDGE == event_name or PLAYBACK_STOP == event_name) and is_agent:
+            self.push_handler.push_on_ring_end(saas_id, flow_id, call_id, AgentScene.MANUAL, call_id)
+
+
+    def bot_event_channel(self, event, call_info, device_info):
+        event_name = EslEventUtil.getEventName(event)
+        saas_id = call_info.saas_id if call_info else None
+        flow_id = call_info.cti_flow_id if call_info else None
+        call_id = call_info.call_id if call_info else None
+        agent_num = device_info.agent_key if device_info else None
+        is_agent = (device_info and DeviceType.AGENT.code == device_info.device_type) if device_info else False
+        caller = (device_info.called if is_agent else device_info.caller) if device_info else None
+        called = (device_info.caller if is_agent else device_info.called) if device_info else None
+        human_service_id = '00000000000000000'
+
+        agent = self.data_handle_server.get_agent(saas_id, agent_num)
+        if not agent:
+            # self.logger.warn("bot event service channel agent is null %s %s %s %s %s", saas_id, event_name, caller, called,
+            #                  json.dumps(event.serialize('json')))
+            return
+        agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_num)
+        if not agent_monitor:
+            # self.logger.warn("bot event service channel agentMonitor is null %s %s %s %s %s", saas_id, event_name, caller,
+            #                  called, json.dumps(event.serialize('json')))
+            return
+
+        # 信道发起事件,触发完成发起(或桥)&& 坐席侧
+        if CHANNEL_ORIGINATE == event_name and is_agent:
+            self.push_handler.push_on_call_ring(saas_id, flow_id, agent_num, AgentScene.ROBOT, call_id, ServiceDirect.ROBOT_CALL.service_direct, called, caller, human_service_id)
+            self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_RINGING)
+
+
+        if CHANNEL_ANSWER == event_name:
+            self.agent_state_service.busy(saas_id, agent.agent_num, agent.phone_num)
+            if is_agent:
+                self.agent_monitor_service.update_calling(agent_monitor)
+                self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_ANSWER_INCOMING, "座席接通呼入电话! internal")
+                self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.ROBOT, AgentServiceState.CALLING)
+                self.push_handler.push_answer_call(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, ServiceDirect.ROBOT_CALL.service_direct, WorkStatus.AGENT_HANG_REPROCESSING)
+
+                self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.CALLING, AgentLogState.CHANNEL_TURN_ON, service_id=human_service_id)
+            else:
+                self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_ANSWER_INCOMING, "座席接通呼入电话! external")
+
+        if CHANNEL_HANGUP == event_name and is_agent:
+            self.agent_monitor_service.update_processing(agent_monitor)
+            self.push_handler.push_on_call_end(saas_id, flow_id, agent_num, AgentScene.ROBOT, ServiceDirect.ROBOT_CALL.service_direct, "0")
+            self.push_handler.push_on_agent_work_report(saas_id, flow_id, agent_num, call_id, AgentScene.ROBOT, WorkStatus.AGENT_HANG_REPROCESSING)
+            self.push_handler.push_on_agent_report(saas_id, agent_num, AgentScene.ROBOT, AgentServiceState.REPROCESSING)
+
+            self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.REPROCESSING,
+                                                  AgentLogState.CHANNEL_HANG_UP, service_id=human_service_id)
+
+
+    def reprocessing_idle(self, state_data: AgentDelayStateData):
+        agent = self.data_handle_server.get_agent(state_data.saas_id, state_data.agent_num)
+        if not agent:
+            return
+        agent_monitor = self.data_handle_server.get_agent_monitor(state_data.saas_id, state_data.agent_num)
+        if not agent_monitor:
+            return
+        self.agent_monitor_service.update_idle(agent_monitor)
+        self.push_handler.push_on_agent_work_report(state_data.saas_id, state_data.flow_id, state_data.agent_num, "", state_data.scene, WorkStatus.AGENT_HANG_IDLE)
+        self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.IDLE, AgentLogState.REPROCESSING_IDLE)
 
 
 
 
 class AgentOperService:
 class AgentOperService:
 
 
-    def __init__(self, client, logger):
-        self.inbound_client = client
-        self.logger = logger
-        self.push_handler = PushHandler(logger)
-        self.agent_monitor_service = AgentMonitorService(client, logger)
-        self.agent_actionlog_service = AgentActionLogService(client, logger)
-        self.agent_state_service = AgentStateService(client, logger)
+    def __init__(self, app):
+        self.app = app
+        self.logger = app.logger
+        self.push_handler = PushHandler(app.logger)
+        self.data_handle_server = DataHandleServer(app)
+        self.agent_monitor_service = AgentMonitorService(app)
+        self.agent_actionlog_service = AgentActionLogService(app)
+        self.agent_state_service = AgentStateService(app)
 
 
+    @with_app_context
     def enable(self, req: AgentActionRequest):
     def enable(self, req: AgentActionRequest):
-        agent = _get_agent(req.saas_id, req.agent_number, req.out_id)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_number, req.out_id)
         if agent.agent_state == AgentState.ENABLE.code:
         if agent.agent_state == AgentState.ENABLE.code:
             return
             return
         agent.agent_state = AgentState.ENABLE.code
         agent.agent_state = AgentState.ENABLE.code
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def disable(self, req: AgentActionRequest):
     def disable(self, req: AgentActionRequest):
-        agent = _get_agent(req.saas_id, req.agent_id)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
         if agent.agent_state == AgentState.DISABLE.code:
         if agent.agent_state == AgentState.DISABLE.code:
             return
             return
-        agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_number)
+        agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_number)
         if agent_monitor.check_state == AgentCheck.IN.code and \
         if agent_monitor.check_state == AgentCheck.IN.code and \
                 agent_monitor.service_state == AgentServiceState.CALLING.code:
                 agent_monitor.service_state == AgentServiceState.CALLING.code:
             raise BizException(BizErrorCode.AGENT_CALLING_NOT_ALLOW_OPERATE)
             raise BizException(BizErrorCode.AGENT_CALLING_NOT_ALLOW_OPERATE)
@@ -49,36 +254,34 @@ class AgentOperService:
         agent.agent_state = AgentState.DISABLE.code
         agent.agent_state = AgentState.DISABLE.code
         db.session.commit()
         db.session.commit()
 
 
-        phone = _get_phone(req.saas_id, agent.phone_num)
+        phone = self.data_handle_server.get_phone(req.saas_id, agent.phone_num)
         phone.is_delete = 1
         phone.is_delete = 1
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def checkin(self, req: AgentActionRequest):
     def checkin(self, req: AgentActionRequest):
-       try:
-           agent = _get_agent(req.saas_id, req.agent_id)
-           if not agent or agent.agent_state == AgentState.DISABLE.code:
-               raise BizException(BizErrorCode.ERROR_NOT_FOLLOW_CHECK_IN)
-           phone = _get_phone(req.saas_id, agent.phone_num)
-           agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
-           agent_monitor.check_scene = req.scene
-           self.agent_monitor_service.update_checkin(agent_monitor)
-           self.agent_actionlog_service.insert_check_state(agent_monitor, AgentCheck.IN, AgentLogState.CHECKIN)
-           self.agent_state_service.checkin(agent.saas_id, agent.out_id, agent.phone_num)
-
-           if req.scene == AgentScene.MANUAL.code:
-               # 如果是手动外呼增加置闲
-               self._handle_idle(req.scene, agent)
-           return self._push_event_for_checkin(agent, agent_monitor, phone, req.scene)
-       except Exception as e:
-           self.logger.error(traceback.format_exc())
-           raise e
-
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
+        if not agent or agent.agent_state == AgentState.DISABLE.code:
+            raise BizException(BizErrorCode.ERROR_NOT_FOLLOW_CHECK_IN)
+        phone = self.data_handle_server.get_phone(req.saas_id, agent.phone_num)
+        agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
+        agent_monitor.check_scene = req.scene
+        self.agent_monitor_service.update_checkin(agent_monitor)
+        self.agent_actionlog_service.insert_check_state(agent_monitor, AgentCheck.IN, AgentLogState.CHECKIN)
+        self.agent_state_service.checkin(agent.saas_id, agent.out_id, agent.phone_num)
+
+        # if req.scene == AgentScene.MANUAL.code:
+        #     # 如果是手动外呼增加置忙
+        #     self._handle_idle(req.scene, agent)
+        return self._push_event_for_checkin(agent, agent_monitor, phone, req.scene)
+
+    @with_app_context
     def checkout(self, req: AgentActionRequest):
     def checkout(self, req: AgentActionRequest):
-        agent = _get_agent(req.saas_id, req.agent_id)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
         if not agent or agent.agent_state == AgentState.DISABLE.code:
         if not agent or agent.agent_state == AgentState.DISABLE.code:
             raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
             raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
 
 
-        agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
+        agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
         if not agent_monitor or agent_monitor.service_state == AgentServiceState.CALLING.code:
         if not agent_monitor or agent_monitor.service_state == AgentServiceState.CALLING.code:
             raise BizException(BizErrorCode.AGENT_CALLING_NOT_ALLOW_OPERATE)
             raise BizException(BizErrorCode.AGENT_CALLING_NOT_ALLOW_OPERATE)
 
 
@@ -91,12 +294,13 @@ class AgentOperService:
 
 
         return self._push_event_for_checkout(agent, req.scene)
         return self._push_event_for_checkout(agent, req.scene)
 
 
+    @with_app_context
     def busy(self, req: AgentActionRequest):
     def busy(self, req: AgentActionRequest):
-        agent = _get_agent(req.saas_id, req.agent_id)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
         if not agent or agent.agent_state == AgentState.DISABLE.code:
         if not agent or agent.agent_state == AgentState.DISABLE.code:
             raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
             raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
 
 
-        agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
+        agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
         if not agent_monitor or agent_monitor.check_state == AgentCheck.OUT.code:
         if not agent_monitor or agent_monitor.check_state == AgentCheck.OUT.code:
             raise BizException(BizErrorCode.AGENT_CHECK_OUT_NOT_ALLOW_OPERATE)
             raise BizException(BizErrorCode.AGENT_CHECK_OUT_NOT_ALLOW_OPERATE)
 
 
@@ -112,25 +316,30 @@ class AgentOperService:
         self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.BUSY, AgentLogState.BUSY)
         self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.BUSY, AgentLogState.BUSY)
         self._push_event_for_busy(agent, req.scene)
         self._push_event_for_busy(agent, req.scene)
 
 
+    @with_app_context
     def idle(self, req: AgentActionRequest):
     def idle(self, req: AgentActionRequest):
-        agent = _get_agent(req.saas_id, req.agent_id)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
         if not agent or agent.agent_state == AgentState.DISABLE.code:
         if not agent or agent.agent_state == AgentState.DISABLE.code:
             raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
             raise BizException(BizErrorCode.AGENT_DISABLE_NOT_ALLOW_OPERATE)
         self._handle_idle(req.scene, agent)
         self._handle_idle(req.scene, agent)
 
 
+    @with_app_context
     def assign(self, req: AgentActionRequest):
     def assign(self, req: AgentActionRequest):
         return self.agent_state_service.assign_agent(req.saas_id, req.service_id)
         return self.agent_state_service.assign_agent(req.saas_id, req.service_id)
 
 
     def idle_agent_exist(self, request: AgentActionRequest):
     def idle_agent_exist(self, request: AgentActionRequest):
         pass
         pass
+
+    @with_app_context
     def agent_state(self,req: AgentActionRequest):
     def agent_state(self,req: AgentActionRequest):
         # agent = _get_agent(req.saas_id, req.agent_id)
         # agent = _get_agent(req.saas_id, req.agent_id)
-        agent_monitor = _get_agent_monitor(req.saas_id, req.agent_id)
+        agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, req.agent_id)
         return agent_monitor.service_state
         return agent_monitor.service_state
 
 
+    @with_app_context
     def turn_on(self, req: AgentActionRequest):
     def turn_on(self, req: AgentActionRequest):
-        agent = _get_agent(req.saas_id, req.agent_id)
-        agent_monitor = _get_agent_monitor(req.saas_id, agent.agent_num)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
+        agent_monitor = self.data_handle_server.get_agent_monitor(req.saas_id, agent.agent_num)
         agent_scene = AgentScene.get_by_code(req.scene)
         agent_scene = AgentScene.get_by_code(req.scene)
         if not agent_monitor:
         if not agent_monitor:
             raise BizException(BizErrorCode.RECORD_NOT_EXIST_ERROR)
             raise BizException(BizErrorCode.RECORD_NOT_EXIST_ERROR)
@@ -143,8 +352,9 @@ class AgentOperService:
         self.agent_state_service.busy(agent.saas_id, agent.out_id, agent.phone_num)
         self.agent_state_service.busy(agent.saas_id, agent.out_id, agent.phone_num)
         self.push_handler.push_on_agent_report(agent.saas_id, agent.out_id, agent_scene, AgentServiceState.BUSY)
         self.push_handler.push_on_agent_report(agent.saas_id, agent.out_id, agent_scene, AgentServiceState.BUSY)
 
 
+    @with_app_context
     def _handle_idle(self, scene, agent):
     def _handle_idle(self, scene, agent):
-        agent_monitor = _get_agent_monitor(agent.saas_id, agent.agent_num)
+        agent_monitor = self.data_handle_server.get_agent_monitor(agent.saas_id, agent.agent_num)
         if agent_monitor.check_state == AgentCheck.OUT.code:
         if agent_monitor.check_state == AgentCheck.OUT.code:
             raise BizException(BizErrorCode.AGENT_CHECK_OUT_NOT_ALLOW_OPERATE)
             raise BizException(BizErrorCode.AGENT_CHECK_OUT_NOT_ALLOW_OPERATE)
         if agent_monitor.service_state == AgentServiceState.CALLING.code or agent_monitor.service_state == AgentServiceState.DIALING.code:
         if agent_monitor.service_state == AgentServiceState.CALLING.code or agent_monitor.service_state == AgentServiceState.DIALING.code:
@@ -206,18 +416,21 @@ class AgentOperService:
 
 
 class AgentService:
 class AgentService:
 
 
-    def __init__(self, client, logger):
-        self.inbound_client = client
-        self.logger = logger
-        self.agent_monitor_service = AgentMonitorService(client, logger)
+    def __init__(self, app):
+        self.app = app
+        self.logger = app.logger
+        self.data_handle_server = DataHandleServer(app)
+        self.agent_monitor_service = AgentMonitorService(app)
 
 
+    @with_app_context
     def get_and_check(self, req: AgentActionRequest):
     def get_and_check(self, req: AgentActionRequest):
-        agent = _get_agent(req.saas_id, req.agent_id)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_id)
         if not agent:
         if not agent:
             return {}
             return {}
-        phone = _get_phone(req.saas_id, agent.phone_num)
+        phone = self.data_handle_server.get_phone(req.saas_id, agent.phone_num)
         return phone.to_dict()
         return phone.to_dict()
 
 
+    @with_app_context
     def watch_agent_state(self, req: HumanServiceQueryRequest):
     def watch_agent_state(self, req: HumanServiceQueryRequest):
         pos = HumanServiceMap.query.filter(HumanServiceMap.is_delete == 0, HumanServiceMap.saas_id == req.saas_id,
         pos = HumanServiceMap.query.filter(HumanServiceMap.is_delete == 0, HumanServiceMap.saas_id == req.saas_id,
                                            HumanServiceMap.service_id == req.serviceId).all()
                                            HumanServiceMap.service_id == req.serviceId).all()
@@ -225,8 +438,9 @@ class AgentService:
         monitors = self.agent_monitor_service.detail_monitor_out_ids(req.saas_id, agent_ids)
         monitors = self.agent_monitor_service.detail_monitor_out_ids(req.saas_id, agent_ids)
         return monitors
         return monitors
 
 
+    @with_app_context
     def add(self, req: AgentRequest):
     def add(self, req: AgentRequest):
-        new_agent_num = _get_newest_agent_number(req.saas_id)
+        new_agent_num = self.data_handle_server.get_newest_agent_number(req.saas_id)
         agent = Agent(saas_id=req.saas_id, agent_num=new_agent_num, agent_name=req.agent_name, out_id=req.out_id,
         agent = Agent(saas_id=req.saas_id, agent_num=new_agent_num, agent_name=req.agent_name, out_id=req.out_id,
                       agent_pwd=req.agent_password, agent_type=req.agent_type, phone_num=req.phone_number,
                       agent_pwd=req.agent_password, agent_type=req.agent_type, phone_num=req.phone_number,
                       distribute=req.distribute, agent_state=req.agent_state)
                       distribute=req.distribute, agent_state=req.agent_state)
@@ -238,8 +452,9 @@ class AgentService:
         db.session.commit()
         db.session.commit()
         return new_agent_num
         return new_agent_num
 
 
+    @with_app_context
     def update(self, req: AgentRequest):
     def update(self, req: AgentRequest):
-        agent = _get_agent(req.saas_id, req.agent_number, req.out_id)
+        agent = self.data_handle_server.get_agent(req.saas_id, req.agent_number, req.out_id)
         if not agent:
         if not agent:
             return
             return
         phone_num = agent.phone_num
         phone_num = agent.phone_num
@@ -259,10 +474,12 @@ class AgentService:
             if phone:
             if phone:
                 db.session.delete(phone)
                 db.session.delete(phone)
 
 
+    @with_app_context
     def detail(self, saas_id, agent_number):
     def detail(self, saas_id, agent_number):
-        agent = _get_agent(saas_id, agent_number=agent_number, out_id='')
+        agent = self.data_handle_server.get_agent(saas_id, agent_number=agent_number, out_id='')
         return agent
         return agent
 
 
+    @with_app_context
     def count(self, req: AgentQueryRequest):
     def count(self, req: AgentQueryRequest):
         cnt = Agent.query.filter(Agent.saas_id == req.saas_id,
         cnt = Agent.query.filter(Agent.saas_id == req.saas_id,
                                  or_(Agent.agent_num == req.agent_number,
                                  or_(Agent.agent_num == req.agent_number,
@@ -273,6 +490,7 @@ class AgentService:
                                  ).count()
                                  ).count()
         return cnt
         return cnt
 
 
+    @with_app_context
     def query_page(self, req: AgentQueryRequest):
     def query_page(self, req: AgentQueryRequest):
         pagination = Agent.query.filter(Agent.saas_id == req.saas_id,
         pagination = Agent.query.filter(Agent.saas_id == req.saas_id,
                                         or_(Agent.agent_num == req.agent_number,
                                         or_(Agent.agent_num == req.agent_number,
@@ -298,27 +516,30 @@ class AgentService:
         # }
         # }
         return pagination
         return pagination
 
 
+    @with_app_context
     def delete(self, saas_id, agent_number):
     def delete(self, saas_id, agent_number):
-        agent = _get_agent(saas_id, agent_number=agent_number, out_id='')
+        agent = self.data_handle_server.get_agent(saas_id, agent_number=agent_number, out_id='')
         if not agent:
         if not agent:
             return
             return
         agent.is_delete = 1
         agent.is_delete = 1
 
 
-        agent_monitor = _get_agent_monitor(saas_id, agent_number)
+        agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_number)
         agent_monitor.is_delete = 1
         agent_monitor.is_delete = 1
         db.session.commit()
         db.session.commit()
 
 
-        phone = _get_phone(saas_id, agent.phone_num)
+        phone = self.data_handle_server.get_phone(saas_id, agent.phone_num)
         phone.is_delete = 1
         phone.is_delete = 1
         db.session.commit()
         db.session.commit()
 
 
 
 
 class AgentMonitorService:
 class AgentMonitorService:
 
 
-    def __init__(self, client, logger):
-        self.inbound_client = client
-        self.logger = logger
+    def __init__(self, app):
+        self.app = app
+        self.logger = app.logger
+        self.data_handle_server = DataHandleServer(app)
 
 
+    @with_app_context
     def detail_monitor_out_ids(self, saas_id, out_ids, check_scene=None):
     def detail_monitor_out_ids(self, saas_id, out_ids, check_scene=None):
         if not out_ids:
         if not out_ids:
             return []
             return []
@@ -360,6 +581,7 @@ class AgentMonitorService:
             res.append(data.__dict__)
             res.append(data.__dict__)
         return res
         return res
 
 
+    @with_app_context
     def update_checkin(self, agent_monitor):
     def update_checkin(self, agent_monitor):
         agent_monitor.check_state = AgentCheck.IN.code
         agent_monitor.check_state = AgentCheck.IN.code
         agent_monitor.check_in_time = datetime.utcnow()
         agent_monitor.check_in_time = datetime.utcnow()
@@ -367,6 +589,7 @@ class AgentMonitorService:
         agent_monitor.heart_time = datetime.utcnow()
         agent_monitor.heart_time = datetime.utcnow()
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_checkout(self, agent_monitor):
     def update_checkout(self, agent_monitor):
         agent_monitor.check_state = AgentCheck.OUT.code
         agent_monitor.check_state = AgentCheck.OUT.code
         agent_monitor.check_out_time = datetime.utcnow()
         agent_monitor.check_out_time = datetime.utcnow()
@@ -376,34 +599,41 @@ class AgentMonitorService:
         self.logger.info("update_checkout %s", agent_monitor.check_out_time)
         self.logger.info("update_checkout %s", agent_monitor.check_out_time)
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_idle(self, agent_monitor):
     def update_idle(self, agent_monitor):
         agent_monitor.service_state = AgentServiceState.IDLE.code
         agent_monitor.service_state = AgentServiceState.IDLE.code
         agent_monitor.idle_time = datetime.utcnow()
         agent_monitor.idle_time = datetime.utcnow()
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_busy(self, agent_monitor):
     def update_busy(self, agent_monitor):
         agent_monitor.service_state = AgentServiceState.BUSY.code
         agent_monitor.service_state = AgentServiceState.BUSY.code
         agent_monitor.busy_time = datetime.utcnow()
         agent_monitor.busy_time = datetime.utcnow()
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_dialing(self, agent_monitor):
     def update_dialing(self, agent_monitor):
         agent_monitor.service_state = AgentServiceState.DIALING.code
         agent_monitor.service_state = AgentServiceState.DIALING.code
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_calling(self, agent_monitor):
     def update_calling(self, agent_monitor):
         agent_monitor.service_state = AgentServiceState.CALLING.code
         agent_monitor.service_state = AgentServiceState.CALLING.code
         agent_monitor.call_time = datetime.utcnow()
         agent_monitor.call_time = datetime.utcnow()
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_processing(self, agent_monitor):
     def update_processing(self, agent_monitor):
         agent_monitor.service_state = AgentServiceState.REPROCESSING.code
         agent_monitor.service_state = AgentServiceState.REPROCESSING.code
         agent_monitor.hang_time = datetime.utcnow()
         agent_monitor.hang_time = datetime.utcnow()
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_session_id(self, agent_monitor, session_id):
     def update_session_id(self, agent_monitor, session_id):
         agent_monitor.session_id = session_id
         agent_monitor.session_id = session_id
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def update_heart_error(self, agent_monitor):
     def update_heart_error(self, agent_monitor):
         agent_monitor.heart_state = AgentHeartState.ABNORMAL.code
         agent_monitor.heart_state = AgentHeartState.ABNORMAL.code
         agent_monitor.heart_time = datetime.utcnow()
         agent_monitor.heart_time = datetime.utcnow()
@@ -416,10 +646,12 @@ class AgentMonitorService:
 
 
 class AgentActionLogService:
 class AgentActionLogService:
 
 
-    def __init__(self, client, logger):
-        self.inbound_client = client
-        self.logger = logger
+    def __init__(self, app):
+        self.app = app
+        self.logger = app.logger
+        self.data_handle_server = DataHandleServer(app)
 
 
+    @with_app_context
     def insert_check_state(self, agent_monitor, agent_check_enum: AgentCheck, agent_log_enum: AgentLogState):
     def insert_check_state(self, agent_monitor, agent_check_enum: AgentCheck, agent_log_enum: AgentLogState):
         action_log = AgentActionLog()
         action_log = AgentActionLog()
         action_log.saas_id = agent_monitor.saas_id
         action_log.saas_id = agent_monitor.saas_id
@@ -445,6 +677,7 @@ class AgentActionLogService:
         db.session.add(action_log)
         db.session.add(action_log)
         db.session.commit()
         db.session.commit()
 
 
+    @with_app_context
     def insert_service_state(self, agent_monitor, agent_service_state: AgentServiceState, agent_log_enum: AgentLogState,
     def insert_service_state(self, agent_monitor, agent_service_state: AgentServiceState, agent_log_enum: AgentLogState,
                              task_id=None, service_id=None):
                              task_id=None, service_id=None):
         if agent_monitor.service_state == agent_service_state.code:
         if agent_monitor.service_state == agent_service_state.code:
@@ -485,35 +718,36 @@ class AgentActionLogService:
 
 
 class AgentStateService:
 class AgentStateService:
 
 
-    def __init__(self, client, logger):
-        self.inbound_client = client
-        self.logger = logger
+    def __init__(self, app):
+        self.app = app
+        self.logger = app.logger
         self.redis_handler = RedisHandler()
         self.redis_handler = RedisHandler()
         self.assigned_recycle_millisecond = 60000
         self.assigned_recycle_millisecond = 60000
         self.state_service_id_data_map = defaultdict(dict)
         self.state_service_id_data_map = defaultdict(dict)
         self.executor = ThreadPoolExecutor(max_workers=10)
         self.executor = ThreadPoolExecutor(max_workers=10)
-        self.agent_monitor_service = AgentMonitorService(client, logger)
-        self.agent_actionlog_service = AgentActionLogService(client, logger)
+        self.data_handle_server = DataHandleServer(app)
+        self.agent_monitor_service = AgentMonitorService(app)
+        self.agent_actionlog_service = AgentActionLogService(app)
 
 
     def idle(self, saas_id, agent_id, phone_num):
     def idle(self, saas_id, agent_id, phone_num):
-        human_service = _get_human_service_service(saas_id, agent_id)
+        human_service = self.data_handle_server.get_human_service_service(saas_id, agent_id)
         if human_service is None:
         if human_service is None:
             self.logger.info(f"agent engine idle not have human service {saas_id} {agent_id}")  # 使用print替代log
             self.logger.info(f"agent engine idle not have human service {saas_id} {agent_id}")  # 使用print替代log
             return
             return
         self.idle_hash(saas_id, agent_id, phone_num, human_service.service_id)
         self.idle_hash(saas_id, agent_id, phone_num, human_service.service_id)
 
 
     def busy(self, saas_id, agent_id, phone_num):
     def busy(self, saas_id, agent_id, phone_num):
-        human_service = _get_human_service_service(saas_id, agent_id)
+        human_service = self.data_handle_server.get_human_service_service(saas_id, agent_id)
         if human_service is None:
         if human_service is None:
             self.logger.info(f"agent engine busy not hava human service {saas_id} {agent_id}")  # 使用print替代log
             self.logger.info(f"agent engine busy not hava human service {saas_id} {agent_id}")  # 使用print替代log
             return
             return
         self.busy_hash(saas_id, agent_id, phone_num, human_service.service_id)
         self.busy_hash(saas_id, agent_id, phone_num, human_service.service_id)
 
 
     def idle_by_human(self, saas_id, agent_id, service_id):
     def idle_by_human(self, saas_id, agent_id, service_id):
-        agent = _get_agent(saas_id, out_id=agent_id)
+        agent = self.data_handle_server.get_agent(saas_id, out_id=agent_id)
         if not agent:
         if not agent:
             return
             return
-        agent_monitor = _get_agent_monitor(saas_id, agent_number=agent.agent_num)
+        agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_number=agent.agent_num)
         if not agent_monitor:
         if not agent_monitor:
             return
             return
         if agent_monitor.check_state == AgentCheck.IN.code:
         if agent_monitor.check_state == AgentCheck.IN.code:
@@ -522,10 +756,10 @@ class AgentStateService:
             self.idle_hash(saas_id, agent_id, agent.phone_num, service_id)
             self.idle_hash(saas_id, agent_id, agent.phone_num, service_id)
 
 
     def busy_by_human(self, saas_id, service_id, agent_id=None):
     def busy_by_human(self, saas_id, service_id, agent_id=None):
-        agent = _get_agent(saas_id, out_id=agent_id)
+        agent = self.data_handle_server.get_agent(saas_id, out_id=agent_id)
         if not agent:
         if not agent:
             return
             return
-        agent_monitor = _get_agent_monitor(saas_id, agent_number=agent.agent_num)
+        agent_monitor = self.data_handle_server.get_agent_monitor(saas_id, agent_number=agent.agent_num)
         if not agent_monitor:
         if not agent_monitor:
             return
             return
         if agent_monitor.check_state == AgentCheck.IN.code:
         if agent_monitor.check_state == AgentCheck.IN.code:
@@ -697,34 +931,3 @@ class AgentStateService:
         idle_agents = sorted(idle_agents, key=lambda agent: agent.assign_time, reverse=False)
         idle_agents = sorted(idle_agents, key=lambda agent: agent.assign_time, reverse=False)
         return idle_agents[0].phone_num
         return idle_agents[0].phone_num
 
 
-
-def _get_agent(saas_id, agent_id=None, agent_number=None, out_id=None):
-    agent = Agent.query.filter(
-        Agent.saas_id == saas_id,
-        or_(Agent.out_id == agent_id, Agent.out_id == out_id, Agent.agent_num == agent_number)
-    ).first()
-    return agent
-
-
-def _get_newest_agent_number(saas_id):
-    agent = Agent.query.filter(Agent.saas_id == saas_id).order_by(Agent.agent_num.desc()).first()
-    agentNum = START_AGENT_NUM
-    if agent and agent.agent_num:
-        agentNum = str(int(agent.agent_num) + 1)
-    return agentNum
-
-
-def _get_agent_monitor(saas_id, agent_number):
-    monitor = AgentMonitor.query.filter(AgentMonitor.saas_id == saas_id,
-                                        AgentMonitor.agent_num == agent_number).first()
-    return monitor
-
-
-def _get_phone(saas_id, phone_num):
-    phone = Phone.query.filter(Phone.saas_id == saas_id, Phone.phone_num == phone_num).first()
-    return phone
-
-
-def _get_human_service_service(saas_id, agent_id):
-    human_service_map = HumanServiceMap.query.filter(HumanServiceMap.saas_id == saas_id, HumanServiceMap.agent_id ==agent_id).first()
-    return human_service_map

+ 12 - 2
src/core/callcenter/api.py

@@ -176,15 +176,25 @@ class AgentStateData(BaseApi):
         self.assign_time = assign_time
         self.assign_time = assign_time
         self.phone_num = phone_num
         self.phone_num = phone_num
 
 
+class AgentDelayStateData(BaseApi):
+    def __init__(self, saas_id=None, flow_id=None, agent_num=None, service_state=None, scene=None):
+        self.saas_id = saas_id
+        self.flow_id = flow_id
+        self.agent_num = agent_num
+        self.service_state = service_state
+        self.scene = scene
 
 
 class HangupCallRequest(BaseApi):
 class HangupCallRequest(BaseApi):
-    def __init__(self, saas_id, call_id, agent_number):
+    def __init__(self, saas_id=None, flow_id=None, agent_id=None, called=None, call_id=None, scene=None):
         # saasId(必填)
         # saasId(必填)
         self.saas_id = saas_id
         self.saas_id = saas_id
+        self.flow_id = flow_id
         # 呼叫唯一id(选填)
         # 呼叫唯一id(选填)
         self.call_id = call_id
         self.call_id = call_id
+        self.called = called
         # 分机号(必填)
         # 分机号(必填)
-        self.agent_number = agent_number
+        self.agent_id = agent_id
+        self.scene = scene
 
 
 
 
 class CheckInCallRequest(BaseApi):
 class CheckInCallRequest(BaseApi):

+ 19 - 4
src/core/callcenter/cache.py

@@ -68,10 +68,9 @@ class Cache:
         self.redis_handler.set(CALL_INFO + call.call_id, call.to_json_string(), self.cacheDay * 24 * 60 * 60)
         self.redis_handler.set(CALL_INFO + call.call_id, call.to_json_string(), self.cacheDay * 24 * 60 * 60)
 
 
 
 
-    def get_call_info_by_device_id(self, device_id):
+    def get_call_id_by_device_id(self, device_id):
         call_id = self.deviceCall.get(device_id)
         call_id = self.deviceCall.get(device_id)
-        if not call_id:
-            return self.get_call_info(call_id)
+        return call_id
 
 
 
 
     # 获取callInfo
     # 获取callInfo
@@ -164,4 +163,20 @@ class Cache:
 
 
     def get_after_play_hold_music(self, call_id):
     def get_after_play_hold_music(self, call_id):
         key = AFTER_PLAY_HOLD_MUSIC % call_id
         key = AFTER_PLAY_HOLD_MUSIC % call_id
-        return self.redis_handler.redis.get(key)
+        return self.redis_handler.redis.get(key)
+
+    def get_call_is_end(self, call_id):
+        key = CTI_MANAGE_CENTER_CALL_END_KEY % call_id
+        return self.redis_handler.get(key)
+
+    def set_call_is_end(self, call_id):
+        key = CTI_MANAGE_CENTER_CALL_END_KEY % call_id
+        return self.redis_handler.redis.set(key, "1", ex=60 * 10, nx=True)
+
+    def get_call_is_answer(self, saas_id, flow_id):
+        key = CTI_AGENT_MANUAL_ANSWER%(saas_id, flow_id)
+        return self.redis_handler.get(key)
+
+    def set_call_is_answer(self, saas_id, flow_id):
+        key = CTI_AGENT_MANUAL_ANSWER%(saas_id, flow_id)
+        return self.redis_handler.redis.set(key, "1", ex=60, nx=True)

+ 47 - 30
src/core/callcenter/call.py

@@ -3,9 +3,12 @@
 import json
 import json
 import time
 import time
 from datetime import datetime
 from datetime import datetime
+
+from src.core.callcenter.agent import AgentMonitorService, AgentActionLogService
 from src.core.callcenter.cache import Cache
 from src.core.callcenter.cache import Cache
 from src.core.callcenter.constant import saasId, HOLD_MUSIC_PATH
 from src.core.callcenter.constant import saasId, HOLD_MUSIC_PATH
-from src.core.callcenter.enumeration import CallCause, Direction, NextType, DeviceType, CdrType, AgentServiceState,AgentScene,WorkStatus
+from src.core.callcenter.enumeration import CallCause, Direction, NextType, DeviceType, CdrType, AgentServiceState, \
+    AgentScene, WorkStatus, AgentLogState, ServiceDirect
 from src.core.callcenter.api import AgentCallRequest, CallInfo, HangupCallRequest, CheckInCallRequest, \
 from src.core.callcenter.api import AgentCallRequest, CallInfo, HangupCallRequest, CheckInCallRequest, \
     DeviceInfo, NextCommand, MakeCallContext
     DeviceInfo, NextCommand, MakeCallContext
 from src.core.callcenter.esl.constant.sip_header_constant import sipHeaderServiceId, sipHeaderCtiFlowId
 from src.core.callcenter.esl.constant.sip_header_constant import sipHeaderServiceId, sipHeaderCtiFlowId
@@ -15,13 +18,16 @@ from src.core.callcenter.data_handler import *
 
 
 class CallService:
 class CallService:
 
 
-    def __init__(self, client, logger):
+    def __init__(self, client, app):
         self.client = client
         self.client = client
-        self.logger = logger
-        self.cache = Cache(client.app)
+        self.logger = app.logger
+        self.cache = Cache(app)
         self.snowflake = Snowflake()
         self.snowflake = Snowflake()
-        self.dataHandleServer=DataHandleServer(client.app)
-        self.push_handler = PushHandler(logger)
+        self.push_handler = PushHandler(app.logger)
+        self.data_handle_server=DataHandleServer(app)
+        self.agent_monitor_service = AgentMonitorService(app)
+        self.agent_actionlog_service = AgentActionLogService(app)
+        # self.push_handler = PushHandler(logger)
 
 
     def call(self, request: AgentCallRequest):
     def call(self, request: AgentCallRequest):
         call_id = 'C' + str(self.snowflake.next_id())
         call_id = 'C' + str(self.snowflake.next_id())
@@ -34,9 +40,9 @@ class CallService:
         agent = self.cache.get_agent_info(request.saas_id, request.agent_id)
         agent = self.cache.get_agent_info(request.saas_id, request.agent_id)
         route_gateway = self.cache.get_route_gateway(request.saas_id)
         route_gateway = self.cache.get_route_gateway(request.saas_id)
         call_info = CallInfo(cti_flow_id=request.cti_flow_id, call_id=call_id, agent_key=agent.agent_number, sip_server=agent.sip_server,
         call_info = CallInfo(cti_flow_id=request.cti_flow_id, 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=agent.agent_number, called=request.called, direction=Direction.OUTBOUND.code,
                              caller_display=request.caller_display, called_display=request.called_display,
                              caller_display=request.caller_display, called_display=request.called_display,
-                             call_type=request.call_type.code, call_time=now, follow_data=request.follow_data,
+                             call_type=request.call_type, call_time=now, follow_data=request.follow_data,
                              uuid1=request.uuid1, uuid2=request.uuid2, saas_id=saasId,
                              uuid1=request.uuid1, uuid2=request.uuid2, saas_id=saasId,
                              core_uuid=None, conference=None, group_id=None, hidden_customer=0, number_location=None, agent_name=None, login_type=None, ivr_id=None, task_id=None, media_host=None, client_host=None, record=None, record2=None, record_time=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, first_queue_time=None, queue_start_time=None, queue_end_time=None, overflow_count=0, cdr_notify_url=None, queue_level=None, transfer_agent=None, device_list=[], device_info_map = {}, process_data = {}, next_commands=[], call_details=[])
                              core_uuid=None, conference=None, group_id=None, hidden_customer=0, number_location=None, agent_name=None, login_type=None, ivr_id=None, task_id=None, media_host=None, client_host=None, record=None, record2=None, record_time=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, first_queue_time=None, queue_start_time=None, queue_end_time=None, overflow_count=0, cdr_notify_url=None, queue_level=None, transfer_agent=None, device_list=[], device_info_map = {}, process_data = {}, next_commands=[], call_details=[])
         device_info = DeviceInfo(cti_flow_id=request.cti_flow_id, device_id=device_id, call_time=now, call_id=call_id, device_type=DeviceType.AGENT.code,
         device_info = DeviceInfo(cti_flow_id=request.cti_flow_id, device_id=device_id, call_time=now, call_id=call_id, device_type=DeviceType.AGENT.code,
@@ -55,20 +61,26 @@ class CallService:
                                   sip_header_map={sipHeaderCtiFlowId: request.cti_flow_id})
                                   sip_header_map={sipHeaderCtiFlowId: request.cti_flow_id})
 
 
         self.client.make_call_new(context)
         self.client.make_call_new(context)
-
-        # 创建一条通话记录
-        self.dataHandleServer.create_record({
-            "session_id": call_id,
-            "time_begin": datetime.utcnow(),
-            "category": 1,
-            "agent_num":request.agent_id,
-            "phone": request.called
-        })
-        # 变更坐席状态为拨号中
-        self.dataHandleServer.update_agent_monitor_service_state(request.agent_id, AgentServiceState.DIALING.code)
-        self.push_handler.push_on_agent_work_report(request.saas_id, request.cti_flow_id, request.agent_id, call_id,AgentScene.ROBOT, WorkStatus.AGENT_HANG_IDLE)
+        self.do_after_manual_call(call_info, agent.agent_number)
+        # # 创建一条通话记录
+        # self.dataHandleServer.create_record({
+        #     "session_id": call_id,
+        #     "time_begin": datetime.utcnow(),
+        #     "category": 1,
+        #     "agent_num":request.agent_id,
+        #     "phone": request.called
+        # })
+        # # 变更坐席状态为拨号中
+        # self.dataHandleServer.update_agent_monitor_service_state(request.agent_id, AgentServiceState.DIALING.code)
+        # self.push_handler.push_on_agent_work_report(request.saas_id, request.cti_flow_id, request.agent_id, call_id,AgentScene.ROBOT, WorkStatus.AGENT_DIALING)
         return call_id
         return call_id
 
 
+    def do_after_manual_call(self, call_info: CallInfo, agent_id):
+        agent_monitor = self.data_handle_server.get_agent_monitor(call_info.saas_id, agent_number=agent_id)
+        self.agent_monitor_service.update_dialing(agent_monitor)
+        self.push_handler.push_on_call_ring(call_info.saas_id, flow_id=call_info.cti_flow_id, user_id=agent_id, scene=AgentScene.MANUAL, call_id=call_info.call_id, service_direct=ServiceDirect.MANUAL_CALL.service_direct)
+        self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.DIALING, AgentLogState.DIALING)
+
     def hold(self, call_info: CallInfo, device_id):
     def hold(self, call_info: CallInfo, device_id):
         devices = call_info.device_list
         devices = call_info.device_list
         try:
         try:
@@ -113,16 +125,21 @@ class CallService:
                                   call_type=call_info.call_type, service_id=service_id, sip_header_map=sip_header_map)
                                   call_type=call_info.call_type, service_id=service_id, sip_header_map=sip_header_map)
         self.client.make_call_new(context)
         self.client.make_call_new(context)
 
 
-    def hangup(self, request: HangupCallRequest):
-        call_info = self.cache.get_call_info(request.call_id)
-        if not call_info:
-            self.logger.info('hangup call not exist callId: %s', request.call_id)
-            return
-        devices = call_info.device_list
-        if not devices:
-            self.logger.info('hangup deviceList is null callId: %s', request.call_id)
-            return
-        self.hangup_all(call_info, CallCause.AGENT_HANGUP_CALL)
+    def hangup_by_scene(self, request: HangupCallRequest):
+        scene = AgentScene.get_by_code(request.scene)
+        if scene and AgentScene.MANUAL == scene:
+            self.do_manual_hang(request)
+        elif scene and not AgentScene.MANUAL == scene:
+            self.do_robot_hang(request)
+
+    def do_manual_hang(self, request: HangupCallRequest):
+        self.hangup_call(request.call_id)
+
+        agent_monitor = self.data_handle_server.get_agent_monitor(saas_id=request.saas_id, agent_number=request.agent_id)
+        self.agent_actionlog_service.insert_service_state(agent_monitor, AgentServiceState.HANGING, AgentLogState.MANUAL_HANG_UP)
+
+    def do_robot_hang(self, request: HangupCallRequest):
+        self.hangup_call(request.call_id)
 
 
     def hangup_all(self, call_info: CallInfo, case_enum=CallCause.DEFAULT):
     def hangup_all(self, call_info: CallInfo, case_enum=CallCause.DEFAULT):
         devices = call_info.device_list
         devices = call_info.device_list

+ 42 - 0
src/core/callcenter/callback.py

@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+# encoding:utf-8
+import threading
+
+import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
+from src.core.callcenter.agent import AgentEventService
+from src.core.callcenter.cache import Cache
+from src.core.callcenter.enumeration import CallType
+from src.core.callcenter.esl.constant.event_names import CUSTOM, DETECTED_TONE
+
+
+class Callback(object):
+
+    def __init__(self, app):
+        self.app = app
+        self.logger = app.logger
+        self.cache = Cache(app)
+        self.agent_event_service = AgentEventService(app)
+
+    def callback_event(self, event):
+        event_name = EslEventUtil.getEventName(event)
+        # CUSTOM == event_name or
+        if not (event_name.startswith('CHANNEL_') or event_name.startswith('PLAYBACK_') or event_name == DETECTED_TONE):
+            return
+        call_id = EslEventUtil.getCallId(event)
+        device_id = EslEventUtil.getDeviceId(event)
+        if not call_id and device_id:
+            call_id = self.cache.get_call_id_by_device_id(device_id)
+        call_info = self.cache.get_call_info(call_id)
+        if not call_info:
+            # self.logger.info("liuwei::debugger::callback:return::event_name=%s, call_id=%s, device_id=%s", event_name, call_id, device_id)
+            return
+
+        call_type = CallType.get_by_code(call_info.call_type) if call_info else None
+        device_info = call_info.device_info_map.get(device_id) if call_info and call_info.device_info_map else None
+        # self.logger.info("liuwei::debugger::callback::event_name=%s, call_type=%s, call_id=%s, device_id=%s, call_info=%s", event_name, call_type, call_id, device_id, call_info)
+        if CallType.BOT_CALL == call_type:
+            threading.Thread(target=self.agent_event_service.bot_event_channel, args=(event, call_info, device_info)).start()
+            # self.agent_event_service.bot_event_channel(event, call_info, device_info)
+        else:
+            threading.Thread(target=self.agent_event_service.agent_event_channel, args=(event, call_info, device_info)).start()
+            # self.agent_event_service.agent_event_channel(event, call_info, device_info)

+ 2 - 0
src/core/callcenter/constant.py

@@ -86,6 +86,8 @@ CTI_ENGINE_DELAY_ACTION = "DELAY:ACTION:%s"
 CTI_ENGINE_DELAY_ACTION_LOCK = "DELAY:ACTION:LOCK:%s"
 CTI_ENGINE_DELAY_ACTION_LOCK = "DELAY:ACTION:LOCK:%s"
 NEED_PLAY_HOLD_MUSIC = "CTI:ENGINE:NEED:HOLD:%s"
 NEED_PLAY_HOLD_MUSIC = "CTI:ENGINE:NEED:HOLD:%s"
 AFTER_PLAY_HOLD_MUSIC = "CTI:ENGINE:AFTER:HOLD:%s"
 AFTER_PLAY_HOLD_MUSIC = "CTI:ENGINE:AFTER:HOLD:%s"
+CTI_MANAGE_CENTER_CALL_END_KEY = "CTI:MANAGE:CENTER:CALL:END:KEY:%s"
+CTI_AGENT_MANUAL_ANSWER = "AGENT:MANUAL:ANSWER:%s:%s"
 
 
 def get_json_dict(json_text=None):
 def get_json_dict(json_text=None):
     if isinstance(json_text, str):
     if isinstance(json_text, str):

+ 27 - 0
src/core/callcenter/dao.py

@@ -491,4 +491,31 @@ class CallRecord(db.Model):
             'create_time': self.create_time.isoformat() if self.create_time else None,
             'create_time': self.create_time.isoformat() if self.create_time else None,
             'update_by': self.update_by,
             'update_by': self.update_by,
             'update_time': self.update_time.isoformat() if self.update_time else None,
             'update_time': self.update_time.isoformat() if self.update_time else None,
+        }
+
+class BotRecords(db.Model):
+    __tablename__ = 'botrecords'
+    __table_args__ = {'comment': '记录机器人会话信息'}
+
+    id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='主键')
+    session = db.Column(db.String(50), nullable=False, unique=True, comment='请求ID')
+    req_time = db.Column(db.DateTime, nullable=True, comment='来电时间')
+    uid = db.Column(db.String(20), nullable=True, comment='来电手机号')
+    bid = db.Column(db.String(20), nullable=True, comment='话术ID')
+    intent = db.Column(db.String(20), nullable=True, comment='意图')
+    contents = db.Column(db.Text, nullable=True, comment='内容')
+    dialog = db.Column(db.Text, nullable=True, comment='对话')
+    def __repr__(self):
+        return json.dumps(self.to_dict())
+
+    def to_dict(self):
+        return {
+            'id': self.id,
+            'session': self.session,
+            'req_time': self.req_time.isoformat() if self.req_time else None,
+            'uid': self.uid,
+            'bid': self.bid,
+            'intent': self.intent,
+            'contents': self.contents,
+            'dialog': self.dialog,
         }
         }

+ 46 - 10
src/core/callcenter/data_handler.py

@@ -1,11 +1,7 @@
+from src.core import with_app_context
+from src.core.callcenter.constant import START_AGENT_NUM
 from src.core.callcenter.dao import *
 from src.core.callcenter.dao import *
-from functools import wraps
-def with_app_context(func):
-    @wraps(func)
-    def wrapper(self, *args, **kwargs):
-        with self.app.app_context():
-            return func(self, *args, **kwargs)
-    return wrapper
+from sqlalchemy import or_
 
 
 class DataHandleServer:
 class DataHandleServer:
     """通话记录服务"""
     """通话记录服务"""
@@ -46,7 +42,7 @@ class DataHandleServer:
 
 
     @with_app_context
     @with_app_context
     def update_record(self, session_id, call_info):
     def update_record(self, session_id, call_info):
-        call_record = CallRecord.query.filter_by(session_id=session_id).first()
+        call_record = CallRecord.query.filter(CallRecord.session_id == session_id).first()
         # 动态更新字段
         # 动态更新字段
         for key, value in call_info.items():
         for key, value in call_info.items():
             if hasattr(call_record, key):
             if hasattr(call_record, key):
@@ -55,15 +51,55 @@ class DataHandleServer:
 
 
     @with_app_context
     @with_app_context
     def get_user_name(self,agent_num):
     def get_user_name(self,agent_num):
-        agent = Agent.query.filter(agent_num == agent_num).first()
+        agent = Agent.query.filter(Agent.agent_num == agent_num).first()
         return agent
         return agent
 
 
     @with_app_context
     @with_app_context
     def get_agent_phone(self, saas_id, agent_num):
     def get_agent_phone(self, saas_id, agent_num):
         return Phone.query.filter(Phone.saas_id == saas_id, Phone.phone_num == agent_num).first()
         return Phone.query.filter(Phone.saas_id == saas_id, Phone.phone_num == agent_num).first()
 
 
+    @with_app_context
+    def get_agent(self,saas_id, agent_id=None, agent_number=None, out_id=None):
+        agent = Agent.query.filter(
+            Agent.saas_id == saas_id,
+            or_(Agent.out_id == agent_id, Agent.out_id == out_id, Agent.agent_num == agent_number)
+        ).first()
+        return agent
+
+    @with_app_context
+    def get_newest_agent_number(self,saas_id):
+        agent = Agent.query.filter(Agent.saas_id == saas_id).order_by(Agent.agent_num.desc()).first()
+        agentNum = START_AGENT_NUM
+        if agent and agent.agent_num:
+            agentNum = str(int(agent.agent_num) + 1)
+        return agentNum
+
+    @with_app_context
+    def get_agent_monitor(self,saas_id, agent_number):
+        monitor = AgentMonitor.query.filter(AgentMonitor.saas_id == saas_id,
+                                            AgentMonitor.agent_num == agent_number).first()
+        return monitor
+
+    @with_app_context
+    def get_phone(self,saas_id, phone_num):
+        phone = Phone.query.filter(Phone.saas_id == saas_id, Phone.phone_num == phone_num).first()
+        return phone
+
+    @with_app_context
+    def get_human_service_service(self,saas_id, agent_id):
+        human_service_map = HumanServiceMap.query.filter(HumanServiceMap.saas_id == saas_id,
+                                                         HumanServiceMap.agent_id == agent_id).first()
+        return human_service_map
+
     @with_app_context
     @with_app_context
     def update_agent_monitor_service_state(self, agent_num,service_state):
     def update_agent_monitor_service_state(self, agent_num,service_state):
-        agent_monitor = AgentMonitor.query.filter(agent_num == agent_num).first()
+        agent_monitor = AgentMonitor.query.filter(AgentMonitor.agent_num == agent_num).first()
         agent_monitor.service_state = service_state
         agent_monitor.service_state = service_state
+        db.session.commit()
+
+    @with_app_context
+    def update_call_record_bussiness_type(self, session):
+        BotRecord = BotRecords.query.filter(BotRecords.session == session).first()
+        print("BotRecord",BotRecord.intent,session,flush=True)
+        self.update_record(session, {"bussiness_type": BotRecord.intent})
         db.session.commit()
         db.session.commit()

+ 8 - 4
src/core/callcenter/esl/client.py

@@ -19,8 +19,8 @@ from apscheduler.schedulers.background import BackgroundScheduler
 from src.core.callcenter import BizException
 from src.core.callcenter import BizException
 from src.core.callcenter.cache import Cache
 from src.core.callcenter.cache import Cache
 from src.core.callcenter.api import MakeCallContext, DelayAction, CallInfo, DeviceInfo, NextCommand
 from src.core.callcenter.api import MakeCallContext, DelayAction, CallInfo, DeviceInfo, NextCommand
-from src.core.callcenter.constant import SK, EMPTY, CTI_ENGINE_DELAY_ACTION_LOCK, HOLD_MUSIC_PATH, saasId, \
-    WaitingHangupMusicPath
+from src.core.callcenter.callback import Callback
+from src.core.callcenter.constant import SK, EMPTY, CTI_ENGINE_DELAY_ACTION_LOCK, HOLD_MUSIC_PATH, WaitingHangupMusicPath, saasId
 from src.core.callcenter.esl.constant.esl_constant import BRIDGE_VARIABLES, BRIDGE, HANGUP, NORMAL_CLEARING, SIP_HEADER, \
 from src.core.callcenter.esl.constant.esl_constant import BRIDGE_VARIABLES, BRIDGE, HANGUP, NORMAL_CLEARING, SIP_HEADER, \
     SPACE, SPLIT, SOFIA, \
     SPACE, SPLIT, SOFIA, \
     ORIGINATE, PARK, SET, EAVESDROP, SMF_ALEG, EXECUTE, PLAYBACK, PAUSE, TRANSFER, UUID_TRANSFER, UUID_BROADCAST, \
     ORIGINATE, PARK, SET, EAVESDROP, SMF_ALEG, EXECUTE, PLAYBACK, PAUSE, TRANSFER, UUID_TRANSFER, UUID_BROADCAST, \
@@ -46,6 +46,8 @@ class InboundClient:
         self.logger = app.logger
         self.logger = app.logger
         self.bot_agent = agent
         self.bot_agent = agent
         self.cache = Cache(app)
         self.cache = Cache(app)
+        self.callback = Callback(app)
+        self.dataHandleServer = DataHandleServer(app)
         self.handler_table = self.scan_esl_event_handlers()
         self.handler_table = self.scan_esl_event_handlers()
         self.default_event_handler = DefaultEslEventHandler(self, self.bot_agent)
         self.default_event_handler = DefaultEslEventHandler(self, self.bot_agent)
         self.host, self.port, self.password = SERVE_HOST, '8021', '4918257983818884358'
         self.host, self.port, self.password = SERVE_HOST, '8021', '4918257983818884358'
@@ -121,6 +123,7 @@ class InboundClient:
         address = self.host + ':' + self.port
         address = self.host + ':' + self.port
         # self.logger.info("process_esl_event.event_name=%s,coreUUID=%s", event_name, coreUUID)
         # self.logger.info("process_esl_event.event_name=%s,coreUUID=%s", event_name, coreUUID)
         try:
         try:
+            self.callback.callback_event(e)
             if event_name in self.handler_table:
             if event_name in self.handler_table:
                 items = self.handler_table.get(event_name)
                 items = self.handler_table.get(event_name)
                 for x in items:
                 for x in items:
@@ -176,8 +179,7 @@ class InboundClient:
             #         self.cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_DECR, delay_action, timeouts=20)
             #         self.cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_DECR, delay_action, timeouts=20)
             self.cache.add_call_info(call_info)
             self.cache.add_call_info(call_info)
             self.hangup_call(call_id, device_id, CallCause.CALL_TIMEOUT)
             self.hangup_call(call_id, device_id, CallCause.CALL_TIMEOUT)
-            print("人工外呼,呼叫超时,用户未接通会走这", flush=True)
-
+            self.dataHandleServer.update_record(call_id, {"status": 0})
     def exec_when_play_timeout(self, call_id):
     def exec_when_play_timeout(self, call_id):
         call_info = self.cache.get_call_info(call_id)
         call_info = self.cache.get_call_info(call_id)
         if not call_info or not call_info.next_commands:
         if not call_info or not call_info.next_commands:
@@ -209,6 +211,7 @@ class InboundClient:
                              device_id, WaitingHangupMusicPath)
                              device_id, WaitingHangupMusicPath)
 
 
     def make_call_new(self, context: MakeCallContext):
     def make_call_new(self, context: MakeCallContext):
+        # self.logger.info("拨打测试context:%s", context.__dict__)
         called = context.get_called()
         called = context.get_called()
         params = {'gateway': context.route_gateway_name, 'called': called, 'realm': context.get_realm()}
         params = {'gateway': context.route_gateway_name, 'called': called, 'realm': context.get_realm()}
 
 
@@ -222,6 +225,7 @@ class InboundClient:
         else:
         else:
             profile = self.expression(profile2, params)
             profile = self.expression(profile2, params)
             builder.append(f"{profile}{PARK}")
             builder.append(f"{profile}{PARK}")
+            # self.logger.info("拨打测试builder:%s", builder)
         cmd = "".join(builder)
         cmd = "".join(builder)
         self.logger.info(cmd)
         self.logger.info(cmd)
         self.con.bgapi(ORIGINATE, cmd)
         self.con.bgapi(ORIGINATE, cmd)

+ 16 - 6
src/core/callcenter/esl/handler/channel_answer_handler.py

@@ -3,9 +3,9 @@
 import json
 import json
 import time
 import time
 from datetime import datetime
 from datetime import datetime
-from src.core.callcenter.constant import saasId, get_record_prefix, get_record_file_name
-from src.core.callcenter.enumeration import NextType, AnswerFlag, Direction, DeviceType, AgentScene, CdrType, CallType, \
-    CallStage
+from src.core.callcenter.constant import saasId, get_record_prefix,get_record_file_name
+from src.core.callcenter.enumeration import NextType, AnswerFlag, Direction, DeviceType, AgentScene, CdrType, \
+    WorkStatus, AgentServiceState, CallStage, CallType
 from src.core.callcenter.esl.annotation import EslEventName
 from src.core.callcenter.esl.annotation import EslEventName
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
 from src.core.callcenter.esl.constant.event_names import CHANNEL_ANSWER
 from src.core.callcenter.esl.constant.event_names import CHANNEL_ANSWER
@@ -28,7 +28,7 @@ class ChannelAnswerHandler(EslEventHandler):
     def handle(self, address, event, coreUUID):
     def handle(self, address, event, coreUUID):
         call_id = EslEventUtil.getCallId(event)
         call_id = EslEventUtil.getCallId(event)
         call_info = self.cache.get_call_info(call_id)
         call_info = self.cache.get_call_info(call_id)
-        # self.logger.info("lwanswer call_id:%s, call_info:%s, event:%s"% (call_id, call_info, json.loads(event.serialize('json'))))
+        self.logger.info("liuwei::debugger::answer call_id:%s, call_info:%s", call_id, call_info)
         if not call_info:
         if not call_info:
             return
             return
 
 
@@ -36,18 +36,19 @@ class ChannelAnswerHandler(EslEventHandler):
         device_info = call_info.device_info_map.get(device_id)
         device_info = call_info.device_info_map.get(device_id)
         next_command = call_info.next_commands[0] if len(call_info.next_commands) > 0 else None
         next_command = call_info.next_commands[0] if len(call_info.next_commands) > 0 else None
         device_type = DeviceType.get_by_code(device_info.device_type)
         device_type = DeviceType.get_by_code(device_info.device_type)
-        self.logger.info("lwChannelAnswerHandler call_id:%s, device_id:%s, device_type:%s, next_command:%s"%(call_id, device_id, device_type, next_command))
+        self.logger.info("liuwei::debugger::ChannelAnswerHandler call_id:%s, device_id:%s, device_type:%s, next_command:%s"%(call_id, device_id, device_type, next_command))
         if not next_command:
         if not next_command:
             return
             return
 
 
         if CallType.AGENT_CALL.code == call_info.call_type and device_info.device_type == DeviceType.CUSTOMER.code:
         if CallType.AGENT_CALL.code == call_info.call_type and device_info.device_type == DeviceType.CUSTOMER.code:
             self.record(event, device_id)
             self.record(event, device_id)
-            self.push_handler.push_on_ring_start(saas_id=call_info.saas_id, flow_id=call_info.cti_flow_id, user_id=call_info.agent_key, scene=AgentScene.MANUAL, call_id=call_info.call_id)
 
 
         device_info.answer_time = EslEventUtil.getEventDateTimestamp(event)
         device_info.answer_time = EslEventUtil.getEventDateTimestamp(event)
         device_info.ring_end_time = EslEventUtil.getEventDateTimestamp(event)
         device_info.ring_end_time = EslEventUtil.getEventDateTimestamp(event)
         call_info.answer_count = call_info.answer_count + 1
         call_info.answer_count = call_info.answer_count + 1
         call_info.next_commands.remove(next_command)
         call_info.next_commands.remove(next_command)
+        self.logger.info("liuwei::debugger::ChannelAnswerHandler call_info.answer_time::%s,time:%s", call_info.answer_time, EslEventUtil.getEventDateTimestamp(event))
+
 
 
         if NextType.NEXT_CALL_OTHER.code == next_command.next_type:
         if NextType.NEXT_CALL_OTHER.code == next_command.next_type:
             self.call_other(call_info, device_info, event)
             self.call_other(call_info, device_info, event)
@@ -59,8 +60,17 @@ class ChannelAnswerHandler(EslEventHandler):
             self.listen(call_info, device_info, next_command, event)
             self.listen(call_info, device_info, next_command, event)
         else:
         else:
             self.logger.warn("can not match command :%s, callId :%s", next_command.next_type, call_id)
             self.logger.warn("can not match command :%s, callId :%s", next_command.next_type, call_id)
+
+        # if device_info.device_type == DeviceType.AGENT.code:  # 如果是坐席接听 变更坐席状态
+        #     call_info.answer_time = EslEventUtil.getEventDateTimestamp(event)
+        #     self.dataHandleServer.update_record(call_id, {"status": 1})
+        #     self.push_handler.push_on_agent_work_report(call_info.saas_id, call_info.cti_flow_id, call_info.agent_key, call_info.call_id, AgentScene.ROBOT,WorkStatus.AGENT_ANSWER_INCOMING)
+        #     self.dataHandleServer.update_agent_monitor_service_state(call_info.agent_key,AgentServiceState.CALLING.code)
+        #     self.logger.info("坐席接听 event:%s" % (json.loads(event.serialize('json'))))
+
         self.cache.add_call_info(call_info)
         self.cache.add_call_info(call_info)
 
 
+
     def call_other(self, call: CallInfo, device: DeviceInfo, event):
     def call_other(self, call: CallInfo, device: DeviceInfo, event):
         call_id = call.call_id
         call_id = call.call_id
         device_id = device.device_id
         device_id = device.device_id

+ 17 - 16
src/core/callcenter/esl/handler/channel_bridge_handler.py

@@ -13,21 +13,22 @@ class ChannelBridgeHandler(EslEventHandler):
 
 
     def __init__(self, inbound_client, bot_agent):
     def __init__(self, inbound_client, bot_agent):
         super().__init__(inbound_client, bot_agent)
         super().__init__(inbound_client, bot_agent)
-        self.dataHandleServer = DataHandleServer(inbound_client.app)
-        self.push_handler = PushHandler(inbound_client.logger)
+        # self.dataHandleServer = DataHandleServer(inbound_client.app)
+        # self.push_handler = PushHandler(inbound_client.logger)
 
 
     def handle(self, address, event, coreUUID):
     def handle(self, address, event, coreUUID):
-        call_id = EslEventUtil.getCallId(event)
-        device_id = EslEventUtil.getDeviceId(event)
-        call = self.cache.get_call_info(call_id)
-        device = call.device_info_map.get(device_id)
-        if not call.answer_time:
-            call.answer_time = EslEventUtil.getEventDateTimestamp(event)
-            self.cache.add_call_info(call)
-
-        self.logger.info("bridge call_info.answer_time:%s,device_info.answer_time%s,device.device_type%s" % (call.answer_time, device.answer_time,device.device_type))
-        if device.device_type == DeviceType.AGENT.code: # 如果是坐席接听 变更坐席状态
-            self.dataHandleServer.update_agent_monitor_service_state(call.agent_key, AgentServiceState.CALLING.code)
-            self.push_handler.push_on_agent_work_report(call.saas_id, call.cti_flow_id, call.agent_key, call.call_id, AgentScene.ROBOT, WorkStatus.AGENT_ANSWER_INCOMING)
-
-
+        pass
+        # call_id = EslEventUtil.getCallId(event)
+        # device_id = EslEventUtil.getDeviceId(event)
+        # call_info = self.cache.get_call_info(call_id)
+        # device = call_info.device_info_map.get(device_id)
+        # # 每通电话的第一次写入应答时间
+        # if not call_info.answer_time:
+        #     call_info.answer_time = EslEventUtil.getEventDateTimestamp(event)
+        #     self.cache.add_call_info(call_info)
+        #     self.dataHandleServer.update_record(call_id, {"status": 1})
+        #     self.logger.info("bridge call_info.answer_time:%s,device_info.answer_time%s,device.device_type%s" % (call_info.answer_time, device.answer_time,device.device_type))
+        # if device.device_type == DeviceType.AGENT.code: # 如果是坐席接听 变更坐席状态
+        #     # self.dataHandleServer.update_record(call_id, {"status": 1})
+        #     self.push_handler.push_on_agent_work_report(call_info.saas_id, call_info.cti_flow_id, call_info.agent_key, call_info.call_id, AgentScene.ROBOT,WorkStatus.AGENT_ANSWER_INCOMING)
+        #     self.dataHandleServer.update_agent_monitor_service_state(call_info.agent_key,AgentServiceState.CALLING.code)

+ 16 - 14
src/core/callcenter/esl/handler/channel_hangup_handler.py

@@ -23,7 +23,7 @@ class ChannelHangupHandler(EslEventHandler):
     def __init__(self, inbound_client, bot_agent):
     def __init__(self, inbound_client, bot_agent):
         super().__init__(inbound_client, bot_agent)
         super().__init__(inbound_client, bot_agent)
         self.acd_service = AcdService(inbound_client,inbound_client.app)
         self.acd_service = AcdService(inbound_client,inbound_client.app)
-        self.call_service = CallService(inbound_client,inbound_client.logger)
+        self.call_service = CallService(inbound_client,inbound_client.app)
         self.push_handler = PushHandler(inbound_client.logger)
         self.push_handler = PushHandler(inbound_client.logger)
         self.dataHandleServer=DataHandleServer(inbound_client.app)
         self.dataHandleServer=DataHandleServer(inbound_client.app)
 
 
@@ -107,24 +107,26 @@ class ChannelHangupHandler(EslEventHandler):
                 # self.inbound_client.hangup_call(call_id, device_id, CallCause.HANGUP_EVENT)
                 # self.inbound_client.hangup_call(call_id, device_id, CallCause.HANGUP_EVENT)
 
 
             # 全部挂机以后推送挂机状态
             # 全部挂机以后推送挂机状态
-            self.logger.info('yushanghui::call_info.device_list %s', call_info.device_list)
-            if len(call_info.device_list) == 0:
-                # 计算当前通话时长
-                if call_info.answer_time:
-                    call_info.end_time = timestamp
-                    call_info.talk_time = int(call_info.end_time) - int(call_info.answer_time)
-                    self.dataHandleServer.update_record(call_id, {"time_end": datetime.utcnow(), "times": call_info.talk_time // 1000})
+            # self.logger.info('yushanghui::call_info.device_list %s', call_info.device_list)
+            # if len(call_info.device_list) == 0:
+            #     self.push_handler.push_on_call_end(call_info.cti_flow_id, call_info.agent_key, AgentScene.ROBOT, call_info.direction, device_info.device_type)
+            #     self.push_handler.push_on_agent_work_report(call_info.saas_id, call_info.cti_flow_id,  call_info.agent_key, call_info.call_id, AgentScene.ROBOT, WorkStatus.AGENT_HANG_IDLE)
+            #     # 计算当前通话时长
+            #     if call_info.answer_time:
+            #         call_info.end_time = timestamp
+            #         call_info.talk_time = int(call_info.end_time) - int(call_info.answer_time)
+            #         self.dataHandleServer.update_record(call_id, {"time_end": datetime.utcnow(), "times": int(call_info.talk_time / 1_000_000) })
+            #
+            #     self.logger.info('全部挂断 %s', device_info.device_type)
+            #     # 更新坐席状态
+            #     if device_info.device_type == DeviceType.AGENT.code:
+            #         self.logger.info('更新坐席状态')
+            #         self.dataHandleServer.update_agent_monitor_service_state(call_info.agent_key, AgentServiceState.IDLE.code)
 
 
             # 判断挂机方向 && 更新缓存
             # 判断挂机方向 && 更新缓存
             self.hangup_dir(call_info, device_info, cause)
             self.hangup_dir(call_info, device_info, cause)
             self.cache.add_call_info(call_info)
             self.cache.add_call_info(call_info)
 
 
-
-            # 更新坐席状态
-            if device_info.device_type == DeviceType.AGENT.code:
-                  self.push_handler.push_on_call_end(call_info.cti_flow_id, call_info.agent_key, AgentScene.ROBOT, call_info.direction, device_info.device_type)
-                  self.push_handler.push_on_agent_work_report(call_info.saas_id, call_info.cti_flow_id, call_info.agent_key,call_info.call_id, AgentScene.ROBOT,WorkStatus.AGENT_HANG_IDLE)
-                  self.dataHandleServer.update_agent_monitor_service_state(device_id, AgentServiceState.IDLE.code)
         except:
         except:
             traceback.print_exc()
             traceback.print_exc()
 
 

+ 10 - 9
src/core/callcenter/esl/handler/channel_originate_handler.py

@@ -1,7 +1,7 @@
 #!/usr/bin/env python3
 #!/usr/bin/env python3
 # encoding:utf-8
 # encoding:utf-8
 from src.core.callcenter.esl.annotation import EslEventName
 from src.core.callcenter.esl.annotation import EslEventName
-from src.core.callcenter.enumeration import  DeviceType, AgentServiceState,AgentScene,WorkStatus
+from src.core.callcenter.enumeration import  DeviceType,AgentScene,WorkStatus,Direction
 from src.core.callcenter.esl.constant.event_names import CHANNEL_ORIGINATE
 from src.core.callcenter.esl.constant.event_names import CHANNEL_ORIGINATE
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
@@ -15,11 +15,12 @@ class ChannelOriginateHandler(EslEventHandler):
         self.push_handler = PushHandler(inbound_client.logger)
         self.push_handler = PushHandler(inbound_client.logger)
 
 
     def handle(self, address, event, coreUUID):
     def handle(self, address, event, coreUUID):
-        call_id = EslEventUtil.getCallId(event)
-        device_id = EslEventUtil.getDeviceId(event)
-        call = self.cache.get_call_info(call_id)
-        device = call.device_info_map.get(device_id)
-        print('ceshisdsdsdsdsdsdsd',device.device_type,DeviceType.AGENT.code,flush=True)
-        self.logger.info('ChannelOriginateHandler::event %s, device.device_type: %s, DeviceType.AGENT.code:%s ', event,device.device_type, DeviceType.AGENT.code)
-        if device.device_type == DeviceType.AGENT.code: # 如果是坐席接听 变更坐席状态
-            self.push_handler.push_on_agent_work_report(call.saas_id, call.cti_flow_id,call.agent_key,call.call_id,AgentScene.ROBOT, WorkStatus.AGENT_RINGING)
+        pass
+        # call_id = EslEventUtil.getCallId(event)
+        # device_id = EslEventUtil.getDeviceId(event)
+        # call = self.cache.get_call_info(call_id)
+        # device = call.device_info_map.get(device_id)
+        # self.logger.info('ChannelOriginateHandler::event %s, device.device_type: %s,call.direction:%s ', event,device.device_type, call.direction)
+        # if device.device_type == DeviceType.AGENT.code: # 如果是呼入有响铃
+        #     self.push_handler.push_on_call_ring(call.cti_flow_id,call.agent_key,AgentScene.ROBOT,call.call_id,call.caller, call.called,"00000000000000000")
+        #     self.push_handler.push_on_agent_work_report(call.saas_id, call.cti_flow_id,call.agent_key,call.call_id,AgentScene.ROBOT, WorkStatus.AGENT_RINGING,phone=call.caller)

+ 11 - 1
src/core/callcenter/esl/handler/channel_progress_media_handler.py

@@ -2,15 +2,25 @@
 # encoding:utf-8
 # encoding:utf-8
 
 
 from src.core.callcenter.esl.annotation import EslEventName
 from src.core.callcenter.esl.annotation import EslEventName
+from src.core.callcenter.enumeration import  DeviceType,AgentScene,WorkStatus, Direction
 from src.core.callcenter.esl.constant.event_names import CHANNEL_PROGRESS_MEDIA
 from src.core.callcenter.esl.constant.event_names import CHANNEL_PROGRESS_MEDIA
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
-
+import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
+from src.core.callcenter.push import PushHandler
 
 
 @EslEventName(CHANNEL_PROGRESS_MEDIA)
 @EslEventName(CHANNEL_PROGRESS_MEDIA)
 class ChannelProgressMediaHandler(EslEventHandler):
 class ChannelProgressMediaHandler(EslEventHandler):
 
 
     def __init__(self, inbound_client, bot_agent):
     def __init__(self, inbound_client, bot_agent):
         super().__init__(inbound_client, bot_agent)
         super().__init__(inbound_client, bot_agent)
+        self.push_handler = PushHandler(inbound_client.logger)
 
 
     def handle(self, address, event, coreUUID):
     def handle(self, address, event, coreUUID):
         pass
         pass
+        # call_id = EslEventUtil.getCallId(event)
+        # device_id = EslEventUtil.getDeviceId(event)
+        # call_info = self.cache.get_call_info(call_id)
+        # device = call_info.device_info_map.get(device_id)
+        # self.logger.info('ChannelProgressMediaHandler:: device.device_type: %s,  call_info.direction: %s ',device.device_type, call_info.direction)
+        # if call_info.direction == Direction.OUTBOUND.code and device.device_type == DeviceType.AGENT.code:
+        #     self.push_handler.push_on_agent_work_report(call_info.saas_id, call_info.cti_flow_id, call_info.agent_key, call_info.call_id, AgentScene.MANUAL, WorkStatus.AGENT_CALLING_RINGING)

+ 10 - 1
src/core/callcenter/esl/handler/detected_tone_handler.py

@@ -3,15 +3,24 @@
 # encoding:utf-8
 # encoding:utf-8
 
 
 from src.core.callcenter.esl.annotation import EslEventName
 from src.core.callcenter.esl.annotation import EslEventName
+from src.core.callcenter.enumeration import  DeviceType,AgentScene
 from src.core.callcenter.esl.constant.event_names import DETECTED_TONE
 from src.core.callcenter.esl.constant.event_names import DETECTED_TONE
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
-
+import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
+from src.core.callcenter.push import PushHandler
 
 
 @EslEventName(DETECTED_TONE)
 @EslEventName(DETECTED_TONE)
 class DetectedToneHandler(EslEventHandler):
 class DetectedToneHandler(EslEventHandler):
 
 
     def __init__(self, inbound_client, bot_agent):
     def __init__(self, inbound_client, bot_agent):
         super().__init__(inbound_client, bot_agent)
         super().__init__(inbound_client, bot_agent)
+        self.push_handler = PushHandler(inbound_client.logger)
 
 
     def handle(self, address, event, coreUUID):
     def handle(self, address, event, coreUUID):
         pass
         pass
+        # call_id = EslEventUtil.getCallId(event)
+        # device_id = EslEventUtil.getDeviceId(event)
+        # call = self.cache.get_call_info(call_id)
+        # device = call.device_info_map.get(device_id)
+        # if call.answer_time and device.device_type == DeviceType.AGENT.code:
+        #     self.push_handler.push_on_detected_tone(call.cti_flow_id, call.agent_key, AgentScene.MANUAL,call.call_id)

+ 26 - 0
src/core/callcenter/esl/handler/playback_start_handler.py

@@ -0,0 +1,26 @@
+#!/usr/bin/env python3
+# encoding:utf-8
+from src.core.callcenter.esl.annotation import EslEventName
+from src.core.callcenter.enumeration import  DeviceType,AgentScene
+from src.core.callcenter.esl.constant.event_names import PLAYBACK_START
+from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
+import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
+from src.core.callcenter.push import PushHandler
+from src.core.callcenter.data_handler import *
+
+@EslEventName(PLAYBACK_START)
+class PlaybackStartHandler(EslEventHandler):
+
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
+        self.dataHandleServer = DataHandleServer(inbound_client.app)
+        self.push_handler = PushHandler(inbound_client.logger)
+
+    def handle(self, address, event, coreUUID):
+        pass
+        # call_id = EslEventUtil.getCallId(event)
+        # device_id = EslEventUtil.getDeviceId(event)
+        # call = self.cache.get_call_info(call_id)
+        # device = call.device_info_map.get(device_id)
+        # if device.device_type == DeviceType.AGENT.code:
+        #     self.push_handler.push_on_ring_start(call.cti_flow_id, call.agent_key, AgentScene.MANUAL, call.call_id)

+ 5 - 1
src/core/callcenter/esl/handler/playback_stop_handler.py

@@ -3,10 +3,12 @@
 
 
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
 from src.core.callcenter.constant import HOLD_MUSIC_PATH
 from src.core.callcenter.constant import HOLD_MUSIC_PATH
+from src.core.callcenter.data_handler import *
 from src.core.callcenter.enumeration import NextType, CallCause
 from src.core.callcenter.enumeration import NextType, CallCause
 from src.core.callcenter.esl.annotation import EslEventName
 from src.core.callcenter.esl.annotation import EslEventName
 from src.core.callcenter.esl.constant.event_names import PLAYBACK_STOP
 from src.core.callcenter.esl.constant.event_names import PLAYBACK_STOP
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
+from src.core.callcenter.push import PushHandler
 
 
 
 
 @EslEventName(PLAYBACK_STOP)
 @EslEventName(PLAYBACK_STOP)
@@ -14,6 +16,8 @@ class PlaybackStopHandler(EslEventHandler):
 
 
     def __init__(self, inbound_client, bot_agent):
     def __init__(self, inbound_client, bot_agent):
         super().__init__(inbound_client, bot_agent)
         super().__init__(inbound_client, bot_agent)
+        self.dataHandleServer = DataHandleServer(inbound_client.app)
+        self.push_handler = PushHandler(inbound_client.logger)
 
 
     def handle(self, address, event, coreUUID):
     def handle(self, address, event, coreUUID):
         call_id = EslEventUtil.getCallId(event)
         call_id = EslEventUtil.getCallId(event)
@@ -40,4 +44,4 @@ class PlaybackStopHandler(EslEventHandler):
             call_info.end_time = device_info.end_time
             call_info.end_time = device_info.end_time
             for _device_id in call_info.device_list:
             for _device_id in call_info.device_list:
                 self.inbound_client.hangup_call(call_id, _device_id, CallCause.PLAYBACK_STOP)
                 self.inbound_client.hangup_call(call_id, _device_id, CallCause.PLAYBACK_STOP)
-        self.cache.add_call_info(call_info)
+        self.cache.add_call_info(call_info)

+ 27 - 10
src/core/callcenter/push.py

@@ -8,6 +8,7 @@ from src.core.datasource import RedisHandler
 class PushHandler:
 class PushHandler:
     def __init__(self, logger):
     def __init__(self, logger):
         self.logger = logger
         self.logger = logger
+
     def push_to_socket_service(self,user_id, data, event='common_down_data'):
     def push_to_socket_service(self,user_id, data, event='common_down_data'):
         # 创建发布的消息
         # 创建发布的消息
         message = json.dumps({
         message = json.dumps({
@@ -18,17 +19,19 @@ class PushHandler:
         # 获取 RedisHandler 实例并发布消息到 Redis 频道
         # 获取 RedisHandler 实例并发布消息到 Redis 频道
         redis_handler = RedisHandler()
         redis_handler = RedisHandler()
         redis_handler.publish('socket_channel', message)
         redis_handler.publish('socket_channel', message)
-    def push_on_agent_work_report(self, saas_id, flow_id, user_id, call_id, scene: AgentScene, work_status: WorkStatus, description=None):
+
+    def push_on_agent_work_report(self, saas_id, flow_id, user_id, call_id, scene: AgentScene, work_status: WorkStatus, description=None, phone=None):
         data = {
         data = {
             'eventName': DownEvent.ON_AGENT_WORK_REPORT.code,
             'eventName': DownEvent.ON_AGENT_WORK_REPORT.code,
             'ext': {'workStatus': work_status.code,
             'ext': {'workStatus': work_status.code,
                     'description': description or work_status.description,
                     'description': description or work_status.description,
                     'callId': call_id,
                     'callId': call_id,
                     'ctiFlowId': flow_id,
                     'ctiFlowId': flow_id,
-                    'scene': scene.code
+                    'scene': scene.code,
+                    'phone':phone
                     }
                     }
         }
         }
-        self.logger.info("flowId:[%s] OnAgentWorkReport push:[%s].", flow_id, json.dumps(data))
+        self.logger.info("flowId:[%s] push_on_agent_work_report push:[%s].", flow_id, json.dumps(data))
         new_data = {'data': json.dumps(data)}
         new_data = {'data': json.dumps(data)}
         self.push_to_socket_service(user_id, json.dumps(new_data))
         self.push_to_socket_service(user_id, json.dumps(new_data))
     def push_on_agent_report(self, saas_id, out_id, scene: AgentScene, service_state: AgentServiceState):
     def push_on_agent_report(self, saas_id, out_id, scene: AgentScene, service_state: AgentServiceState):
@@ -48,7 +51,7 @@ class PushHandler:
         new_data = {'data': json.dumps(data)}
         new_data = {'data': json.dumps(data)}
         self.push_to_socket_service(user_id, json.dumps(new_data))
         self.push_to_socket_service(user_id, json.dumps(new_data))
 
 
-    def push_on_call_ring(self, saas_id, flow_id, user_id,scene:AgentScene, call_id,  calling_no, called_no, human_service_id):
+    def push_on_call_ring(self, saas_id, flow_id, user_id,scene:AgentScene, call_id, service_direct, calling_no=None, called_no=None, human_service_id=None):
         data = {
         data = {
             'eventName': DownEvent.ON_CALLRING.code,
             'eventName': DownEvent.ON_CALLRING.code,
             'ext': {
             'ext': {
@@ -57,14 +60,15 @@ class PushHandler:
                 'scene': scene.code,
                 'scene': scene.code,
                 'callingNo': calling_no,
                 'callingNo': calling_no,
                 'calledNo': called_no,
                 'calledNo': called_no,
+                'serviceDirect': service_direct,
                 'serviceTaskId': human_service_id
                 'serviceTaskId': human_service_id
             }
             }
         }
         }
-        self.logger.info("flowId:[%s] OnAgentWorkReport push:[%s].", flow_id, json.dumps(data))
+        self.logger.info("flowId:[%s] push_on_call_ring push:[%s].", flow_id, json.dumps(data))
         new_data = {'data': json.dumps(data)}
         new_data = {'data': json.dumps(data)}
         self.push_to_socket_service(user_id, json.dumps(new_data))
         self.push_to_socket_service(user_id, json.dumps(new_data))
 
 
-    def push_on_call_end(self, flow_id, user_id,  scene: AgentScene, service_direct=None, disconnect_type=0):
+    def push_on_call_end(self, saas_id, flow_id, user_id,  scene: AgentScene, service_direct=None, disconnect_type=0):
         data = {
         data = {
             'eventName': DownEvent.ON_CALL_END.code,
             'eventName': DownEvent.ON_CALL_END.code,
             'ext': {
             'ext': {
@@ -74,7 +78,7 @@ class PushHandler:
                 'serviceDirect': service_direct
                 'serviceDirect': service_direct
             }
             }
         }
         }
-        self.logger.info("flowId:[%s] OnAgentWorkReport push:[%s].", flow_id, json.dumps(data))
+        self.logger.info("flowId:[%s] push_on_call_end push:[%s].", flow_id, json.dumps(data))
         new_data = {'data': json.dumps(data)}
         new_data = {'data': json.dumps(data)}
         self.push_to_socket_service(user_id, json.dumps(new_data))
         self.push_to_socket_service(user_id, json.dumps(new_data))
 
 
@@ -104,7 +108,7 @@ class PushHandler:
         new_data = {'data': json.dumps(data)}
         new_data = {'data': json.dumps(data)}
         self.push_to_socket_service(user_id, json.dumps(new_data))
         self.push_to_socket_service(user_id, json.dumps(new_data))
 
 
-    def push_answer_call(self, saas_id,flow_id, out_id, call_id, scene: AgentScene, service_direct,work_status,user_id ):
+    def push_answer_call(self, saas_id,flow_id, user_id, call_id, scene: AgentScene, service_direct,work_status):
         data = {
         data = {
             'eventName': DownEvent.ANSWER_CALL.code,
             'eventName': DownEvent.ANSWER_CALL.code,
             'ext': {
             'ext': {
@@ -112,9 +116,22 @@ class PushHandler:
                 'scene': scene.code,
                 'scene': scene.code,
                 'callId': call_id,
                 'callId': call_id,
                 'serviceDirect':service_direct,
                 'serviceDirect':service_direct,
-                'workStatus':work_status
+                'workStatus':work_status.code
             }
             }
         }
         }
-        self.logger.info("flowId:[%s] push_on_ring_end push:[%s].", flow_id, json.dumps(data))
+        self.logger.info("flowId:[%s] push_answer_call push:[%s].", flow_id, json.dumps(data))
+        new_data = {'data': json.dumps(data)}
+        self.push_to_socket_service(user_id, json.dumps(new_data))
+
+    def push_on_detected_tone(self, saas_id, flow_id, user_id, scene: AgentScene, call_id):
+        data = {
+            'eventName': DownEvent.ON_DETECTED_TONE.code,
+            'ext': {
+                'ctiFlowId': flow_id,
+                'scene': scene.code,
+                'callId': call_id,
+            }
+        }
+        self.logger.info("flowId:[%s] push_on_detected_tone push:[%s].", flow_id, json.dumps(data))
         new_data = {'data': json.dumps(data)}
         new_data = {'data': json.dumps(data)}
         self.push_to_socket_service(user_id, json.dumps(new_data))
         self.push_to_socket_service(user_id, json.dumps(new_data))

+ 38 - 72
src/core/callcenter/views.py

@@ -16,9 +16,9 @@ from .acd import AcdService
 agent = BotAgent(app)
 agent = BotAgent(app)
 inbound_client = InboundClient(agent,app)
 inbound_client = InboundClient(agent,app)
 outbound_client = OutboundClient(agent,app)
 outbound_client = OutboundClient(agent,app)
-call_service = CallService(inbound_client, app.logger)
-agent_service = AgentService(inbound_client, app.logger)
-agent_oper_service = AgentOperService(inbound_client, app.logger)
+call_service = CallService(inbound_client, app)
+agent_service = AgentService(app)
+agent_oper_service = AgentOperService(app)
 acd_service = AcdService(inbound_client, app)
 acd_service = AcdService(inbound_client, app)
 agent.acd_service = acd_service
 agent.acd_service = acd_service
 
 
@@ -59,108 +59,74 @@ def get_cdn_url():
 @app.route('/open/agent/get-init-config', methods=['POST'])
 @app.route('/open/agent/get-init-config', methods=['POST'])
 def get_init_config():
 def get_init_config():
     """获取初始化配置"""
     """获取初始化配置"""
-    try:
-        data = request.get_json()
-        param = AgentActionRequest.from_json(data)
-        res = agent_service.get_and_check(param)
-        return success_response(res)
-
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return error_response(e)
+    data = request.get_json()
+    param = AgentActionRequest.from_json(data)
+    res = agent_service.get_and_check(param)
+    return success_response(res)
 
 
 
 
 @app.route('/open/agent/check-in', methods=['POST'])
 @app.route('/open/agent/check-in', methods=['POST'])
 def check_in():
 def check_in():
     """坐席签入"""
     """坐席签入"""
-    try:
-        data = request.get_json()
-        param = AgentActionRequest.from_json(data)
-        res = agent_oper_service.checkin(param)
-        return success_response(res)
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return error_response(e)
+    data = request.get_json()
+    param = AgentActionRequest.from_json(data)
+    res = agent_oper_service.checkin(param)
+    return success_response(res)
 
 
 
 
 @app.route('/open/agent/check-out', methods=['POST'])
 @app.route('/open/agent/check-out', methods=['POST'])
 def check_out():
 def check_out():
     """坐席签出"""
     """坐席签出"""
-    try:
-        data = request.get_json()
-        param = AgentActionRequest.from_json(data)
-        res= agent_oper_service.checkout(param)
-        return success_response(res)
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return error_response(e)
+    data = request.get_json()
+    param = AgentActionRequest.from_json(data)
+    res = agent_oper_service.checkout(param)
+    return success_response(res)
 
 
 
 
 @app.route('/open/agent/busy', methods=['POST'])
 @app.route('/open/agent/busy', methods=['POST'])
 def busy():
 def busy():
     """坐席置忙"""
     """坐席置忙"""
-    try:
-        data = request.get_json()
-        param = AgentActionRequest.from_json(data)
-        res= agent_oper_service.busy(param)
-        return success_response(res)
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return error_response(e)
+    data = request.get_json()
+    param = AgentActionRequest.from_json(data)
+    res = agent_oper_service.busy(param)
+    return success_response(res)
 
 
 
 
 @app.route('/open/agent/idle', methods=['POST'])
 @app.route('/open/agent/idle', methods=['POST'])
 def idle():
 def idle():
     """坐席置闲"""
     """坐席置闲"""
-    try:
-        data = request.get_json()
-        param = AgentActionRequest.from_json(data)
-        res = agent_oper_service.idle(param)
-        return success_response(res)
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return {"error": "An error occurred", "details": str(e)}, 500
+    data = request.get_json()
+    param = AgentActionRequest.from_json(data)
+    res = agent_oper_service.idle(param)
+    return success_response(res)
 
 
 
 
 @app.route('/open/agent/turn-on', methods=['POST'])
 @app.route('/open/agent/turn-on', methods=['POST'])
 def turn_on():
 def turn_on():
     """接通"""
     """接通"""
-    try:
-        data = request.get_json()
-        param = AgentActionRequest.from_json(data)
-        return agent_oper_service.checkin(param)
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return {"error": "An error occurred", "details": str(e)}, 500
+    data = request.get_json()
+    param = AgentActionRequest.from_json(data)
+    return agent_oper_service.checkin(param)
 
 
 
 
 @app.route('/open/agent/hang-up', methods=['POST'])
 @app.route('/open/agent/hang-up', methods=['POST'])
 def hang_up():
 def hang_up():
     """挂断"""
     """挂断"""
-    try:
-        data = request.get_json()
-        param = AgentActionRequest.from_json(data)
-        res = call_service.hangup(param)
-        return success_response(res)
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return {"error": "An error occurred", "details": str(e)}, 500
-
+    data = request.get_json()
+    param = AgentActionRequest.from_json(data)
+    res = call_service.hangup(param)
+    return success_response(res)
 
 
 @app.route('/open/agent/agent-state', methods=['POST'])
 @app.route('/open/agent/agent-state', methods=['POST'])
 def agent_state():
 def agent_state():
     """获取坐席状态"""
     """获取坐席状态"""
-    try:
-        data = request.get_json()
-        # param = HumanServiceQueryRequest.from_json(data)
-        # res = agent_service.watch_agent_state(param)
-        param = AgentActionRequest.from_json(data)
-        res = agent_oper_service.agent_state(param)
+    data = request.get_json()
+    # param = HumanServiceQueryRequest.from_json(data)
+    # res = agent_service.watch_agent_state(param)
+    param = AgentActionRequest.from_json(data)
+    res = agent_oper_service.agent_state(param)
 
 
-        return success_response(res)
-    except Exception as e:
-        print("Exception occurred: %s", str(e))
-        return {"error": "An error occurred", "details": str(e)}, 500
+    return success_response(res)
 
 
 
 
 @app.route('/open/agent/manual-call', methods=['POST'])
 @app.route('/open/agent/manual-call', methods=['POST'])
@@ -188,8 +154,8 @@ def manual_hang():
     """挂断"""
     """挂断"""
     data = request.get_json()
     data = request.get_json()
     # agent = Cache.get_agent_info(data.get('saas_id'), data.get('agent_id'))
     # agent = Cache.get_agent_info(data.get('saas_id'), data.get('agent_id'))
-    req = HangupCallRequest(saas_id=data.get('saas_id'), call_id=data.get('call_id'), agent_number=data.get('agent_id'))
-    call_service.hangup(req)
+    req = HangupCallRequest(saas_id=data.get('saas_id'), flow_id=data.get('ctiFlowId'), agent_id=data.get('agent_id'), called=data.get('called'), call_id=data.get('call_id'), scene=data.get('scene'))
+    call_service.hangup_by_scene(req)
     return success_response()
     return success_response()
 
 
 
 

+ 27 - 8
src/core/voip/asr.py

@@ -50,11 +50,12 @@ class TestSt:
     def get_cached_token(cls):
     def get_cached_token(cls):
         # 检查是否已有缓存的Token且未过期s):
         # 检查是否已有缓存的Token且未过期s):
         #         # 检查是否已有缓存的Token且未
         #         # 检查是否已有缓存的Token且未
-        if cls.token_cache["token"] and cls.token_cache["expire_time"]:
-            current_time = int(time.time())
-            if current_time < cls.token_cache["expire_time"]:
-                print("使用缓存的Token")
-                return cls.token_cache["token"]
+        current_time = int(time.time())
+        # if cls.token_cache["token"] and cls.token_cache["expire_time"]:
+        if cls.token_cache["token"] and cls.token_cache["expire_time"] - current_time > 60:
+            # if current_time < cls.token_cache["expire_time"]:
+            #     print("使用缓存的Token")
+            return cls.token_cache["token"]
 
 
         # 如果没有缓存Token或者Token已过期,重新获取
         # 如果没有缓存Token或者Token已过期,重新获取
         new_token, expire_time = get_token()
         new_token, expire_time = get_token()
@@ -68,6 +69,9 @@ class TestSt:
             return None
             return None
 
 
     def __init__(self, tid, message_receiver=None):
     def __init__(self, tid, message_receiver=None):
+        self.is_closed = False
+        self.lock = threading.Lock()
+
         self.__th = threading.Thread(target=self.__test_run)
         self.__th = threading.Thread(target=self.__test_run)
         self.__id = tid
         self.__id = tid
         self.message_receiver = message_receiver
         self.message_receiver = message_receiver
@@ -79,10 +83,25 @@ class TestSt:
         self.__th.start()
         self.__th.start()
 
 
     def send_audio(self, audio_data):
     def send_audio(self, audio_data):
-        if self.sr:
-            # print("Sending audio data of length:", len(audio_data))
-            self.sr.send_audio(audio_data)
+        # if self.sr:
+        #     # print("Sending audio data of length:", len(audio_data))
+        #     self.sr.send_audio(audio_data)
             # print("Audio data sent.")
             # print("Audio data sent.")
+        if self.sr and not self.is_closed:
+            with self.lock:
+                try:
+                    self.sr.send_audio(audio_data)
+                except Exception as e:
+                    print(f"Error sending audio: {e}")
+                    self.close()
+    def close(self):
+        with self.lock:
+            if not self.is_closed:
+                self.is_closed = True
+                try:
+                    self.sr.stop()
+                except Exception as e:
+                    print(f"Error stopping ASR: {e}")
 
 
     def __test_run(self):
     def __test_run(self):
         print("Thread:{} start..".format(self.__id))
         print("Thread:{} start..".format(self.__id))

+ 7 - 0
src/core/voip/bot.py

@@ -21,6 +21,8 @@ from src.core.callcenter.api import BotChatRequest,ChatMessage
 from src.core import singleton_keys
 from src.core import singleton_keys
 from src.core.callcenter.snowflake import Snowflake
 from src.core.callcenter.snowflake import Snowflake
 
 
+from src.core.callcenter.data_handler import *
+
 calls = {}
 calls = {}
 # recording_file = '/code/src/core/voip/incoming_call.wav'
 # recording_file = '/code/src/core/voip/incoming_call.wav'
 # player_file1 = '/code/src/core/voip/test111.wav'
 # player_file1 = '/code/src/core/voip/test111.wav'
@@ -211,6 +213,8 @@ class MyCall(pj.Call):
         self.txtLock = False
         self.txtLock = False
         self.inputLongStart = time.time()    #长按键开始时间
         self.inputLongStart = time.time()    #长按键开始时间
 
 
+
+
     def wait_time_check(self, current_time, wait_time):
     def wait_time_check(self, current_time, wait_time):
         try:
         try:
             # 确保 wait_time 是整数类型
             # 确保 wait_time 是整数类型
@@ -362,6 +366,8 @@ class MyCall(pj.Call):
         elif action_code == 'transfer':  # 转人工
         elif action_code == 'transfer':  # 转人工
             print('todo 转人工')
             print('todo 转人工')
             self.agent.transfer(user_part=self.user_part, call_id=self.session_id, device_id=self.device_id)
             self.agent.transfer(user_part=self.user_part, call_id=self.session_id, device_id=self.device_id)
+            #更新通话记录机器人意图
+            self.agent.dataHandleServer.update_call_record_bussiness_type(self.session_id)
 
 
 class ToTextBotAgent:
 class ToTextBotAgent:
     def __init__(self, user_asr_text, call_agent):
     def __init__(self, user_asr_text, call_agent):
@@ -490,6 +496,7 @@ class BotAgent:
         self.is_stopping = False
         self.is_stopping = False
         self.acd_service = None
         self.acd_service = None
         self.cache = Cache(app)
         self.cache = Cache(app)
+        self.dataHandleServer = DataHandleServer(app)
         threading.Thread(target=self.create_pjsua2, daemon=True).start()
         threading.Thread(target=self.create_pjsua2, daemon=True).start()
 
 
     def create_pjsua2(self):
     def create_pjsua2(self):

Vissa filer visades inte eftersom för många filer har ändrats