|
@@ -1,6 +1,6 @@
|
|
|
#!/usr/bin/env python3
|
|
|
# encoding:utf-8
|
|
|
-
|
|
|
+import subprocess
|
|
|
import json
|
|
|
import sys
|
|
|
import os
|
|
@@ -96,7 +96,7 @@ class ChannelHangupHandler(EslEventHandler):
|
|
|
bucket_type = call_info.bucket_type if call_info.bucket_type else "EMPTY"
|
|
|
registry.CALL_HANGUP_REQUESTS.labels(f"{bucket_type}", f"{device_info.sip_status}").inc()
|
|
|
|
|
|
- self.logger.info('ChannelHangupHandler, device_id=%s, hangup_reason=%s, device_type=%s, cdr_type=%s, end_time=%s, skip_hangup_all=%s, answer_count=%s, hangup_count=%s' % (device_id, hangup_reason, device_info.device_type, device_info.cdr_type, call_info.end_time, skip_hangup_all, call_info.answer_count, call_info.hangup_count))
|
|
|
+ self.logger.info('ChannelHangupHandler, call_id=%s, device_id=%s, hangup_reason=%s, device_type=%s, cdr_type=%s, end_time=%s, skip_hangup_all=%s, answer_count=%s, hangup_count=%s' % (call_id, device_id, hangup_reason, device_info.device_type, device_info.cdr_type, call_info.end_time, skip_hangup_all, call_info.answer_count, call_info.hangup_count))
|
|
|
# 如果是转人工
|
|
|
# if 'transferToAgent' == hangup_reason and DeviceType.ROBOT.code == device_info.device_type:
|
|
|
# call_info.answer_flag = AnswerFlag.TRANSFER_TO_AGENT.code
|
|
@@ -129,10 +129,12 @@ class ChannelHangupHandler(EslEventHandler):
|
|
|
|
|
|
# 全部挂机以后推送挂机状态
|
|
|
# self.logger.info('yushanghui::call_info.device_list %s', call_info.device_list)
|
|
|
- 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:
|
|
|
self.get_call_info_record(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)
|
|
@@ -140,6 +142,15 @@ class ChannelHangupHandler(EslEventHandler):
|
|
|
except:
|
|
|
traceback.print_exc()
|
|
|
|
|
|
+ def hook_serial_warn(self, call_info:CallInfo):
|
|
|
+ no_answer_cnt = self.cache.get_serial_no_answer_cnt(call_info)
|
|
|
+ if no_answer_cnt >=5:
|
|
|
+ self.logger.warn('WARING::serial_no_answer_cnt greater than 5')
|
|
|
+
|
|
|
+ no_speed_hangup_cnt = self.cache.get_serial_speed_hangup_cnt(call_info)
|
|
|
+ if no_speed_hangup_cnt >=3:
|
|
|
+ self.logger.warn('WARING::get_serial_speed_hangup_cnt greater than 3')
|
|
|
+
|
|
|
def get_call_id(self, event):
|
|
|
call_id = EslEventUtil.getCallId(event)
|
|
|
device_id = EslEventUtil.getDeviceId(event)
|
|
@@ -155,14 +166,19 @@ class ChannelHangupHandler(EslEventHandler):
|
|
|
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 if value.sip_status else 'EMPTY')
|
|
|
- hangup_cause.append(value.hangup_cause if value.hangup_cause else 'EMPTY')
|
|
|
- if value.device_type == DeviceType.AGENT.code :
|
|
|
- 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)
|
|
|
- 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()
|
|
|
+ try:
|
|
|
+ self.logger.info("get_call_info_record: %s", call_info)
|
|
|
+ for value in call_info.device_info_map.values():
|
|
|
+ records.append(value.record) if value.record else None
|
|
|
+ sip_status.append(value.sip_status if value.sip_status else 'EMPTY')
|
|
|
+ hangup_cause.append(value.hangup_cause if value.hangup_cause else 'EMPTY')
|
|
|
+ if value.device_type == DeviceType.AGENT.code :
|
|
|
+ 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)
|
|
|
+ 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()
|
|
|
+ except Exception as e:
|
|
|
+ self.logger.info("get_call_info_record:exception %s", e)
|
|
|
+ traceback.print_exc()
|
|
|
|
|
|
def update_name(self,call_id, agent_name):
|
|
|
try:
|
|
@@ -180,26 +196,29 @@ class ChannelHangupHandler(EslEventHandler):
|
|
|
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:
|
|
|
- # self._ensure_path_permissions(merge_record)
|
|
|
- # os.chmod(merge_record, 0o755) # 设置文件权限为 755
|
|
|
- # self.logger.info("成功设置文件权限: %s -> 755", merge_record)
|
|
|
- # 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,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)
|
|
|
+ # 计算录音时长
|
|
|
+ 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))
|
|
|
except Exception as e:
|
|
|
self.logger.error("更新录音记录失败: call_id=%s, error=%s", call_id, str(e))
|
|
|
|
|
|
- def _ensure_path_permissions(self, file_path):
|
|
|
- """确保文件及其父级目录的权限为 755"""
|
|
|
- current_path = os.path.abspath(file_path)
|
|
|
- self.logger.info("_ensure_path_permissions::%s", current_path)
|
|
|
- # while current_path != "/": # 遍历到根目录为止
|
|
|
- # if os.path.exists(current_path):
|
|
|
- # os.chmod(current_path, 0o755) # 设置当前路径权限为 755
|
|
|
- # current_path = os.path.dirname(current_path) # 获取父目录路径
|
|
|
+ def get_audio_duration(self, audio_path):
|
|
|
+ """使用 ffmpeg 计算音频时长"""
|
|
|
+ try:
|
|
|
+ result = subprocess.run(
|
|
|
+ ["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "json", audio_path],
|
|
|
+ stdout=subprocess.PIPE,
|
|
|
+ stderr=subprocess.PIPE,
|
|
|
+ text=True
|
|
|
+ )
|
|
|
+ info = json.loads(result.stdout)
|
|
|
+ duration = float(info["format"]["duration"])
|
|
|
+ return duration
|
|
|
+ except Exception as e:
|
|
|
+ print(f"获取音频时长失败: {e}")
|
|
|
+ return None
|
|
|
+
|
|
|
def merge_audio_files(self,audio_files):
|
|
|
if not audio_files:
|
|
|
self.logger.info("没有可合并的音频文件")
|