|
@@ -8,7 +8,9 @@ import traceback
|
|
from pydub import AudioSegment
|
|
from pydub import AudioSegment
|
|
import threading
|
|
import threading
|
|
from src.core.callcenter.acd import AcdService
|
|
from src.core.callcenter.acd import AcdService
|
|
|
|
+from src.core.callcenter.agent import AgentStateService
|
|
from src.core.callcenter.call import CallService
|
|
from src.core.callcenter.call import CallService
|
|
|
|
+from src.core.callcenter.constant import SAAS_ID
|
|
from src.core.callcenter.enumeration import CallType, DeviceType, AnswerFlag, NextType, CdrType, HangupDir, \
|
|
from src.core.callcenter.enumeration import CallType, DeviceType, AnswerFlag, NextType, CdrType, HangupDir, \
|
|
CallCause,AgentServiceState,AgentScene, WorkStatus
|
|
CallCause,AgentServiceState,AgentScene, WorkStatus
|
|
from src.core.callcenter.esl.annotation import EslEventName
|
|
from src.core.callcenter.esl.annotation import EslEventName
|
|
@@ -29,6 +31,8 @@ class ChannelHangupHandler(EslEventHandler):
|
|
self.call_service = CallService(inbound_client,inbound_client.app)
|
|
self.call_service = CallService(inbound_client,inbound_client.app)
|
|
self.push_handler = PushHandler(inbound_client.logger)
|
|
self.push_handler = PushHandler(inbound_client.logger)
|
|
self.dataHandleServer=DataHandleServer(inbound_client.app)
|
|
self.dataHandleServer=DataHandleServer(inbound_client.app)
|
|
|
|
+ self.agent_state_service = AgentStateService(inbound_client.app)
|
|
|
|
+
|
|
|
|
|
|
def handle(self, address, event, coreUUID):
|
|
def handle(self, address, event, coreUUID):
|
|
# self.logger.info(json.loads(event.serialize('json')))
|
|
# self.logger.info(json.loads(event.serialize('json')))
|
|
@@ -129,15 +133,18 @@ class ChannelHangupHandler(EslEventHandler):
|
|
|
|
|
|
# 全部挂机以后推送挂机状态
|
|
# 全部挂机以后推送挂机状态
|
|
# self.logger.info('yushanghui::call_info.device_list %s', call_info.device_list)
|
|
# self.logger.info('yushanghui::call_info.device_list %s', call_info.device_list)
|
|
|
|
+ # 判断挂机方向 && 更新缓存
|
|
|
|
+ self.hangup_dir(call_info, device_info, cause)
|
|
if call_info.hangup_count >= call_info.answer_count:
|
|
if call_info.hangup_count >= call_info.answer_count:
|
|
- # if len(call_info.device_list) == 0:
|
|
|
|
|
|
+ # if len(call_info.device_list) == 0:
|
|
self.get_call_info_record(call_info)
|
|
self.get_call_info_record(call_info)
|
|
|
|
|
|
# 连续报警判断
|
|
# 连续报警判断
|
|
self.hook_serial_warn(call_info)
|
|
self.hook_serial_warn(call_info)
|
|
- # 判断挂机方向 && 更新缓存
|
|
|
|
- self.hangup_dir(call_info, device_info, cause)
|
|
|
|
self.cache.add_call_info(call_info, persistent=True)
|
|
self.cache.add_call_info(call_info, persistent=True)
|
|
|
|
+ if device_info.device_type != DeviceType.ROBOT.code:
|
|
|
|
+ # 释放坐席接听锁
|
|
|
|
+ self.agent_state_service.handle_release_agent_lock(call_info.agent_key, SAAS_ID)
|
|
|
|
|
|
except:
|
|
except:
|
|
traceback.print_exc()
|
|
traceback.print_exc()
|
|
@@ -146,10 +153,12 @@ class ChannelHangupHandler(EslEventHandler):
|
|
no_answer_cnt = self.cache.get_serial_no_answer_cnt(call_info)
|
|
no_answer_cnt = self.cache.get_serial_no_answer_cnt(call_info)
|
|
if no_answer_cnt >=5:
|
|
if no_answer_cnt >=5:
|
|
self.logger.warn('WARING::serial_no_answer_cnt greater than 5')
|
|
self.logger.warn('WARING::serial_no_answer_cnt greater than 5')
|
|
|
|
+ self.dataHandleServer.create_warning_record(0, '连续5个未接')
|
|
|
|
|
|
no_speed_hangup_cnt = self.cache.get_serial_speed_hangup_cnt(call_info)
|
|
no_speed_hangup_cnt = self.cache.get_serial_speed_hangup_cnt(call_info)
|
|
if no_speed_hangup_cnt >=3:
|
|
if no_speed_hangup_cnt >=3:
|
|
self.logger.warn('WARING::get_serial_speed_hangup_cnt greater than 3')
|
|
self.logger.warn('WARING::get_serial_speed_hangup_cnt greater than 3')
|
|
|
|
+ self.dataHandleServer.create_warning_record(2, '连续3个5s内挂断')
|
|
|
|
|
|
def get_call_id(self, event):
|
|
def get_call_id(self, event):
|
|
call_id = EslEventUtil.getCallId(event)
|
|
call_id = EslEventUtil.getCallId(event)
|
|
@@ -175,7 +184,7 @@ class ChannelHangupHandler(EslEventHandler):
|
|
if value.device_type == DeviceType.AGENT.code :
|
|
if value.device_type == DeviceType.AGENT.code :
|
|
agent_name = value.agent_key
|
|
agent_name = value.agent_key
|
|
self.logger.info("get_call_info_record: %s,agent_name:%s, sip_status:%s, hangup_cause:%s", records, agent_name, sip_status, hangup_cause)
|
|
self.logger.info("get_call_info_record: %s,agent_name:%s, sip_status:%s, hangup_cause:%s", records, agent_name, sip_status, hangup_cause)
|
|
- threading.Thread(target=self._update_record_in_thread, args=(call_info.call_id, list(dict.fromkeys(records)), ",".join(sip_status), ",".join(hangup_cause), agent_name)).start()
|
|
|
|
|
|
+ threading.Thread(target=self._update_record_in_thread, args=(call_info, list(dict.fromkeys(records)), ",".join(sip_status), ",".join(hangup_cause), agent_name)).start()
|
|
except Exception as e:
|
|
except Exception as e:
|
|
self.logger.info("get_call_info_record:exception %s", e)
|
|
self.logger.info("get_call_info_record:exception %s", e)
|
|
traceback.print_exc()
|
|
traceback.print_exc()
|
|
@@ -186,20 +195,22 @@ class ChannelHangupHandler(EslEventHandler):
|
|
return agent
|
|
return agent
|
|
except Exception as e:
|
|
except Exception as e:
|
|
self.logger.error("update_name error: %s", str(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):
|
|
|
|
|
|
+ def _update_record_in_thread(self, call_info, records, sip_status, hangup_cause, agent_name):
|
|
"""用于在独立线程中执行 update_record"""
|
|
"""用于在独立线程中执行 update_record"""
|
|
try:
|
|
try:
|
|
|
|
+ call_id = call_info.call_id
|
|
|
|
+ hangup_dir = call_info.hangup_dir
|
|
agent = self.update_name(call_id, agent_name)
|
|
agent = self.update_name(call_id, agent_name)
|
|
# status = 0 if answer_count <= 0 else 1
|
|
# status = 0 if answer_count <= 0 else 1
|
|
if len(records) == 0:
|
|
if len(records) == 0:
|
|
- 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)
|
|
|
|
|
|
+ self.logger.warning("没有录音文件,直接更新记录: call_id=%s, sip_status=%s, hangup_cause=%s, agent_name=%s, hangup_dir=%s", call_id, sip_status, hangup_cause,agent_name, hangup_dir)
|
|
|
|
+ self.dataHandleServer.update_record(call_id, time_end=datetime.now(), sip_status=sip_status, sip_hangup_cause=hangup_cause, hangup_dir=hangup_dir, user_id=agent.user_id if agent else None, user_name=agent.agent_name if agent else None)
|
|
return
|
|
return
|
|
merge_record = self.merge_audio_files(records) if len(records) > 1 else records[0]
|
|
merge_record = self.merge_audio_files(records) if len(records) > 1 else records[0]
|
|
# 计算录音时长
|
|
# 计算录音时长
|
|
- duration = self.get_audio_duration(merge_record)
|
|
|
|
- self.dataHandleServer.update_record(call_id, times=int(duration), 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, duration=%s", call_id, int(duration))
|
|
|
|
|
|
+ duration = self.get_audio_duration(merge_record) or 0
|
|
|
|
+ self.dataHandleServer.update_record(call_id, times=int(duration), time_end=datetime.now(), url=merge_record, sip_status=sip_status, sip_hangup_cause=hangup_cause, hangup_dir=hangup_dir, user_id=agent.user_id if agent else None, user_name=agent.agent_name if agent else None)
|
|
|
|
+ self.logger.info("更新录音记录完成: call_id=%s, duration=%s, hangup_dir=%s", call_id, int(duration), hangup_dir)
|
|
except Exception as e:
|
|
except Exception as e:
|
|
self.logger.error("更新录音记录失败: call_id=%s, error=%s", call_id, str(e))
|
|
self.logger.error("更新录音记录失败: call_id=%s, error=%s", call_id, str(e))
|
|
|
|
|
|
@@ -217,13 +228,17 @@ class ChannelHangupHandler(EslEventHandler):
|
|
return duration
|
|
return duration
|
|
except Exception as e:
|
|
except Exception as e:
|
|
print(f"获取音频时长失败: {e}")
|
|
print(f"获取音频时长失败: {e}")
|
|
- return None
|
|
|
|
|
|
+ return 0
|
|
|
|
|
|
def merge_audio_files(self,audio_files):
|
|
def merge_audio_files(self,audio_files):
|
|
if not audio_files:
|
|
if not audio_files:
|
|
self.logger.info("没有可合并的音频文件")
|
|
self.logger.info("没有可合并的音频文件")
|
|
return
|
|
return
|
|
- # 初始化第一个音频文件
|
|
|
|
|
|
+ if not os.path.exists(audio_files[0]):
|
|
|
|
+ self.logger.info("没有可合并的音频文件")
|
|
|
|
+ return
|
|
|
|
+
|
|
|
|
+ # 初始化第一个音频文件
|
|
combined = AudioSegment.from_file(audio_files[0])
|
|
combined = AudioSegment.from_file(audio_files[0])
|
|
# 循环添加其余的音频文件
|
|
# 循环添加其余的音频文件
|
|
for audio_file in audio_files[1:]:
|
|
for audio_file in audio_files[1:]:
|
|
@@ -269,6 +284,8 @@ class ChannelHangupHandler(EslEventHandler):
|
|
call_info.hangup_dir = HangupDir.HOST_HANGUP.code
|
|
call_info.hangup_dir = HangupDir.HOST_HANGUP.code
|
|
elif DeviceType.CUSTOMER.code == device_info.device_type:
|
|
elif DeviceType.CUSTOMER.code == device_info.device_type:
|
|
call_info.hangup_dir = HangupDir.CUSTOMER_HANGUP.code
|
|
call_info.hangup_dir = HangupDir.CUSTOMER_HANGUP.code
|
|
|
|
+ # elif DeviceType.ROBOT.code == device_info.device_type:
|
|
|
|
+ # call_info.hangup_dir = HangupDir.ROBOT_HANGUP.code
|
|
|
|
|
|
# if not call_info.end_time:
|
|
# if not call_info.end_time:
|
|
# call_info.end_time = device_info.end_time
|
|
# call_info.end_time = device_info.end_time
|