فهرست منبع

Merge branch 'develop' into jms_20250106_prod

Davidliu 2 ماه پیش
والد
کامیت
668cc0caaf

+ 1 - 1
docker-compose.yml

@@ -1,7 +1,7 @@
 services:
   pjsua:
     image: pjsua2:v2.14.1214
-    container_name: pjsua
+    container_name: voip
     restart: always
 #    network_mode: host
     volumes:

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

@@ -45,13 +45,13 @@ class AcdService:
         agent_number = self.agent_service.assign(AgentActionRequest(saas_id=SAAS_ID, service_id=service_id))
         if not agent_number:
             # 如果没有空闲坐席,播放等待音
-            text = "AcdService transferToAgent agentNumber is empty serviceId:%s,called:%s,callId:%s"%(service_id, call_info.called, call_info.call_id)
+            text = "AcdService transferToAgent agentNumber is empty serviceId:%s,caller:%s,called:%s,callId:%s"%(service_id, call_info.caller, call_info.called, call_info.call_id)
             # print(text, flush=True)
             self.logger.info(text)
             self.add_acd_queue(call_info, service_id)
         else:
             # 有空闲坐席,直接转接
-            text = "AcdService transferToAgent agentNumber not empty %s, serviceId:%s,called:%s,callId:%s"%(agent_number, service_id, call_info.called, call_info.call_id)
+            text = "AcdService transferToAgent agentNumber not empty %s, serviceId:%s,caller:%s,called:%s,callId:%s"%(agent_number, service_id, call_info.caller,call_info.called, call_info.call_id)
             # print(text, flush=True)
             self.logger.info(text)
             self.call_service.transfer(call_info, agent_number, service_id)

+ 7 - 3
src/core/callcenter/agent.py

@@ -144,7 +144,8 @@ class AgentEventService:
                     if call_id:
                         self.cache.set_call_is_end(call_id)
                 self.agent_monitor_service.update_processing(agent_monitor)
-                self.logger.info('挂断更新')
+                self.logger.info('挂断更新:%s', agent)
+                # self.data_handle_server.update_record(call_id, user_id=agent.user_id, user_name=agent.agent_name)
                 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)
@@ -203,11 +204,12 @@ class AgentEventService:
             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,phone=call_info.caller)
+                self.data_handle_server.update_record(call_id, transfer_user_id=agent.user_id,transfer_user_name=agent.agent_name)  #转接给客服以后更新转接人
 
 
             if CHANNEL_ANSWER == event_name:
                 self.agent_state_service.busy(saas_id, agent.agent_num, agent.phone_num)
-                self.data_handle_server.update_record(call_id, status=1, transfer_user_id=agent.user_id,transfer_user_name=agent.agent_name)
+                # self.data_handle_server.update_record(call_id, status=1, transfer_user_id=agent.user_id,transfer_user_name=agent.agent_name)
                 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")
@@ -280,7 +282,7 @@ class AgentOperService:
                 if sec > self.agent_heartbeat_expire:
                     self.redis_handler.redis.hdel(_name, key)
                     self.logger.error("agent heartbeat expired, will checkout %s %s", key, value)
-                    self.checkout(AgentActionRequest(saas_id=SAAS_ID, agent_id=key, agent_number=key))
+                    # self.checkout(AgentActionRequest(saas_id=SAAS_ID, agent_id=key, agent_number=key))
             except:
                 traceback.print_exc()
 
@@ -289,6 +291,8 @@ class AgentOperService:
         members = self.redis_handler.redis.hgetall(name)
         if not members:
             return
+
+        registry.MANUAL_AGENT_LIVES.set(len(members))
         for k,v in members.items():
             check_out_daemon(name, k, v)
         # time.sleep(1)

+ 6 - 4
src/core/callcenter/dao.py

@@ -111,10 +111,10 @@ class AgentActionLog(db.Model):
     pre_check_state = db.Column(db.SmallInteger, nullable=False, default=-1, comment='上一次签入或签出')
     service_state = db.Column(db.SmallInteger, nullable=False, default=-1, comment='坐席状态')
     pre_service_state = db.Column(db.SmallInteger, nullable=False, default=-1, comment='上一次坐席状态')
-    check_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime(2000, 1, 1), comment='签入或签出时间')
-    pre_check_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime(2000, 1, 1), comment='上一次签入或签出时间')
-    service_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime(2000, 1, 1), comment='坐席状态变更时间')
-    pre_service_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime(2000, 1, 1), comment='上一次坐席状态变更时间')
+    check_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime.now, comment='签入或签出时间')
+    pre_check_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime.now, comment='上一次签入或签出时间')
+    service_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime.now, comment='坐席状态变更时间')
+    pre_service_state_time = db.Column(db.TIMESTAMP, nullable=False, default=datetime.now, comment='上一次坐席状态变更时间')
     check_state_duration = db.Column(db.BigInteger, nullable=False, default=0, comment='行为持续时间')
     service_state_duration = db.Column(db.BigInteger, nullable=False, default=0, comment='状态持续时间')
     task_id = db.Column(db.String(32), nullable=False, default='', comment='任务Id')
@@ -412,6 +412,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='描述说明(备注)')
+    type = db.Column(db.SmallInteger, nullable=False, default='0', comment='类型(0人工白名单  1机器人白名单)')
     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='创建人')
@@ -425,6 +426,7 @@ class Whitelist(db.Model):
             'id': self.id,
             'phone': self.phone,
             'description': self.description,
+            'type': self.type,
             'del_flag': self.del_flag,
             'revision': self.revision,
             'create_by': self.create_by,

+ 11 - 9
src/core/callcenter/data_handler.py

@@ -19,7 +19,7 @@ class DataHandleServer:
             "service_category": service_category,
             "user_id":user_id,
             "user_name": user_name,
-            'status': 0
+            'status': 1 if category==0 and service_category == 1 else 0  # 如果通话类型啥呼入并且走到ai 是接通状态 否则默认是未接通
         }
         call_record = CallRecord()
         self.app.logger.info(f"创建通话记录: {call_info}")
@@ -37,8 +37,11 @@ class DataHandleServer:
 
     @with_app_context
     def update_record(self, session_id, **kwargs):
+        self.app.logger.info(f"update_record::session_id:{session_id}")
         call_record = CallRecord.query.filter(CallRecord.session_id == session_id).first()
-
+        if not call_record:
+            self.app.logger.info("update_record::call_recard is empty !!!")
+            return
         time_end = kwargs.get('time_end')
         user_id =  kwargs.get('user_id')
         user_name = kwargs.get('user_name')
@@ -46,17 +49,16 @@ class DataHandleServer:
             bot_record = BotRecords.query.filter(BotRecords.session == session_id).first()
             call_record.bussiness_type = bot_record.intent if bot_record else ''
         # 如果记录是转人工并且有客服接通把客服更新到转接字段
-        self.app.logger.debug(f"Received kwargs: {kwargs} user_id:{user_id},user_name:{user_name}")
-        # if call_record.service_category==2 and user_id:
-        #    call_record.transfer_user_id = user_id
-        #    call_record.transfer_user_name =user_name
-        #    kwargs.pop('user_id', None)
-        #    kwargs.pop('user_name', None)
+        self.app.logger.debug(f"Received kwargs: {kwargs} user_id:{user_id},user_name:{user_name}, call_record:{call_record}")
+        #如果记录已经有user_id不再更新 删除参数里面的user_id
+        if call_record.user_id and 'user_id' in kwargs:
+           kwargs.pop('user_id', None)
+           kwargs.pop('user_name', None)
         # 动态更新字段
         for key, value in kwargs.items():
             if hasattr(call_record, key):
                 setattr(call_record, key, value)
-        self.app.logger.info(f"更新通话记录: {kwargs}")
+        self.app.logger.info(f"更新通话记录: {kwargs}, {call_record.to_dict()}")
         db.session.commit()
 
     @with_app_context

+ 12 - 0
src/core/callcenter/enumeration.py

@@ -3,6 +3,18 @@
 
 from enum import Enum
 
+class WhiteTypeEnum(Enum):
+    DEFAULT = (0, "传统")
+    AI = (1, "AI")
+
+    def __init__(self, code=None, description=None):
+        self.code = code
+        self.description = description
+
+    @classmethod
+    def get_by_code(cls, code):
+        return next((member for member in cls if member.code == code), None)
+
 
 class DelayActionEnum(Enum):
     CALL_TIMEOUT_HANGUP = ('CALL_TIMEOUT_HANGUP', "超时挂机")

+ 49 - 35
src/core/callcenter/esl/client.py

@@ -27,7 +27,7 @@ import src.core.callcenter.esl.utils.esl_event_util as EslEventUtil
 import src.core.callcenter.esl.handler as event_handler
 from src.core.callcenter.esl.constant.sip_header_constant import sipHeaderHoldMusic, profile1, profile2, sipHeaderCallId
 from src.core.callcenter.enumeration import CallCause, DeviceType, DelayActionEnum, HangupDir, CallType, NextType, \
-    Direction, CdrType, BizErrorCode
+    Direction, CdrType, BizErrorCode, WhiteTypeEnum
 from src.core.callcenter.esl.handler.default_esl_event_handler import DefaultEslEventHandler
 from src.core.callcenter.snowflake import Snowflake
 from src.core.datasource import SERVE_HOST
@@ -184,7 +184,7 @@ class InboundClient:
 
             self.cache.add_call_info(call_info)
             self.hangup_call(call_id, device_id, CallCause.CALL_TIMEOUT)
-            self.dataHandleServer.update_record(call_id, status= 0)
+            # self.dataHandleServer.update_record(call_id, status= 0)
 
     def exec_when_play_timeout(self, call_id):
         call_info = self.cache.get_call_info(call_id)
@@ -213,7 +213,7 @@ class InboundClient:
             next_command = NextCommand(device_id = device_id, next_type=NextType.NEXT_HANGUP.code)
             call_info.next_commands = [next_command]
             self.cache.add_call_info(call_info)
-            self.dataHandleServer.update_record(call_id, status= 0)
+            # self.dataHandleServer.update_record(call_id, status= 0)
             self.logger.info("waitingTimeOut 开始播放结束音乐 callId:%s customerDeviceId:%s playFile:%s", call_id,
                              device_id, WaitingHangupMusicPath)
 
@@ -519,7 +519,7 @@ class OutboundClient:
                 if con.connected():
                     info = con.getInfo()
 
-                    # self.logger.info(json.loads(info.serialize('json')))
+                    self.server.logger.info(json.loads(info.serialize('json')))
                     event_name = info.getHeader("Event-Name")
                     self.server.logger.info('Event-Name: %s', event_name)
                     device_id = info.getHeader("unique-id")
@@ -532,37 +532,36 @@ class OutboundClient:
                     kwargs['variable_sip_h_P-LIBRA-CallId'] = call_id
                     kwargs['variable_sip_h_P-LIBRA-DeviceId'] = device_id
 
-                    _bucket_call_type = 2
+                    bucket_call_type = 2
                     destination = None
                     service_category = 0
                     bucket = self.server.get_bucket(call_id)
                     whitelist = self.server.get_whitelist()
-                    self.server.logger.info('call incoming call_id=%s, device_id=%s, bucket=%s', call_id, device_id, bucket.name)
-                    self.server.logger.info('call incoming caller_number=%s, whitelist=%s', caller_number, json.dumps(whitelist))
-
-                    if self.in_whitelist(caller_number, whitelist):
-                        # 检查白名单
-                        _bucket_call_type = 0
-                        self.answer(con, call_id, device_id)
-                        self.build_call_info(CallType.INCOMING_AGENT_CALL.code, call_id, device_id, new_device_id, destination=None, bucket_type=_bucket_call_type, **kwargs)
-                        self.server.agent.acd_service.transfer_to_agent(call_id, device_id)
-                    elif bucket and bucket.name == 'AI':
-                        #转到ai机器人
-                        _bucket_call_type = 1
-                        service_category = 1
-                        destination = self.server.agent.register(**kwargs)
-                        self.server.logger.info("device_id=%s, destination=%s, new_device_id=%s" % (device_id, destination, new_device_id))
-                        self.build_call_info(CallType.INCOMING_BOT_CALL.code, call_id, device_id, new_device_id, str(destination), bucket_type=_bucket_call_type, **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)
+                    in_whitelist_type = self.in_whitelist(caller_number, whitelist)
+                    user_name = None
+                    self.server.logger.info('call incoming call_id=%s, caller_number=%s, device_id=%s, new_device_id=%s, in_whitelist=%s, bucket=%s', call_id, caller_number, device_id, new_device_id, in_whitelist_type, bucket.name)
+                    # 检查白名单
+                    if in_whitelist_type:
+                        if WhiteTypeEnum.AI == in_whitelist_type:
+                            bucket_call_type = 0
+                            service_category = 1
+                            destination = self.bridge_ai(con, bucket_call_type, call_id, device_id, new_device_id, **kwargs)
+                            user_name = f"机器人{destination}"
+                        else:
+                            bucket_call_type = 0
+                            self.transfer_custom(con, bucket_call_type, call_id, device_id, new_device_id, **kwargs)
                     else:
-                        # 传统服务
-                        self.answer(con, call_id, device_id)
-                        self.build_call_info(CallType.INCOMING_AGENT_CALL.code, call_id, device_id, new_device_id, destination=None, bucket_type=_bucket_call_type,  **kwargs)
-                        self.server.agent.acd_service.transfer_to_agent(call_id, device_id)
-
-                    registry.CALL_INCOMING_REQUESTS.labels(f"{_bucket_call_type}").inc()
-                    self.server.dataHandleServer.create_record(call_id, caller_number, _bucket_call_type, service_category=service_category, user_id=destination if _bucket_call_type == 1 else None , user_name=  f"机器人{destination}" if _bucket_call_type ==1 else None)
+                        # 自然分流
+                        if bucket and bucket.name == 'AI':
+                            bucket_call_type = 1
+                            service_category = 1
+                            destination = self.bridge_ai(con, bucket_call_type, call_id,  device_id, new_device_id, **kwargs)
+                            user_name = f"机器人{destination}"
+                        else:
+                            self.transfer_custom(con, bucket_call_type, call_id, device_id, new_device_id, **kwargs)
+
+                    registry.CALL_INCOMING_REQUESTS.labels(f"{bucket_call_type}").inc()
+                    self.server.dataHandleServer.create_record(call_id, caller_number, bucket_call_type, service_category=service_category, user_id=destination if user_name else None, user_name= user_name)
 
                     try:
                         con.disconnect()
@@ -581,11 +580,26 @@ class OutboundClient:
                     # Ignore the error if socket is already closed
                     pass
 
+        def transfer_custom(self, con, bucket_call_type, call_id, device_id, new_device_id, **kwargs):
+            self.answer(con, call_id, device_id)
+            self.build_call_info(CallType.INCOMING_AGENT_CALL.code, call_id, device_id, new_device_id, destination=None, bucket_type=bucket_call_type, **kwargs)
+            self.server.agent.acd_service.transfer_to_agent(call_id, device_id)
+
+        def bridge_ai(self, con, bucket_call_type, call_id, device_id, new_device_id, **kwargs):
+            destination = self.server.agent.register(**kwargs)
+            self.server.logger.info("call_id=%s, device_id=%s, destination=%s, new_device_id=%s" % (call_id, device_id, destination, new_device_id))
+            self.build_call_info(CallType.INCOMING_BOT_CALL.code, call_id, device_id, new_device_id, str(destination), bucket_type=bucket_call_type, **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)
+            return destination
+
         def in_whitelist(self, caller_number, whitelist):
             for x in whitelist:
-                if caller_number in x or caller_number in x:
-                    return True
-            return False
+                phone, _type = x
+                if caller_number in phone or phone in caller_number:
+                    return WhiteTypeEnum.get_by_code(_type)
+
+            return None
 
         def answer(self, con, call_id, device_id, timeouts=30):
             con.execute("answer", "", device_id)
@@ -641,7 +655,7 @@ class OutboundClient:
             self.cache_job_scheduler.add_job(self.update_cache_job, run_date=datetime.now())
             self.cache_job_scheduler.add_job(self.update_cache_job, 'interval', seconds=60, max_instances=1, name='cache_job_daemon')
             self.cache_job_scheduler.add_job(self.update_whitelist, run_date=datetime.now())
-            self.cache_job_scheduler.add_job(self.update_whitelist, 'interval', seconds=600, max_instances=1,name='cache_job_whiteList')
+            self.cache_job_scheduler.add_job(self.update_whitelist, 'interval', seconds=60, max_instances=1,name='cache_job_whiteList')
             self.cache_job_scheduler.start()
 
         def update_cache_job(self):
@@ -653,7 +667,7 @@ class OutboundClient:
         def update_whitelist(self):
             with self.app.app_context():
                 phones = Whitelist.query.filter_by(del_flag=0).all()
-                self.whitelist = [phone.phone for phone in phones]
+                self.whitelist = [(phone.phone, phone.type) for phone in phones]
                 self.logger.info("Whitelist updated: %s", self.whitelist)
 
         def get_whitelist(self):

+ 4 - 4
src/core/callcenter/esl/handler/channel_answer_handler.py

@@ -23,14 +23,14 @@ class ChannelAnswerHandler(EslEventHandler):
 
     def handle(self, address, event, coreUUID):
         call_id = EslEventUtil.getCallId(event)
+        device_id = EslEventUtil.getDeviceId(event)
         call_info = self.cache.get_call_info(call_id)
-        self.logger.info("answer call_id:%s, call_info:%s", call_id, call_info)
+        self.logger.info("answer call_id:%s, device_id:%s, call_info:%s", call_id, device_id, call_info)
         if not call_info:
             self.logger.info("answer call_info is null, call_id:%s", call_id)
             return
 
         registry.CALL_ANSWER_REQUESTS.labels(f"{call_info.bucket_type}").inc()
-        device_id = EslEventUtil.getDeviceId(event)
         device_info = call_info.device_info_map.get(device_id)
         if not device_info:
             self.logger.info("answer device_info is null, call_id:%s, call_info:%s", call_id, call_info)
@@ -50,13 +50,13 @@ class ChannelAnswerHandler(EslEventHandler):
 
         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)
-        self.logger.info("ChannelAnswerHandler call_id:%s, device_id:%s, device_type:%s, next_command:%s"%(call_id, device_id, device_type, next_command))
+        self.logger.info("answer call_id:%s, device_id:%s, device_type:%s, next_command:%s"%(call_id, device_id, device_type, next_command))
         if not next_command:
             self.cache.add_call_info(call_info)
             return
 
         call_info.next_commands.remove(next_command)
-        self.logger.info("ChannelAnswerHandler call_info.answer_time::%s,time:%s", call_info.answer_time, EslEventUtil.getEventDateTimestamp(event))
+        self.logger.info("answer call_id:%s, device_id:%s, call_info.answer_time::%s,time:%s", call_id, device_id, call_info.answer_time, EslEventUtil.getEventDateTimestamp(event))
 
         if NextType.NEXT_CALL_OTHER.code == next_command.next_type:
             self.call_other(call_info, device_info, event)

+ 21 - 11
src/core/callcenter/esl/handler/channel_hangup_handler.py

@@ -34,20 +34,20 @@ class ChannelHangupHandler(EslEventHandler):
         # self.logger.info(json.loads(event.serialize('json')))
         try:
             call_id = self.get_call_id(event)
-            self.logger.info('call_id is %s', call_id)
+            device_id = EslEventUtil.getDeviceId(event)
+            self.logger.info('hangup call_id:%s, device_id:%s', call_id, device_id)
             if not call_id:
                 self.release(event)
                 self.logger.info("call_id is null, event=%s", json.loads(event.serialize('json')))
                 return
 
             call_info = self.cache.get_call_info(call_id)
-            self.logger.info('call_info is %s', call_info)
+            self.logger.info('hangup call_id:%s, device_id:%s, call_info: %s', call_id, device_id, call_info)
             if not call_info:
                 self.release(event)
                 self.logger.info("call_info:%s is null", call_id)
                 return
 
-            device_id = EslEventUtil.getDeviceId(event)
             device_info = call_info.device_info_map.get(device_id)
             if not device_info:
                 self.release(event)
@@ -58,7 +58,7 @@ class ChannelHangupHandler(EslEventHandler):
                 self.release(event)
 
             count = len(call_info.device_list)
-            self.logger.info('ChannelHangupHandler, call_id=%s, device_id=%s, count=%s'% (call_id, device_id, count))
+            self.logger.info('hangup, call_id=%s, device_id=%s, count=%s'% (call_id, device_id, count))
             try:
                 call_info.device_list.remove(device_id)
             except:
@@ -152,20 +152,30 @@ class ChannelHangupHandler(EslEventHandler):
         records = []
         sip_status = []
         hangup_cause = []
+        agent_name = ''
         for value in call_info.device_info_map.values():
             records.append(value.record) if value.record else None
             sip_status.append(value.sip_status)
             hangup_cause.append(value.hangup_cause)
-        self.logger.info("get_call_info_record: %s", records)
-        threading.Thread(target=self._update_record_in_thread, args=(call_info.call_id, list(set(records)), ",".join(sip_status), ",".join(hangup_cause),call_info.answer_count)).start()
+            if value.device_type == DeviceType.AGENT.code :
+                agent_name = value.agent_key
+        self.logger.info("get_call_info_record: %s,agent_name:%s", records, agent_name)
+        threading.Thread(target=self._update_record_in_thread, args=(call_info.call_id, list(set(records)), ",".join(sip_status), ",".join(hangup_cause), agent_name)).start()
 
-    def _update_record_in_thread(self, call_id, records, sip_status, hangup_cause, answer_count):
+    def update_name(self,call_id, agent_name):
+        try:
+            agent = self.dataHandleServer.get_user_name(agent_name)
+            return agent
+        except Exception as e:
+            self.logger.error("update_name error: %s", str(e))
+    def _update_record_in_thread(self, call_id, records, sip_status, hangup_cause, agent_name):
         """用于在独立线程中执行 update_record"""
         try:
-            status = 0 if answer_count <= 0 else 1
+            agent = self.update_name(call_id, agent_name)
+            # status = 0 if answer_count <= 0 else 1
             if len(records) == 0:
-                self.logger.warning("没有录音文件,直接更新记录: call_id=%s, sip_status=%s, hangup_cause=%s", call_id, sip_status, hangup_cause)
-                self.dataHandleServer.update_record(call_id, time_end=datetime.now(), sip_status=sip_status, sip_hangup_cause=hangup_cause, status=status)
+                self.logger.warning("没有录音文件,直接更新记录: call_id=%s, sip_status=%s, hangup_cause=%s, agent_name=%s", call_id, sip_status, hangup_cause,agent_name)
+                self.dataHandleServer.update_record(call_id, time_end=datetime.now(), sip_status=sip_status, sip_hangup_cause=hangup_cause,user_id=agent.user_id if agent else None, user_name=agent.agent_name if agent else None)
                 return
             merge_record = self.merge_audio_files(records) if len(records) > 1 else records[0]
             # try:
@@ -175,7 +185,7 @@ class ChannelHangupHandler(EslEventHandler):
             # except Exception as chmod_error:
             #     self.logger.error("设置文件权限失败: %s, error: %s", merge_record, str(chmod_error))
 
-            self.dataHandleServer.update_record(call_id, time_end=datetime.now(), url=merge_record, sip_status=sip_status, sip_hangup_cause=hangup_cause, status=status)
+            self.dataHandleServer.update_record(call_id, time_end=datetime.now(), url=merge_record, sip_status=sip_status, sip_hangup_cause=hangup_cause,user_id=agent.user_id if agent else None, user_name=agent.agent_name if agent else None)
             self.logger.info("更新录音记录完成: call_id=%s", call_id)
         except Exception as e:
             self.logger.error("更新录音记录失败: call_id=%s, error=%s", call_id, str(e))

+ 3 - 1
src/core/callcenter/esl/handler/dtmf_handler.py

@@ -1,5 +1,6 @@
 #!/usr/bin/env python3
 # encoding:utf-8
+import json
 
 from src.core.callcenter.esl.annotation import EslEventName
 from src.core.callcenter.esl.constant.event_names import DTMF
@@ -13,4 +14,5 @@ class DTMFHandler(EslEventHandler):
         super().__init__(inbound_client, bot_agent)
 
     def handle(self, address, event, coreUUID):
-        pass
+        self.logger.info("DTMFHandler, event=%s", json.loads(event.serialize('json')))
+

+ 1 - 0
src/core/callcenter/registry.py

@@ -42,5 +42,6 @@ BOT_CREATE_ACCOUNT_LATENCY = Histogram('bot_create_account_latency',  '创建虚
 
 FLASK_ACTIVE_THREADS = Gauge('flask_active_threads', 'Number of active threads')
 BOT_AGENT_LIVES = Gauge('bot_agent_lives', 'Number of active agents')
+MANUAL_AGENT_LIVES = Gauge('manual_agent_lives', 'Number of active agents')
 
 

+ 16 - 16
src/core/callcenter/ws.py

@@ -37,22 +37,22 @@ Thread(target=listen_to_redis).start()
 
 # def common_down_data(user_id, data, namespace='/ws/cs-im'):
 #     emit('common_down_data', data, room=user_id, namespace=namespace)
-def common_down_data(user_id, data, namespace='/ws/cs-im'):
-    """推送 common_down_data 消息"""
-    # 发布消息到 Redis 频道
-    redis_handler.publish('socket_channel', json.dumps({
-        'event': 'common_down_data',
-        'user_id': user_id,
-        'data': data
-    }))
-def common_down_cmd(user_id, data):
-    """推送 common_down_cmd 消息"""
-    # 发布消息到 Redis 频道
-    redis_handler.publish('socket_channel', json.dumps({
-        'event': 'common_down_cmd',
-        'user_id': user_id,
-        'data': data
-    }))
+# def common_down_data(user_id, data, namespace='/ws/cs-im'):
+#     """推送 common_down_data 消息"""
+#     # 发布消息到 Redis 频道
+#     redis_handler.publish('socket_channel', json.dumps({
+#         'event': 'common_down_data',
+#         'user_id': user_id,
+#         'data': data
+#     }))
+# def common_down_cmd(user_id, data):
+#     """推送 common_down_cmd 消息"""
+#     # 发布消息到 Redis 频道
+#     redis_handler.publish('socket_channel', json.dumps({
+#         'event': 'common_down_cmd',
+#         'user_id': user_id,
+#         'data': data
+#     }))
 
 # def common_down_cmd(user_id, data):
 #     emit('common_down_cmd', data, room=user_id)