Browse Source

Merge branch 'dev_20241205' of ssh://gitlab.fuxicarbon.com:1111/client_service/voice-gateway-service into dev_20241205

余尚辉 3 months ago
parent
commit
72b0b3ca70

+ 3 - 0
src/core/callcenter/acd.py

@@ -61,6 +61,9 @@ class AcdService:
         all_task = []
         for k, v in self.holdsQueue.items():
             self.logger.info("AcdService tryTransferAgent start, queue.k:%s, queue.v:%s", k, v.qsize())
+            if v.qsize() <= 0:
+                self.holdsQueue.pop(k, None)
+                continue
             all_task.append(self.pool.submit(self.holds_one_queue, k, v))
         wait(all_task, timeout=6, return_when=ALL_COMPLETED)
 

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

@@ -295,9 +295,9 @@ class AgentOperService:
         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)
+        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
@@ -837,7 +837,7 @@ class AgentStateService:
     def idle_hash(self, saas_id, agent_id, phone_num, service_id):
         key = self._key(saas_id, service_id)
         state_data = AgentStateData()
-        self.logger.info("idle_hash, key=%s, saas_id=%s, phone_num=%s"%(key, saas_id, phone_num))
+        # self.logger.info("idle_hash, key=%s, saas_id=%s, phone_num=%s", key, saas_id, phone_num)
         cache_agent_map = self.get_cache_agent_map(saas_id, service_id)
         if cache_agent_map and phone_num in cache_agent_map:
             state_data = cache_agent_map[phone_num]
@@ -847,6 +847,7 @@ class AgentStateService:
         self.redis_handler.redis.hset(key, phone_num, state_data.to_json_string())
         self.redis_handler.redis.expire(key, self._get_expire_time())
         # self.update_report_state(saas_id, service_id)
+        self.logger.info("idle_hash, key=%s, saas_id=%s, phone_num=%s, state_data=%s"%(key, saas_id, phone_num, state_data))
 
     def busy_hash(self, saas_id, agent_id, phone_num, service_id):
         cache_agent_map = self.get_cache_agent_map(saas_id, service_id)

+ 3 - 1
src/core/callcenter/cache.py

@@ -6,13 +6,15 @@ import sys
 import time
 import uuid
 from datetime import datetime
+
+from src.core import singleton_keys
 from src.core.callcenter.constant import *
 from src.core.callcenter.api import AgentInfo, CallInfo, RouteGateway
 from src.core.callcenter.dao import Agent, Phone
 from src.core.callcenter.data_handler import DataHandleServer
 from src.core.datasource import RedisHandler
 
-
+@singleton_keys
 class Cache:
     def __init__(self, app):
         self.cacheDay = 7

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

@@ -27,7 +27,6 @@ class CallService:
         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):
         call_id = 'C' + str(self.snowflake.next_id())
@@ -61,17 +60,6 @@ class CallService:
 
         self.client.make_call_new(context)
         self.do_after_manual_call(call_info, agent.agent_number)
-        # # 创建一条通话记录
-        # self.dataHandleServer.create_record({
-        #     "session_id": call_id,
-        #     "time_begin": datetime.now(),
-        #     "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
 
     def do_after_manual_call(self, call_info: CallInfo, agent_id):

+ 9 - 6
src/core/callcenter/config.py

@@ -19,9 +19,11 @@ class BaseConfig(object):
     SQLALCHEMY_DATABASE_URI = f"{DIALCT}+{DRITVER}://{USERNAME}:{PASSWORD}@{HOST}:{PORT}/{DBNAME}?charset=utf8"
     SQLALCHEMY_TRACK_MODIFICATIONS = False   # Disable track modifications
     SQLALCHEMY_ECHO = False  # Optional: Log SQL queries
+
+
 dictConfig({
         "version": 1,
-        "disable_existing_loggers": False,  # 不覆盖默认配置
+        "disable_existing_loggers": True,  # 不覆盖默认配置
         "formatters": {  # 日志输出样式
             "default": {
                 "format": "%(asctime)s - %(module)s.%(lineno)d - %(levelname)s - %(threadName)s: %(message)s"
@@ -34,13 +36,14 @@ dictConfig({
                 "formatter": "default",
             },
             "log_file": {
-                "class": "logging.handlers.RotatingFileHandler",
-                "level": "INFO",
+                "class": "logging.handlers.TimedRotatingFileHandler",  # 按时间切分日志
+                "level": "DEBUG",
                 "formatter": "default",   # 日志输出样式对应formatters
                 "filename": "./logs/flask.log",  # 指定log文件目录
-                "maxBytes": 20*1024*1024,   # 文件最大20M
-                "backupCount": 10,          # 最多10个文件
-                "encoding": "utf8",         # 文件编码
+                "when": "midnight",        # 按天切分,午夜时分创建新文件
+                "interval": 1,             # 间隔1天
+                "backupCount": 10,         # 保留10天的日志文件
+                "encoding": "utf8",        # 文件编码
             },
 
         },

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

@@ -558,18 +558,6 @@ class OutboundClient:
                     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, destination=destination)
 
-                    # destination = "user/1001"
-                    # msg = ESL.ESLevent("sendmsg", uuid)
-                    # msg.addHeader("call-command", "execute")
-                    # msg.addHeader("execute-app-name", "bridge")
-                    # msg.addHeader("execute-app-arg", destination)
-                    # # 发送消息以执行 bridge 操作
-                    # con.sendEvent(msg)
-                    # self.logger.info(f"Call {uuid} is bridged to {destination}")
-
-                    # con.execute("answer", "", uuid)
-
-                    # con.execute("transfer", "1001 XML default", uuid)
                     try:
                         con.disconnect()
                         self.server.logger.info("connection disconnected !!!")
@@ -579,6 +567,13 @@ class OutboundClient:
                     self.server.logger.info("Failed to connect to FreeSWITCH")
             except:
                 traceback.print_exc()
+            finally:
+                try:
+                    if self.request.fileno() != -1:
+                        self.request.close()
+                except OSError:
+                    # Ignore the error if socket is already closed
+                    pass
 
         def build_call_info(self, call_id, device_id, new_device_id, destination, bucket_type, **kwargs):
             caller = kwargs.get('Channel-Caller-ID-Number')

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

@@ -31,10 +31,10 @@ class ChannelAnswerHandler(EslEventHandler):
         device_id = EslEventUtil.getDeviceId(event)
         device_info = call_info.device_info_map.get(device_id)
         if CallType.AGENT_CALL.code == call_info.call_type and device_info.device_type == DeviceType.CUSTOMER.code:
-            self.record(event, device_id)
+            device_info.record = self.record(event, device_id)
 
         if CallType.BOT_CALL.code == call_info.call_type and device_info.device_type == DeviceType.ROBOT.code:
-            self.record(event, device_id)
+            device_info.record = self.record(event, device_id)
             call_info.answer_flag = AnswerFlag.ROBOT_ANSWER.code
             registry.CALL_BOT_ANSWER_REQUESTS.labels(f"{call_info.bucket_type}").inc()
 
@@ -61,13 +61,6 @@ class ChannelAnswerHandler(EslEventHandler):
         else:
             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)
 
 
@@ -93,7 +86,7 @@ class ChannelAnswerHandler(EslEventHandler):
         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,
+                                called=called, display=call.called_display, caller=call.called_display, record=record_url,
                                 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
@@ -110,7 +103,7 @@ class ChannelAnswerHandler(EslEventHandler):
         self.logger.info("开始桥接电话: callId:%s, caller:%s, called:%s, device1:%s, device2:%s"% (call.call_id,
                          call.caller, call.called, next_command.device_id, next_command.next_value))
         self.logger.info("liuwei::debugger::answer, 33333")
-        self.record(event, device_id=device.device_id)
+        device.record = self.record(event, device_id=device.device_id)
         device1 = call.device_info_map.get(next_command.device_id)
         device2 = call.device_info_map.get(next_command.next_value)
 
@@ -127,10 +120,11 @@ class ChannelAnswerHandler(EslEventHandler):
         from_device_id = next_command.device_id
         device_id = EslEventUtil.getDeviceId(event)
         call.answer_flag = AnswerFlag.AGENT_ANSWER.code
-        if CallType.BOT_CALL.code == call.call_type:
-            registry.CALL_BOT_TRANSFER_REQUESTS.labels(f"{call.bucket_type}").inc()
+        registry.CALL_BOT_TRANSFER_REQUESTS.labels(f"{call.bucket_type}").inc()
+
+        device_info = call.device_info_map.get(device_id)
+        device_info.record = self.record(event, device_id)
 
-        self.record(event, device_id)
         call.next_commands.append(NextCommand(call.device_list[0], NextType.NEXT_TRANSFER_SUCCESS.code, device_id))
         self.logger.info("转接电话中 callId:%s, from:%s, to:%s "% (call.call_id, device_id, next_command.next_value))
         self.inbound_client.transfer_call(device_id, next_command.next_value)
@@ -166,9 +160,6 @@ class ChannelAnswerHandler(EslEventHandler):
                 _record_url = self.start_recording(device_id, get_record_file_name(call_id, CallStage.AGENT), call)
         else:
             _record_url = self.start_recording(device_id, get_record_file_name(call_id, CallStage.ALL), call)
-        device.record = _record_url
-        self.logger.info("luyincall:%s, device:%s" % (call, device))
-        self.cache.add_call_info(call)
         return _record_url
 
     def start_recording(self, device_id, file_name, call: CallInfo):

+ 2 - 21
src/core/callcenter/esl/handler/channel_bridge_handler.py

@@ -1,34 +1,15 @@
 #!/usr/bin/env python3
 # encoding:utf-8
 from src.core.callcenter.esl.annotation import EslEventName
-from src.core.callcenter.enumeration import  DeviceType, AgentServiceState,WorkStatus,AgentScene
 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.push import PushHandler
-from src.core.callcenter.data_handler import *
+
 
 @EslEventName(CHANNEL_BRIDGE)
 class ChannelBridgeHandler(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_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)
+        pass

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

@@ -1,10 +1,8 @@
 #!/usr/bin/env python3
 # encoding:utf-8
 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_ORIGINATE
 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_ORIGINATE)
@@ -16,11 +14,3 @@ class ChannelOriginateHandler(EslEventHandler):
 
     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)
-        # 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)

+ 0 - 9
src/core/callcenter/esl/handler/channel_progress_media_handler.py

@@ -2,10 +2,8 @@
 # encoding:utf-8
 
 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.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)
@@ -17,10 +15,3 @@ class ChannelProgressMediaHandler(EslEventHandler):
 
     def handle(self, address, event, coreUUID):
         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)

+ 0 - 8
src/core/callcenter/esl/handler/detected_tone_handler.py

@@ -3,10 +3,8 @@
 # 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 DETECTED_TONE
 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)
@@ -18,9 +16,3 @@ class DetectedToneHandler(EslEventHandler):
 
     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 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)

+ 2 - 9
src/core/callcenter/esl/handler/playback_start_handler.py

@@ -1,12 +1,11 @@
 #!/usr/bin/env python3
 # encoding:utf-8
+from src.core.callcenter.data_handler import *
 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):
@@ -18,9 +17,3 @@ class PlaybackStartHandler(EslEventHandler):
 
     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)

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

@@ -507,8 +507,8 @@ class BotAgent:
         ep_cfg.uaConfig.maxCalls = 20
         ep_cfg.uaConfig.maxAccounts = 20
         ep_cfg.medConfig.noVad = True
-        ep_cfg.logConfig.level = 4
-        ep_cfg.logConfig.consoleLevel = 4
+        ep_cfg.logConfig.level = 3
+        ep_cfg.logConfig.consoleLevel = 3
         self.ep.libCreate()
         self.ep.libInit(ep_cfg)