Browse Source

merge callrecord

774056846 4 months ago
parent
commit
9beba3d4f4

+ 2 - 0
README.md

@@ -1,2 +1,4 @@
 # voice-gateway-service
 
+
+

+ 10 - 8
src/core/callcenter/acd.py

@@ -4,7 +4,7 @@ import time
 from datetime import datetime
 from queue import Queue
 from typing import Dict, Any, Optional
-import src.core.callcenter.cache as Cache
+from src.core.callcenter.cache import Cache
 from src.core.callcenter.agent import AgentOperService
 from src.core.callcenter.call import CallService
 from src.core.callcenter.api import CallInfo, AgentActionRequest
@@ -16,11 +16,13 @@ from src.core.callcenter.enumeration import AnswerFlag
 
 
 class AcdService:
-    def __init__(self, client, logger):
+    def __init__(self, client, app):
         self.client = client
-        self.logger = logger
-        self.call_service = CallService(client, logger)
-        self.agent_service = AgentOperService(client, logger)
+        self.app = app
+        self.logger = app.logger
+        self.cache = Cache(app)
+        self.call_service = CallService(client, app.logger)
+        self.agent_service = AgentOperService(client, app.logger)
         self.holdsQueue: Dict[str, Queue] = {}
         self.pool = ThreadPoolExecutor(max_workers=4)
         self.checkIdleScheduler = BackgroundScheduler()
@@ -28,11 +30,11 @@ class AcdService:
         self.checkIdleScheduler.start()
 
     def transfer_to_agent(self, call_id, device_id, service_id):
-        call_info = Cache.get_call_info(call_id)
+        call_info = self.cache.get_call_info(call_id)
         if not call_info:
             return
         call_info.answer_flag = AnswerFlag.TRANSFER_TO_AGENT.code
-        Cache.add_call_info(call_info)
+        self.cache.add_call_info(call_info)
         print('debugger::transfer_to_agent, come in ', flush=True)
         # 1. hold住并且播放等待音
         self.call_service.hold(call_info, device_id)
@@ -69,7 +71,7 @@ class AcdService:
         tmp_arr = []
         while not call_info_queue.empty():
             call_id = call_info_queue.get_nowait()
-            call_info = Cache.get_call_info(call_id)
+            call_info = self.cache.get_call_info(call_id)
             if not call_info or not call_info.device_list:
                 continue
             agent_number = self.agent_service.assign(AgentActionRequest(saas_id=saasId, service_id=task_service_id))

+ 141 - 140
src/core/callcenter/cache.py

@@ -11,148 +11,149 @@ from src.core.callcenter.api import AgentInfo, CallInfo, RouteGateway
 from src.core.callcenter.dao import Agent, Phone
 from src.core.datasource import RedisHandler
 
-cacheDay = 7
-deviceCall = {}
-deviceUserPart = {}
-redis_handler = RedisHandler()
-print(redis_handler.redis.info())
 
+class Cache:
+    def __init__(self, app):
+        self.cacheDay = 7
+        self.deviceCall = {}
+        self.deviceUserPart = {}
+        self.redis_handler = RedisHandler()
 
-def get_agent_info(saas_id, agent_number):
-    text = redis_handler.get(AGENT_INFO + saas_id + ":" + agent_number)
-    print('get_agent_info', saas_id, agent_number, text)
-    sys.stdout.flush()  # 强制刷新输出缓冲区
-    if text:
-        return AgentInfo.from_json(text)
-    phone = get_agent_phone(saas_id, agent_number)
-    agent_info = AgentInfo(saas_id=saas_id, sip_server=phone.sip_server, agent_number=agent_number)
-    print('get_agent_info', saas_id, agent_number, agent_info)
-    add_agent_info(agent=agent_info)
-    sys.stdout.flush()  # 强制刷新输出缓冲区
-    return agent_info
+    def get_agent_info(self, saas_id, agent_number):
+        text = self.redis_handler.get(AGENT_INFO + saas_id + ":" + agent_number)
+        print('get_agent_info', saas_id, agent_number, text)
+        sys.stdout.flush()  # 强制刷新输出缓冲区
+        if text:
+            return AgentInfo.from_json(text)
+        phone = self.get_agent_phone(saas_id, agent_number)
+        agent_info = AgentInfo(saas_id=saas_id, sip_server=phone.sip_server, agent_number=agent_number)
+        print('get_agent_info', saas_id, agent_number, agent_info, flush=True)
+        self.add_agent_info(agent=agent_info)
+        sys.stdout.flush()  # 强制刷新输出缓冲区
+        return agent_info
 
 
-def refresh_agent_token(agent_number, token):
-    redis_handler.set(AGENT_TOKEN + token, agent_number, cacheDay * 24 * 60 * 60)
-
-
-def delete_key(key):
-    redis_handler.redis.delete(key)
-
-
-def get_agent_number(token):
-    return redis_handler.get(AGENT_TOKEN + token)
-
-
-# 缓存坐席
-def add_agent_info(call_info: CallInfo = None, agent: AgentInfo = None, call_id=None, device_id=None):
-    if call_info and not agent:
-        agent = get_agent_info(call_info.saas_id, call_info.agent_key)
-    if not agent:
-        return
-    if call_id:
-        agent.call_id = call_id
-    if device_id:
-        agent.device_id = device_id
-    redis_handler.set(AGENT_INFO + agent.saas_id + ":" + agent.agent_number, agent.to_json_string(), cacheDay * 24 * 60 * 60)
-
-
-# 缓存CALL_INFO
-def add_call_info(call: CallInfo):
-    for k, v in call.device_info_map.items():
-        add_device(k, call.call_id)
-    # print('add_call_info', call.call_id, call.to_json_string())
-    redis_handler.set(CALL_INFO + call.call_id, call.to_json_string(), cacheDay * 24 * 60 * 60)
-
-
-def get_call_info_by_device_id(device_id):
-    call_id = deviceCall.get(device_id)
-    if not call_id:
-        return get_call_info(call_id)
-
-
-# 获取callInfo
-def get_call_info(call_id):
-    text = None
-    if call_id:
-        text = redis_handler.get(CALL_INFO + call_id)
-        # print('get_call_info', call_id, text)
-        # sys.stdout.flush()  # 强制刷新输出缓冲区
-    if text:
-        return CallInfo.from_json(text)
-
-
-def remove_call_info(call_id):
-    if not call_id:
-        return None
-    call_info = get_call_info(call_id)
-    if call_info and call_info.device_info_map:
-        for k, v in call_info.device_info_map.items():
-            deviceCall.pop(k)
-    delete_key(CALL_INFO + call_id)
-
-
-def add_device(device_id, call_id):
-    if not device_id or not call_id:
-        return None
-    deviceCall[device_id] = call_id
-
-
-def get_user_part(device_id):
-    return deviceUserPart.get(device_id)
-
-
-def add_device_user_part(device_id, user_part):
-    if not device_id or not user_part:
-        return
-    deviceUserPart[device_id] = user_part
-
-
-def get_route_gateway(saas_id):
-    return RouteGateway(id=1,
-                        saas_id=saas_id,
-                        name='63366692',
-                        media_host='192.168.20.99',
-                        media_port=5060,
-                        caller_prefix='',
-                        called_prefix='',
-                        status=0)
-
-
-def get_agent_phone(saas_id, agent_num):
-    return Phone.query.filter(Phone.saas_id == saas_id, Phone.phone_num == agent_num).first()
-
-def add_delay_message(action, delay_action, timeouts):
-    delay_action.uuid = uuid.uuid4()
-    key = CTI_ENGINE_DELAY_ACTION % action
-    msg = delay_action.to_json_string()
-    action_time = datetime.utcnow().timestamp() + timeouts * 1000
-    redis_handler.redis.zadd(key, {msg : action_time})
+    def refresh_agent_token(self, agent_number, token):
+        self.redis_handler.set(AGENT_TOKEN + token, agent_number, self.cacheDay * 24 * 60 * 60)
+
+
+    def delete_key(self, key):
+        self.redis_handler.redis.delete(key)
+
+
+    def get_agent_number(self, token):
+        return self.redis_handler.get(AGENT_TOKEN + token)
+
+
+    # 缓存坐席
+    def add_agent_info(self, call_info: CallInfo = None, agent: AgentInfo = None, call_id=None, device_id=None):
+        if call_info and not agent:
+            agent = self.get_agent_info(call_info.saas_id, call_info.agent_key)
+        if not agent:
+            return
+        if call_id:
+            agent.call_id = call_id
+        if device_id:
+            agent.device_id = device_id
+        self.redis_handler.set(AGENT_INFO + agent.saas_id + ":" + agent.agent_number, agent.to_json_string(), self.cacheDay * 24 * 60 * 60)
+
+
+    # 缓存CALL_INFO
+    def add_call_info(self, call: CallInfo):
+        for k, v in call.device_info_map.items():
+            self.add_device(k, call.call_id)
+        # print('add_call_info', call.call_id, call.to_json_string())
+        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):
+        call_id = self.deviceCall.get(device_id)
+        if not call_id:
+            return self.get_call_info(call_id)
+
+
+    # 获取callInfo
+    def get_call_info(self, call_id):
+        text = None
+        if call_id:
+            text = self.redis_handler.get(CALL_INFO + call_id)
+            # print('get_call_info', call_id, text)
+            # sys.stdout.flush()  # 强制刷新输出缓冲区
+        if text:
+            return CallInfo.from_json(text)
+
+
+    def remove_call_info(self, call_id):
+        if not call_id:
+            return None
+        call_info = self.get_call_info(call_id)
+        if call_info and call_info.device_info_map:
+            for k, v in call_info.device_info_map.items():
+                self.deviceCall.pop(k)
+        self.delete_key(CALL_INFO + call_id)
+
+
+    def add_device(self, device_id, call_id):
+        if not device_id or not call_id:
+            return None
+        self.deviceCall[device_id] = call_id
+
+
+    def get_user_part(self, device_id):
+        return self.deviceUserPart.get(device_id)
+
+
+    def add_device_user_part(self, device_id, user_part):
+        if not device_id or not user_part:
+            return
+        self.deviceUserPart[device_id] = user_part
+
+
+    def get_route_gateway(self, saas_id):
+        return RouteGateway(id=1,
+                            saas_id=saas_id,
+                            name='63366692',
+                            media_host='192.168.20.99',
+                            media_port=5060,
+                            caller_prefix='',
+                            called_prefix='',
+                            status=0)
+
+
+    def get_agent_phone(self, saas_id, agent_num):
+        return Phone.query.filter(Phone.saas_id == saas_id, Phone.phone_num == agent_num).first()
+
+    def add_delay_message(self, action, delay_action, timeouts):
+        delay_action.uuid = uuid.uuid4()
+        key = CTI_ENGINE_DELAY_ACTION % action
+        msg = delay_action.to_json_string()
+        action_time = datetime.utcnow().timestamp() + timeouts * 1000
+        self.redis_handler.redis.zadd(key, {msg : action_time})
 
-def get_delay_message(action):
-    key = CTI_ENGINE_DELAY_ACTION % action
-    current_time = int(time.time() * 1000)  # 毫秒级时间戳
-    members = redis_handler.redis.zrangebyscore(key, 0, current_time, start=0, num=DELAY_ACTION_BATCH_SIZE, withscores=True)
-    if not members:
-        return []
-    # scored_entries = [{"member": entry[0].decode('utf-8'), "score": entry[1]} for entry in members]
-    action_list = [entry[0].decode('utf-8') for entry in members]
-    if action_list:
-        redis_handler.redis.zrem(key, *action_list)
-    return action_list
-
-def lock_delay_action(val):
-    key = CTI_ENGINE_DELAY_ACTION_LOCK % val
-    return redis_handler.redis.set(key, "1", ex=60*10, nx=True)
-
-def set_need_play_hold_music(call_id):
-    key = NEED_PLAY_HOLD_MUSIC % call_id
-    return redis_handler.redis.set(key, "1", ex=60 * 1, nx=True)
-
-def get_need_play_hold_music(call_id):
-    key = NEED_PLAY_HOLD_MUSIC % call_id
-    return redis_handler.redis.get(key)
-
-def del_need_play_hold_music(call_id):
-    key = NEED_PLAY_HOLD_MUSIC % call_id
-    delete_key(key)
+    def get_delay_message(self, action):
+        key = CTI_ENGINE_DELAY_ACTION % action
+        current_time = int(time.time() * 1000)  # 毫秒级时间戳
+        members = self.redis_handler.redis.zrangebyscore(key, 0, current_time, start=0, num=DELAY_ACTION_BATCH_SIZE, withscores=True)
+        if not members:
+            return []
+        # scored_entries = [{"member": entry[0].decode('utf-8'), "score": entry[1]} for entry in members]
+        action_list = [entry[0].decode('utf-8') for entry in members]
+        if action_list:
+            self.redis_handler.redis.zrem(key, *action_list)
+        return action_list
+
+    def lock_delay_action(self, val):
+        key = CTI_ENGINE_DELAY_ACTION_LOCK % val
+        return self.redis_handler.redis.set(key, "1", ex=60*10, nx=True)
+
+    def set_need_play_hold_music(self, call_id):
+        key = NEED_PLAY_HOLD_MUSIC % call_id
+        return self.redis_handler.redis.set(key, "1", ex=60 * 1, nx=True)
+
+    def get_need_play_hold_music(self, call_id):
+        key = NEED_PLAY_HOLD_MUSIC % call_id
+        return self.redis_handler.redis.get(key)
+
+    def del_need_play_hold_music(self, call_id):
+        key = NEED_PLAY_HOLD_MUSIC % call_id
+        self.delete_key(key)

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

@@ -3,21 +3,23 @@
 
 import time
 from datetime import datetime
-import src.core.callcenter.cache as Cache
+from src.core.callcenter.cache import Cache
 from src.core.callcenter.constant import saasId, HOLD_MUSIC_PATH
-from src.core.callcenter.enumeration import CallCause, Direction, NextType, DeviceType, CdrType
+from src.core.callcenter.enumeration import CallCause, Direction, NextType, DeviceType, CdrType, AgentServiceState
 from src.core.callcenter.api import AgentCallRequest, CallInfo, HangupCallRequest, CheckInCallRequest, \
     DeviceInfo, NextCommand, MakeCallContext
 from src.core.callcenter.esl.constant.sip_header_constant import sipHeaderServiceId, sipHeaderCtiFlowId
 from src.core.callcenter.snowflake import Snowflake
-
+from src.core.callcenter.data_handler import *
 
 class CallService:
 
     def __init__(self, client, logger):
         self.client = client
         self.logger = logger
+        self.cache = Cache(client.app)
         self.snowflake = Snowflake()
+        self.dataHandleServer=DataHandleServer(client.app)
 
     def call(self, request: AgentCallRequest):
         call_id = 'C' + str(self.snowflake.next_id())
@@ -25,8 +27,8 @@ class CallService:
         # now = lambda: int(round(time.time() * 1000))
         now = datetime.utcnow().timestamp()
 
-        agent = Cache.get_agent_info(request.saas_id, request.agent_id)
-        route_gateway = Cache.get_route_gateway(request.saas_id)
+        agent = self.cache.get_agent_info(request.saas_id, request.agent_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,
                              caller=agent.agent_number, called=request.called, direction=Direction.INBOUND.code,
                              caller_display=request.caller_display, called_display=request.called_display,
@@ -37,7 +39,7 @@ class CallService:
         call_info.device_list.append(device_id)
         call_info.next_commands.append(NextCommand(device_id, NextType.NEXT_CALL_OTHER.code))
         call_info.device_info_map = {device_id: device_info}
-        Cache.add_call_info(call_info)
+        self.cache.add_call_info(call_info)
 
         context = MakeCallContext(display=request.called, caller=request.called, called=request.caller,
                                   call_id=call_id, device_id=device_id, device_type=device_info.device_type,
@@ -45,6 +47,17 @@ class CallService:
                                   sip_header_map={sipHeaderCtiFlowId: request.cti_flow_id})
 
         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)
         return call_id
 
     def hold(self, call_info: CallInfo, device_id):
@@ -58,7 +71,7 @@ class CallService:
         # self.client.sync_invoke_method("bridge_break", method_args=(custom_device_id,))
         # self.client.sync_invoke_method("hold_play", method_args=(custom_device_id,HOLD_MUSIC_PATH))
         self.client.bridge_break(call_info.call_id, custom_device_id)
-        Cache.set_need_play_hold_music(call_info.call_id)
+        self.cache.set_need_play_hold_music(call_info.call_id)
         print('debugger::hold success custom_device_id=%s'%custom_device_id, flush=True)
 
     def cancel_hold(self, call_info: CallInfo, device_id):
@@ -67,7 +80,7 @@ class CallService:
     def transfer(self, call_info: CallInfo, agent_number, service_id):
         caller = call_info.called
         call_id = call_info.call_id
-        agent = Cache.get_agent_info(call_info.saas_id, call_info.agent_key)
+        agent = self.cache.get_agent_info(call_info.saas_id, call_info.agent_key)
         device_id = 'D' + str(self.snowflake.next_id())
         # now = lambda: int(round(time.time() * 1000))
         now = datetime.utcnow().timestamp()
@@ -81,8 +94,8 @@ class CallService:
         call_info.next_commands.append(NextCommand(device_info.device_id, NextType.NEXT_TRANSFER_CALL.code, call_info.device_list[0]))
         call_info.agent_key = agent_number
         # agent.sip_server
-        Cache.add_call_info(call_info)
-        Cache.add_agent_info(agent=agent, call_id=call_id, device_id=device_id)
+        self.cache.add_call_info(call_info)
+        self.cache.add_agent_info(agent=agent, call_id=call_id, device_id=device_id)
 
         sip_header_map = {sipHeaderServiceId: service_id}
         context = MakeCallContext(display=call_info.called, caller=call_info.called, called=agent_number,
@@ -91,7 +104,7 @@ class CallService:
         self.client.make_call_new(context)
 
     def hangup(self, request: HangupCallRequest):
-        call_info = Cache.get_call_info(request.call_id)
+        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
@@ -110,7 +123,7 @@ class CallService:
             self.client.hangup_call(call_info.call_id, device, case_enum)
 
     def hangup_call(self, call_id):
-        call_info = Cache.get_call_info(call_id)
+        call_info = self.cache.get_call_info(call_id)
         if not call_info:
             self.logger.info('hangup call not exist callId: %s', call_id)
             return
@@ -122,5 +135,5 @@ class CallService:
             self.client.hangup_call(call_info.call_id, device, CallCause.RESTART)
 
     def checkin_call(self, request: CheckInCallRequest):
-        agent = Cache.get_agent_info(request.saas_id, request.agent_number)
+        agent = self.cache.get_agent_info(request.saas_id, request.agent_number)
         return self.client.show_channel(agent.device_id)

+ 5 - 1
src/core/callcenter/constant.py

@@ -108,5 +108,9 @@ def format_time_millis(time_millis, pattern='%Y%m%d'):
     return dt.strftime(pattern)
 
 
+# def get_record_prefix(call):
+#     return BASE_RECORD_PATH + call.call_type + '/' + call.saas_id + '/' + call.caller + '/' + format_time_millis(call.call_time)
+
 def get_record_prefix(call):
-    return BASE_RECORD_PATH + call.call_type + '/' + call.saas_id + '/' + call.caller + '/' + format_time_millis(call.call_time)
+    # 确保所有的值都是字符串类型
+    return BASE_RECORD_PATH + str(call.call_type) + '/' + str(call.saas_id) + '/' + str(call.caller) + '/' + format_time_millis(call.call_time)

+ 10 - 5
src/core/callcenter/dao.py

@@ -28,6 +28,7 @@ class Agent(db.Model):
     is_delete = db.Column(db.SmallInteger, nullable=False, default=0, comment='删除标识')
     update_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow, comment='更新时间')
     create_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime.utcnow, comment='创建时间')
+    user_id= db.Column(db.BigInteger, nullable=False, default='', comment='用户id')
 
     __table_args__ = (
         db.UniqueConstraint('saas_id', 'agent_num', name='uniq_vcc_id_agent_num'),
@@ -54,6 +55,7 @@ class Agent(db.Model):
             'is_delete': self.is_delete,
             'update_time': self.update_time.isoformat() if self.update_time else None,
             'create_time': self.create_time.isoformat() if self.create_time else None,
+            'user_id': self.user_id
         }
 
 
@@ -375,7 +377,7 @@ class Whitelist(db.Model):
     id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='主键')
     phone = db.Column(db.String(20), nullable=False, comment='电话号码')
     description = db.Column(db.String(255), nullable=True, comment='描述说明(备注)')
-    del_flag = db.Column(db.Boolean, nullable=False, default=False, comment='删除标志(0代表存在 2代表删除)')
+    del_flag = db.Column(db.SmallInteger, nullable=False, default=False, comment='删除标志(0代表存在 2代表删除)')
     revision = db.Column(db.Integer, nullable=True, comment='乐观锁')
     create_by = db.Column(db.String(32), nullable=True, comment='创建人')
     create_time = db.Column(db.DateTime, nullable=True, default=datetime.utcnow, comment='创建时间')
@@ -404,10 +406,10 @@ class CallRecord(db.Model):
 
     id = db.Column(db.Integer, primary_key=True, autoincrement=True, comment='主键')
     session_id = db.Column(db.String(30), nullable=True, comment='sessionId')
-    type = db.Column(db.SmallInteger, nullable=True, comment='呼入分类(0白名单 1AI服务 2传统服务)')
+    type = db.Column(db.SmallInteger, nullable=True,comment='呼入分类(0白名单 1AI服务 2传统服务)')
     user_id = db.Column(db.BigInteger, nullable=True, comment='客服ID')
     user_name = db.Column(db.String(255), nullable=True, comment='客服名字')
-    service_category = db.Column(db.SmallInteger, nullable=False, comment='服务类型(0人工坐席 1机器人坐席 2机器人转人工)')
+    service_category = db.Column(db.SmallInteger, nullable=False,default=0, comment='服务类型(0人工坐席 1机器人坐席 2机器人转人工)')
     time_begin = db.Column(db.DateTime, nullable=True, comment='通话发起时间')
     time_end = db.Column(db.DateTime, nullable=True, comment='通话结束时间')
     times = db.Column(db.String(30), nullable=True, comment='通话时长(暂时按字符串接收)')
@@ -417,15 +419,18 @@ class CallRecord(db.Model):
     bussiness_type = db.Column(db.String(50), nullable=True, comment='业务类型(创个返回字符串)')
     url = db.Column(db.String(255), nullable=True, comment='录音的地址')
     remark = db.Column(db.String(500), nullable=True, comment='备注')
-    has_parsed = db.Column(db.Boolean, nullable=False, default=False, comment='是否已转录音(0否 1是)')
+    has_parsed = db.Column(db.SmallInteger, nullable=False, default=0, comment='是否已转录音(0否 1是)')
     parsed_voice_content = db.Column(db.Text, nullable=True, comment='通话录音内容')
-    del_flag = db.Column(db.Boolean, nullable=False, default=False, comment='删除标志(0代表存在 2代表删除)')
+    del_flag = db.Column(db.SmallInteger, nullable=False, default=0, comment='删除标志(0代表存在 2代表删除)')
     revision = db.Column(db.Integer, nullable=True, comment='乐观锁')
     create_by = db.Column(db.String(32), nullable=True, default="admin", comment='创建人')
     create_time = db.Column(db.DateTime, nullable=True, default=datetime.utcnow, comment='创建时间')
     update_by = db.Column(db.String(32), nullable=True, default="admin", comment='更新人')
     update_time = db.Column(db.DateTime, nullable=True, onupdate=datetime.utcnow, comment='更新时间')
 
+    def __repr__(self):
+        return json.dumps(self.to_dict())
+
     def to_dict(self):
         return {
             'id': self.id,

+ 54 - 0
src/core/callcenter/data_handler.py

@@ -0,0 +1,54 @@
+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
+
+class DataHandleServer:
+    """通话记录服务"""
+    def __init__(self,app):
+        self.app = app
+
+    @with_app_context
+    def create_record(self, call_info):
+        call_record = CallRecord()
+        # 处理多余的参数
+        for key, value in call_info.items():
+            if hasattr(call_record, key):  # 确保模型有这个属性
+                setattr(call_record, key, value)
+        try:
+            if call_info.get("type") in [0, 2] or call_info.get("category") == 1:  # 如果呼入类型是白名单和传统服务或者是呼出 修改用户id和用户名称
+                agent_num = call_info.get("agent_num")  # 使用 get 方法
+                if agent_num:  # 确保 agent_num 存在
+                    agent = self.get_user_name(agent_num)
+                    call_record.user_id = agent.user_id
+                    call_record.user_name = agent.agent_name
+            db.session.add(call_record)
+            db.session.commit()
+            print("记录创建成功")
+        except Exception as e:
+            db.session.rollback()
+            raise ValueError(f"创建记录失败: {e}")
+
+    @with_app_context
+    def update_record(self, session_id, call_info):
+        call_record = CallRecord.query.filter_by(session_id=session_id).first()
+        # 动态更新字段
+        for key, value in call_info.items():
+            if hasattr(call_record, key):
+                setattr(call_record, key, value)
+        db.session.commit()
+
+    @with_app_context
+    def get_user_name(self,agent_num):
+        agent = Agent.query.filter(agent_num == agent_num).first()
+        return agent
+
+    @with_app_context
+    def update_agent_monitor_service_state(self, agent_num,service_state):
+        agent_monitor = AgentMonitor.query.filter(agent_num == agent_num).first()
+        agent_monitor.service_state = service_state
+        db.session.commit()

+ 58 - 43
src/core/callcenter/esl/client.py

@@ -15,7 +15,7 @@ import concurrent.futures
 
 from apscheduler.schedulers.background import BackgroundScheduler
 
-import src.core.callcenter.cache as Cache
+from src.core.callcenter.cache import Cache
 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
 from src.core.callcenter.esl.constant.esl_constant import BRIDGE_VARIABLES, BRIDGE, HANGUP, NORMAL_CLEARING, SIP_HEADER, SPACE, SPLIT, SOFIA, \
@@ -30,18 +30,19 @@ from src.core.callcenter.esl.handler.default_esl_event_handler import DefaultEsl
 from src.core.callcenter.snowflake import Snowflake
 from src.core.datasource import SERVE_HOST
 from src.core.voip.constant import *
-from src.core.callcenter.dao import *
-
+from src.core.callcenter.data_handler import *
 class InboundClient:
 
-    def __init__(self, agent, logger):
+    def __init__(self, agent, app):
         self.con = None
         self.thread_num = 12
         self.is_stopping = False
-        self.logger = logger
+        self.app = app
+        self.logger = app.logger
         self.bot_agent = agent
+        self.cache = Cache(app)
         self.handler_table = self.scan_esl_event_handlers()
-        self.default_event_handler = DefaultEslEventHandler(self, self.bot_agent, self.logger)
+        self.default_event_handler = DefaultEslEventHandler(self, self.bot_agent)
         self.host, self.port, self.password = SERVE_HOST, '8021', '4918257983818884358'
         self.executors = {x: concurrent.futures.ThreadPoolExecutor(max_workers=1) for x in range(self.thread_num)}
         self.delay_action_executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
@@ -52,7 +53,7 @@ class InboundClient:
 
     def submit_delay_action(self):
         for name, member in DelayActionEnum.__members__.items():
-            action_messages = Cache.get_delay_message(name)
+            action_messages = self.cache.get_delay_message(name)
             for action_message in action_messages:
                 self.delay_action_executor.submit(self.do_delay_action, name, action_message)
 
@@ -72,7 +73,7 @@ class InboundClient:
         handlers = {}
         for _cls in classes:
             items = handlers.get(_cls._esl_event_name, [])
-            items.append(_cls(self, self.bot_agent, self.logger))
+            items.append(_cls(self, self.bot_agent))
             handlers[_cls._esl_event_name] = items
         return handlers
 
@@ -129,7 +130,7 @@ class InboundClient:
 
     def do_delay_action(self, action, message):
         delay_action = DelayAction.from_json(message)
-        flag = Cache.lock_delay_action(delay_action.uuid)
+        flag = self.cache.lock_delay_action(delay_action.uuid)
         if not flag:
             self.logger.info("异步延迟执行操作重复 action:%s msg:%s", action, message)
             return
@@ -146,7 +147,7 @@ class InboundClient:
             self.exec_when_acd_timeout(delay_action.call_id)
 
     def exec_when_call_timeout(self, call_id, device_id):
-        call_info = Cache.get_call_info(call_id)
+        call_info = self.cache.get_call_info(call_id)
         if not call_info or not (device_id in call_info.device_list):
             return
         device_info = call_info.device_info_map.get(device_id)
@@ -164,12 +165,12 @@ class InboundClient:
                 channel = self.show_channel(device_id)
                 if channel:
                     delay_action = DelayAction(call_id=call_id, device_id=device_id)
-                    Cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_DECR, delay_action, timeouts=20)
-            Cache.add_call_info(call_info)
+                    self.cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_DECR, delay_action, timeouts=20)
+            self.cache.add_call_info(call_info)
             self.hangup_call(call_id, device_id, CallCause.CALL_TIMEOUT)
 
     def exec_when_play_timeout(self, call_id):
-        call_info = 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:
             return
         self.logger.debug("播放结束音乐失败,进行挂机 callId:%s", call_id)
@@ -179,7 +180,7 @@ class InboundClient:
                 self.hangup_call(call_id, device_id, CallCause.PLAY_TIMEOUT)
 
     def exec_when_acd_timeout(self, call_id):
-        call_info = Cache.get_call_info(call_id)
+        call_info = self.cache.get_call_info(call_id)
         if not call_info:
             self.logger.info("exec_when_acd_timeout callInfo为空 callId: {}", call_id)
             return
@@ -189,7 +190,7 @@ class InboundClient:
             self.bridge_break(device_id)
             self.hold_play(device_id, HOLD_MUSIC_PATH)
             self.play_timeout(call_id, timeout=30)
-            Cache.add_call_info(call_info)
+            self.cache.add_call_info(call_info)
             self.logger.info("waitingTimeOut 开始播放结束音乐 callId:%s customerDeviceId:%s playFile:%s", call_id,
                              device_id, HOLD_MUSIC_PATH)
 
@@ -268,7 +269,7 @@ class InboundClient:
     def call_timeout(self, call_id, device_id, timeout):
         """呼叫超时主动挂机"""
         delay_action = DelayAction(call_id=call_id, device_id=device_id)
-        Cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_HANGUP.code, delay_action, timeouts=timeout)
+        self.cache.add_delay_message(DelayActionEnum.CALL_TIMEOUT_HANGUP.code, delay_action, timeouts=timeout)
 
     def send_args(self, device_id, name, arg, con=None):
         msg = ESL.ESLevent("sendmsg", device_id)
@@ -490,7 +491,7 @@ class InboundClient:
     def play_timeout(self, call_id, timeout):
         """播放超时主动挂机"""
         delay_action = DelayAction(call_id=call_id)
-        Cache.add_delay_message(DelayActionEnum.PLAY_TIMEOUT_HANGUP.code, delay_action, timeouts=timeout)
+        self.cache.add_delay_message(DelayActionEnum.PLAY_TIMEOUT_HANGUP.code, delay_action, timeouts=timeout)
 
     def listen(self, device_id1, device_id2, aleg=True, bleg=True):
         """监听"""
@@ -519,17 +520,19 @@ class InboundClient:
 
 class OutboundClient:
 
-    def __init__(self, agent, logger,app):
-        self.logger = logger
+    def __init__(self, agent, app):
         self.app = app
+        self.logger = app.logger
         self.whitelist = []
         self.update_whitelist()  # 初始化加载白名单
 
         # 定时更新白名单
         threading.Thread(target=self.refresh_whitelist, daemon=True).start()
 
+
+        self.dataHandleServer = DataHandleServer(app)
         #threading.Thread(target=self.start, args=('0.0.0.0', 8084, agent, logger)).start()
-        server_thread = threading.Thread(target=self.start, args=('0.0.0.0', 8084, agent, logger))
+        server_thread = threading.Thread(target=self.start, args=('0.0.0.0', 8084, agent))
         server_thread.daemon = True  # 设置守护线程
         server_thread.start()
 
@@ -553,6 +556,7 @@ class OutboundClient:
             agent_nums = [agent.agent_num for agent in agents]
             return agent_nums
 
+
     class ESLRequestHandler(socketserver.BaseRequestHandler):
         def setup(self):
             try:
@@ -569,30 +573,39 @@ class OutboundClient:
                     caller_number = info.getHeader("Caller-Caller-ID-Number")  # 获取来电号码
                     whitelist = self.server.load_whitelist()
 
-                     # 检查白名单
-                    if caller_number in whitelist:
-                        # 直接转接到人工坐席
-                        agents = self.server.load_agent_monitor()
-                        # 随机取一个坐席号
-                        destination = random.choice(agents)
-                        # 直接转接到人工坐席
-                        self.server.logger.info("Caller %s is in whitelist, directly transferring call, agents: %s, destination: %s", caller_number, agents,destination)
-                        return
-                    
-
                     call_id = 'C' + str(Snowflake().next_id())
                     new_device_id = 'D' + str(Snowflake().next_id())
 
                     kwargs = json.loads(info.serialize('json'))
                     kwargs['variable_sip_h_P-LIBRA-CallId'] = call_id
                     kwargs['variable_sip_h_P-LIBRA-DeviceId'] = new_device_id
-                    destination = self.server.agent.register(**kwargs)
-                    self.server.logger.info("debugger::device_id=%s, destination=%s, new_device_id=%s", device_id, destination, new_device_id)
-
-                    self.build_call_info(call_id, device_id, new_device_id, str(destination), **kwargs)
-                    Cache.add_device_user_part(device_id, destination)
-                    con.execute("bridge", "{sip_h_P-LIBRA-CallId=%s,sip_h_P-LIBRA-DeviceId=%s,origination_uuid=%s}user/%s"%(call_id, new_device_id, new_device_id, destination), device_id)
-
+                    call_info = {
+                        "session_id": call_id,
+                        "time_begin": datetime.utcnow(),
+                        "category": 0,
+                        "phone": caller_number
+                    }
+                    # 检查白名单
+                    if caller_number in whitelist:
+                        agents = self.server.load_agent_monitor()
+                        destination = random.choice(agents) # 随机取一个坐席号
+                        # 直接转接到人工坐席
+                        self.server.logger.info( "Caller %s is in whitelist, agents: %s, destination: %s", caller_number, agents, destination)
+                        call_info['type']= 0
+                        call_info['agent_num'] = destination
+                    else:
+                        #转到ai机器人
+                        destination = self.server.agent.register(**kwargs)
+                        self.server.logger.info("debugger::device_id=%s, destination=%s, new_device_id=%s", device_id, destination, new_device_id)
+                        call_info['type'] = 1
+                        call_info['service_category'] = 1
+                        call_info['user_id'] = destination
+                        call_info['user_name'] = f"机器人{destination}"
+                        self.build_call_info(call_id, device_id, new_device_id, str(destination), **kwargs)
+                        self.server.cache.add_device_user_part(device_id, destination)
+                        con.execute("bridge", "{sip_h_P-LIBRA-CallId=%s,sip_h_P-LIBRA-DeviceId=%s,origination_uuid=%s}user/%s"%(call_id, new_device_id, new_device_id, destination), device_id)
+
+                    self.server.dataHandleServer.create_record(call_info)
                     # destination = "user/1001"
                     # msg = ESL.ESLevent("sendmsg", uuid)
                     # msg.addHeader("call-command", "execute")
@@ -635,20 +648,22 @@ class OutboundClient:
             call_info.device_list.append(new_device_id)
             # call_info.next_commands.append(NextCommand(device_id, NextType.NEXT_CALL_BRIDGE.code, new_device_id))
             call_info.device_info_map = {device_id: device_custom, new_device_id: device_bot}
-            Cache.add_call_info(call_info)
+            self.server.cache.add_call_info(call_info)
 
 
     class CustomTCPServer(socketserver.TCPServer):
-        def __init__(self, server_address, RequestHandlerClass, agent, logger,whitelist_loader,load_agent_monitor):
+        def __init__(self, server_address, RequestHandlerClass, agent, app,whitelist_loader,load_agent_monitor,dataHandleServer):
             self.agent = agent
-            self.logger = logger
+            self.cache = Cache(app)
+            self.logger = app.logger
             self.load_whitelist = whitelist_loader
             self.load_agent_monitor = load_agent_monitor
+            self.dataHandleServer = dataHandleServer
             super().__init__(server_address, RequestHandlerClass)
 
-    def start(self, HOST='0.0.0.0', PORT=8084, agent=None, logger=None):
+    def start(self, HOST='0.0.0.0', PORT=8084, agent=None):
         # HOST, PORT = "0.0.0.0", 8084
         # 创建一个 TCP 服务器
-        with self.CustomTCPServer((HOST, PORT), self.ESLRequestHandler, agent, logger, self.load_whitelist, self.load_agent_monitor) as server:
+        with self.CustomTCPServer((HOST, PORT), self.ESLRequestHandler, agent, self.app, self.load_whitelist, self.load_agent_monitor,self.dataHandleServer) as server:
             self.logger.info(f"ESL server listening on {HOST}:{PORT}")
             server.serve_forever()

+ 17 - 15
src/core/callcenter/esl/handler/channel_answer_handler.py

@@ -4,7 +4,6 @@ import json
 import time
 from datetime import datetime
 from src.core.callcenter.constant import saasId, get_record_prefix
-import src.core.callcenter.cache as Cache
 from src.core.callcenter.enumeration import NextType, AnswerFlag, Direction, DeviceType, AgentScene, CdrType
 from src.core.callcenter.esl.annotation import EslEventName
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
@@ -14,18 +13,20 @@ from src.core.callcenter.api import CallInfo, DeviceInfo, NextCommand, MakeCallC
 from src.core.callcenter.push import PushHandler
 from src.core.callcenter.snowflake import Snowflake
 
+from src.core.callcenter.data_handler import *
 
 @EslEventName(CHANNEL_ANSWER)
 class ChannelAnswerHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
         self.snowflake = Snowflake()
-        self.push_handler = PushHandler(logger)
+        self.push_handler = PushHandler(inbound_client.logger)
+        self.dataHandleServer = DataHandleServer(inbound_client.app)
 
     def handle(self, address, event, coreUUID):
         call_id = EslEventUtil.getCallId(event)
-        call_info = Cache.get_call_info(call_id)
+        call_info = self.cache.get_call_info(call_id)
         self.logger.info("answer call_id:%s, call_info:%s, event:%s", call_id, call_info, json.loads(event.serialize('json')))
         if not call_info:
             return
@@ -54,17 +55,18 @@ class ChannelAnswerHandler(EslEventHandler):
             self.listen(call_info, device_info, next_command, event)
         else:
             self.logger.warn("can not match command :%s, callId :%s", next_command.next_type, call_id)
-        Cache.add_call_info(call_info)
+        self.cache.add_call_info(call_info)
 
     def call_other(self, call: CallInfo, device: DeviceInfo):
         call_id = call.call_id
         device_id = device.device_id
 
         # 启用录音, 生产时候打开
-        # record = get_record_prefix(call) + '/' + call_id + '.wav'
-        # self.inbound_client.record(device.device_id, 'start', record, 0)
-        # device.record = record
-        # device.record_start_time = device.answer_time
+        record = get_record_prefix(call) + '/' + call_id + '.wav'
+        self.inbound_client.record(device.device_id, 'start', record, 0)
+        device.record = record
+        device.record_start_time = device.answer_time
+        self.dataHandleServer.update_record(call_id, {"url": record})
 
         call.direction = Direction.OUTBOUND.code
         call.answer_flag = AnswerFlag.AGENT_ANSWER.code
@@ -78,15 +80,15 @@ class ChannelAnswerHandler(EslEventHandler):
 
         # now = lambda: int(round(time.time() * 1000))
         now = datetime.utcnow().timestamp()
-        route_gateway = Cache.get_route_gateway(call.saas_id)
-        agent = Cache.get_agent_info(call.saas_id, call.agent_key)
+        route_gateway = self.cache.get_route_gateway(call.saas_id)
+        agent = self.cache.get_agent_info(call.saas_id, call.agent_key)
         new_device = DeviceInfo(device_id=new_device_id, call_id=call_id, agent_key=call.agent_key,
                                 called=called, display=call.called_display, caller=call.called_display,
                                 call_time=now, device_type=DeviceType.CUSTOMER.code, caller_display=route_gateway.name, cdr_type=CdrType.OUTBOUND.code)
         call.next_commands.append(NextCommand(device_id=device_id, next_type=NextType.NEXT_CALL_BRIDGE.code, next_value=new_device_id))
         call.device_info_map[new_device_id] = new_device
-        Cache.add_call_info(call)
-        Cache.add_agent_info(agent=agent, call_id=call_id, device_id=device_id)
+        self.cache.add_call_info(call)
+        self.cache.add_agent_info(agent=agent, call_id=call_id, device_id=device_id)
 
         context = MakeCallContext(display=new_device.caller_display, caller=new_device.caller_display, called=called,
                                   call_id=call_id, device_id=new_device_id, device_type=new_device.device_type,
@@ -103,7 +105,7 @@ class ChannelAnswerHandler(EslEventHandler):
             device1.bridge_time = EslEventUtil.getEventDateTimestamp(event)
         if not device2.bridge_time:
             device2.bridge_time = EslEventUtil.getEventDateTimestamp(event)
-        Cache.add_call_info(call)
+        self.cache.add_call_info(call)
 
         self.inbound_client.bridge_call(call.call_id, next_command.device_id, next_command.next_value)
 

+ 13 - 4
src/core/callcenter/esl/handler/channel_bridge_handler.py

@@ -1,16 +1,25 @@
 #!/usr/bin/env python3
 # encoding:utf-8
-
 from src.core.callcenter.esl.annotation import EslEventName
+from src.core.callcenter.enumeration import  DeviceType, AgentServiceState
 from src.core.callcenter.esl.constant.event_names import CHANNEL_BRIDGE
 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.data_handler import *
 
 @EslEventName(CHANNEL_BRIDGE)
 class ChannelBridgeHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
+        self.dataHandleServer = DataHandleServer(inbound_client.app)
 
     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('debugger::device_id is23232323232 ', device_id, device, flush=True)
+        if device.device_type == DeviceType.AGENT.code: # 如果是坐席接听 变更坐席状态
+            self.dataHandleServer.update_agent_monitor_service_state(device_id, AgentServiceState.IDLE.code)
         pass

+ 2 - 2
src/core/callcenter/esl/handler/channel_hangup_complete_handler.py

@@ -9,8 +9,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 @EslEventName(CHANNEL_HANGUP_COMPLETE)
 class ChannelHangupCompleteHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         pass

+ 19 - 12
src/core/callcenter/esl/handler/channel_hangup_handler.py

@@ -5,25 +5,25 @@ import json
 import sys
 import traceback
 
-import src.core.callcenter.cache as Cache
 from src.core.callcenter.acd import AcdService
 from src.core.callcenter.call import CallService
 from src.core.callcenter.enumeration import CallType, DeviceType, AnswerFlag, NextType, CdrType, HangupDir, \
-    CallCause
+    CallCause,AgentServiceState
 from src.core.callcenter.esl.annotation import EslEventName
 import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
 from src.core.callcenter.esl.constant.event_names import CHANNEL_HANGUP
 from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 from src.core.callcenter.api import CallInfo, DeviceInfo, NextCommand
-
+from src.core.callcenter.data_handler import *
 
 @EslEventName(CHANNEL_HANGUP)
 class ChannelHangupHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
-        # self.acd_service = AcdService(inbound_client, logger)
-        # self.call_service = CallService(inbound_client, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
+        self.acd_service = AcdService(inbound_client)
+        self.call_service = CallService(inbound_client)
+        self.dataHandleServer=DataHandleServer(inbound_client.app)
 
     def handle(self, address, event, coreUUID):
         print(json.loads(event.serialize('json')), flush=True)
@@ -34,7 +34,7 @@ class ChannelHangupHandler(EslEventHandler):
                 self.release(event)
                 print("call_id is null", flush=True)
                 return
-            call = Cache.get_call_info(call_id)
+            call = self.cache.get_call_info(call_id)
             print('debugger::call_info is ', call, flush=True)
             if not call:
                 print("call:%s is null", call_id, flush=True)
@@ -78,13 +78,17 @@ class ChannelHangupHandler(EslEventHandler):
             if device.record_start_time:
                 device.record_time = int(device.end_time) - int(device.record_start_time)
             call.device_info_map[device.device_id] = device
+            # print("ceshiyix shijian",device)
+            # 更新通话记录
+            # self.dataHandleServer.update_record(call_id, {"time_end": datetime.fromtimestamp(int(device.end_time)),"times":device.talk_time})
+
             print('debugger::ChannelHangupHandler, hangup_reason=%s, device_type=%s' % (hangup_reason, device.device_type), flush=True)
             # 如果是转人工
             # if 'transferToAgent' == hangup_reason and DeviceType.ROBOT.code == device.device_type:
             #     call.answer_flag = AnswerFlag.TRANSFER_TO_AGENT.code
             #     service_id = EslEventUtil.getLIBRAServiceId(event)
             #     call.transfer_agent = True
-            #     Cache.add_call_info(call)
+            #     self.cache.add_call_info(call)
             #     print('debugger::ChannelHangupHandler, transferToAgent, service_id=%s' % (service_id), flush=True)
             #     self.acd_service.transfer_to_agent(call, device_id, service_id)
             #     return
@@ -103,13 +107,16 @@ class ChannelHangupHandler(EslEventHandler):
 
             # 判断挂机方向 && 更新缓存
             self.hangup_dir(call, device, cause)
-            Cache.add_call_info(call)
+            self.cache.add_call_info(call)
+
+            if len(call.device_list)==0 and device.device_type == DeviceType.AGENT.code:
+                self.dataHandleServer.update_agent_monitor_service_state(device_id, AgentServiceState.IDLE.code)
         except:
             traceback.print_exc()
 
     def release(self, event):
         device_id = event.getHeader("Unique-ID")
-        user_part = Cache.get_user_part(device_id)
+        user_part = self.cache.get_user_part(device_id)
         self.logger.info(f"release device_id={device_id}, user_part={user_part}")
         self.bot_agent.release(user_part)
 
@@ -127,7 +134,7 @@ class ChannelHangupHandler(EslEventHandler):
 
         # 判断挂机方向 && 更新缓存
         self.hangup_dir(call, device, cause)
-        Cache.add_call_info(call)
+        self.cache.add_call_info(call)
 
     def hangup_dir(self, call:CallInfo, device:DeviceInfo, cause):
         if call.hangup_dir or device.cdr_type > CdrType.CONSULT.code:

+ 6 - 7
src/core/callcenter/esl/handler/channel_park_handler.py

@@ -2,7 +2,6 @@
 # encoding:utf-8
 
 import json
-import src.core.callcenter.cache as Cache
 from src.core.callcenter.constant import HOLD_MUSIC_PATH
 from src.core.callcenter.enumeration import DeviceType
 from src.core.callcenter.esl.constant.esl_constant import SIP_HEADER
@@ -16,8 +15,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 @EslEventName(CHANNEL_PARK)
 class ChannelParkHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         print("ChannelParkHandler, event=%s", json.loads(event.serialize('json')), flush=True)
@@ -39,17 +38,17 @@ class ChannelParkHandler(EslEventHandler):
         print('debugger, ChannelParkHandler, call_id=%s, device_id=%s'%(call_id, device_id), flush=True)
         if not call_id or not device_id:
             return
-        call_info = Cache.get_call_info(call_id)
+        call_info = self.cache.get_call_info(call_id)
         if not call_info:
             print("CHANNEL_PARK callInfo is null", flush=True)
             return
 
         device_info = call_info.device_info_map.get(device_id)
-        hold = Cache.get_need_play_hold_music(call_id)
+        hold = self.cache.get_need_play_hold_music(call_id)
         print('debugger, ChannelParkHandler, hold=%s, device_info=%s' % (hold, device_info), flush=True)
         if hold and device_info.device_type == DeviceType.CUSTOMER.code:
             self.inbound_client.hold_play(device_id, HOLD_MUSIC_PATH)
-            Cache.del_need_play_hold_music(call_id)
+            self.cache.del_need_play_hold_music(call_id)
             self.inbound_client.set_var(device_id, SIP_HEADER + sipHeaderHoldMusic, "false")
 
     def process_fxo_calling(self, event):
@@ -62,7 +61,7 @@ class ChannelParkHandler(EslEventHandler):
         print(f"Incoming call with UUID: {device_id}  {service} is transfer to {destination}")
         #self.inbound_client.con.execute("transfer", f"{destination} XML pbx.fuxicarbon.com", device_id)
         # self.con.execute("answer", "", call_uuid)
-        Cache.add_device_user_part(device_id, destination)
+        self.cache.add_device_user_part(device_id, destination)
         self.inbound_client.con.execute("bridge", f"user/{destination}", device_id)
 
         # destination = "user/1001"

+ 2 - 2
src/core/callcenter/esl/handler/channel_progress_media_handler.py

@@ -9,8 +9,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 @EslEventName(CHANNEL_PROGRESS_MEDIA)
 class ChannelProgressMediaHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         pass

+ 2 - 2
src/core/callcenter/esl/handler/default_esl_event_handler.py

@@ -8,8 +8,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 
 class DefaultEslEventHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         # self.logger.info(json.loads(event.serialize('json')))

+ 2 - 2
src/core/callcenter/esl/handler/detected_tone_handler.py

@@ -10,8 +10,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 @EslEventName(DETECTED_TONE)
 class DetectedToneHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         pass

+ 2 - 2
src/core/callcenter/esl/handler/dtmf_handler.py

@@ -9,8 +9,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 @EslEventName(DTMF)
 class DTMFHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         pass

+ 5 - 2
src/core/callcenter/esl/handler/esl_event_handler.py

@@ -1,14 +1,17 @@
 #!/usr/bin/env python3
 # encoding:utf-8
 
+from src.core.callcenter.cache import Cache
 from abc import ABC, abstractmethod
 
 
 class EslEventHandler(ABC):
-    def __init__(self, inbound_client, bot_agent, logger):
+    def __init__(self, inbound_client, bot_agent):
         self.inbound_client = inbound_client
         self.bot_agent = bot_agent
-        self.logger = logger
+        self.app = inbound_client.app
+        self.logger = inbound_client.logger
+        self.cache = Cache(inbound_client.app)
 
     @abstractmethod
     def handle(self, address, event, coreUUID):

+ 2 - 2
src/core/callcenter/esl/handler/playback_stop_handler.py

@@ -9,8 +9,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 @EslEventName(PLAYBACK_STOP)
 class PlaybackStopHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         pass

+ 2 - 2
src/core/callcenter/esl/handler/record_stop_handler.py

@@ -9,8 +9,8 @@ from src.core.callcenter.esl.handler.esl_event_handler import EslEventHandler
 @EslEventName(RECORD_STOP)
 class RecordStopHandler(EslEventHandler):
 
-    def __init__(self, inbound_client, bot_agent, logger):
-        super().__init__(inbound_client, bot_agent, logger)
+    def __init__(self, inbound_client, bot_agent):
+        super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
         pass

+ 4 - 5
src/core/callcenter/views.py

@@ -1,7 +1,6 @@
 #!/usr/bin/env python3
 # encoding:utf-8
 from . import app
-import src.core.callcenter.cache as Cache
 from src.core.callcenter.agent import AgentService, AgentOperService
 from src.core.callcenter.constant import success_response, error_response
 from src.core.callcenter.enumeration import CallType
@@ -15,8 +14,8 @@ from src.core.voip.bot import BotAgent
 from .acd import AcdService
 
 agent = BotAgent(app.logger)
-inbound_client = InboundClient(agent, app.logger)
-outbound_client = OutboundClient(agent, app.logger,app)
+inbound_client = InboundClient(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)
@@ -188,8 +187,8 @@ def manual_call():
 def manual_hang():
     """挂断"""
     data = request.get_json()
-    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=agent.agent_number)
+    # 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)
     return success_response()
 

+ 3 - 3
src/core/voip/bot.py

@@ -220,7 +220,7 @@ class MyCall(pj.Call):
                 self.play_start_time = current_time
                 # print(f"开始计时: {self.play_start_time}")
             elapsed_time = int(current_time - self.play_start_time)
-            print(f"当前时间: {current_time}, 已过时间: {elapsed_time}, 最大等待时间: {wait_time}")
+            # print(f"当前时间: {current_time}, 已过时间: {elapsed_time}, 最大等待时间: {wait_time}")
             if elapsed_time >= wait_time:
                 # self.user_asr_text_queue.put("ASR408error")
                 self.chat('ASR408error')
@@ -375,8 +375,8 @@ class ToTextBotAgent:
         )
         print("user_asr_text发送结果:", user_asr_text)
         # 发送请求并处理响应
-        # self.test_request(self.request_data)
-        self.to_quest(self.request_data)
+        self.test_request(self.request_data)
+        # self.to_quest(self.request_data)
 
 
     def to_quest(self, request: BotChatRequest):