|
@@ -0,0 +1,225 @@
|
|
|
|
+#!/usr/bin/env python3
|
|
|
|
+# encoding:utf-8
|
|
|
|
+
|
|
|
|
+from urllib.parse import urlparse
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class AgentInfo:
|
|
|
|
+ def __init__(self, sass_id=None, agent_number=None, realm=None, sip_server=None, server_num=None,
|
|
|
|
+ call_id=None, device_id=None, real_device_id=None, line_id=None, fs_user=None, domain=None,
|
|
|
|
+ service_time=0, max_ready_time=0, total_ready_time=0, ready_times=0, not_ready_times=0,
|
|
|
|
+ total_after_time=0, max_talk_time=0, total_talk_time=0, total_ring_times=0, total_answer_times=0):
|
|
|
|
+ self.sass_id = sass_id
|
|
|
|
+ self.agent_number = agent_number
|
|
|
|
+ self.realm = realm
|
|
|
|
+ self.sip_server = sip_server
|
|
|
|
+ self.server_num = server_num
|
|
|
|
+ self.call_id = call_id
|
|
|
|
+ self.device_id = device_id
|
|
|
|
+ # 机器人外呼时真实fs
|
|
|
|
+ self.real_device_id = real_device_id
|
|
|
|
+ self.line_id = line_id
|
|
|
|
+ self.fs_user = fs_user
|
|
|
|
+ self.domain = domain
|
|
|
|
+ # 坐席最近的一次服务时间,电话则是振铃时间(秒)
|
|
|
|
+ self.service_time = service_time
|
|
|
|
+ # 最大空闲时长
|
|
|
|
+ self.max_ready_time = max_ready_time
|
|
|
|
+ # 累计空闲
|
|
|
|
+ self.total_ready_time = total_ready_time
|
|
|
|
+ # 空闲次数
|
|
|
|
+ self.ready_times = ready_times
|
|
|
|
+ # 忙碌次数
|
|
|
|
+ self.not_ready_times = not_ready_times
|
|
|
|
+ # 累计话后时间长
|
|
|
|
+ self.total_after_time = total_after_time
|
|
|
|
+ # 最大通话时长
|
|
|
|
+ self.max_talk_time = max_talk_time
|
|
|
|
+ # 当日累计通话时长
|
|
|
|
+ self.total_talk_time = total_talk_time
|
|
|
|
+ # 振铃次数
|
|
|
|
+ self.total_ring_times = total_ring_times
|
|
|
|
+ # 当日累计接听次数
|
|
|
|
+ self.total_answer_times = total_answer_times
|
|
|
|
+
|
|
|
|
+ def get_realm(self):
|
|
|
|
+ """
|
|
|
|
+ Get the realm by extracting the host from the SIP server if available,
|
|
|
|
+ otherwise return the current realm.
|
|
|
|
+ """
|
|
|
|
+ try:
|
|
|
|
+ if self.sip_server:
|
|
|
|
+ parsed_uri = urlparse(self.sip_server)
|
|
|
|
+ return parsed_uri.hostname if parsed_uri.hostname else self.realm
|
|
|
|
+ except Exception as ex:
|
|
|
|
+ print(f"Error parsing SIP server URI: {ex}")
|
|
|
|
+ return self.realm
|
|
|
|
+
|
|
|
|
+ def is_fs_user(self):
|
|
|
|
+ """
|
|
|
|
+ Determine if the agent is a FreeSWITCH user.
|
|
|
|
+ Default is True if fs_user is None or True.
|
|
|
|
+ """
|
|
|
|
+ return self.fs_user is None or self.fs_user is True
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class CallInfo:
|
|
|
|
+ def __init__(self, core_uuid=None, call_id=None, conference=None, company_id=None, group_id=None,
|
|
|
|
+ hidden_customer=0, caller_display=None, caller=None, called_display=None, called=None,
|
|
|
|
+ number_location=None, agent_key=None, agent_name=None, login_type=None, ivr_id=None, task_id=None,
|
|
|
|
+ media_host=None, cti_host=None, client_host=None, record=None, record2=None, record_time=None,
|
|
|
|
+ call_time=None, call_type=None, direction=None, answer_flag=None, wait_time=None, answer_count=0,
|
|
|
|
+ hangup_dir=None, sdk_hangup=0, hangup_code=None, answer_time=None, end_time=None, talk_time=None,
|
|
|
|
+ frist_queue_time=None, queue_start_time=None, queue_end_time=None, overflow_count=0,
|
|
|
|
+ uuid1=None, uuid2=None, cdr_notify_url=None, queue_level=None, device_list=[], device_info_map={},
|
|
|
|
+ follow_data={}, process_data={}, next_commands=[], call_details=[]):
|
|
|
|
+ self.core_uuid = core_uuid # 通话唯一标识
|
|
|
|
+ self.call_id = call_id # 通话唯一标识
|
|
|
|
+ self.conference = conference # 会议号
|
|
|
|
+ self.company_id = company_id # 企业id
|
|
|
|
+ self.group_id = group_id # 所在技能组id
|
|
|
|
+ self.hidden_customer = hidden_customer # 隐藏客户号码(0:不隐藏;1:隐藏)
|
|
|
|
+ self.caller_display = caller_display # 主叫显号
|
|
|
|
+ self.caller = caller # 主叫
|
|
|
|
+ self.called_display = called_display # 被叫显号
|
|
|
|
+ self.called = called # 被叫
|
|
|
|
+ self.number_location = number_location # 号码归属地
|
|
|
|
+ self.agent_key = agent_key # 坐席
|
|
|
|
+ self.agent_name = agent_name # 坐席名称
|
|
|
|
+ self.login_type = login_type # 坐席登录类型
|
|
|
|
+ self.ivr_id = ivr_id # ivr
|
|
|
|
+ self.task_id = task_id # 任务ID
|
|
|
|
+ self.media_host = media_host # 媒体
|
|
|
|
+ self.cti_host = cti_host # 服务地址
|
|
|
|
+ self.client_host = client_host # 客户服务地址
|
|
|
|
+ self.record = record # 录音地址
|
|
|
|
+ self.record2 = record2 # 第三方存储地址
|
|
|
|
+ self.record_time = record_time # 录音开始时间
|
|
|
|
+ self.call_time = call_time # 呼叫开始时间
|
|
|
|
+ self.call_type = call_type # 呼叫类型 (Enum CallType)
|
|
|
|
+ self.direction = direction # 呼叫方向 (Enum Direction)
|
|
|
|
+ self.answer_flag = answer_flag # 通话标识
|
|
|
|
+ self.wait_time = wait_time # 等待时长
|
|
|
|
+ self.answer_count = answer_count # 应答设备数
|
|
|
|
+ self.hangup_dir = hangup_dir # 挂机方向 (1主叫挂机, 2:被叫挂机, 3:平台挂机)
|
|
|
|
+ self.sdk_hangup = sdk_hangup # sdk挂机标志
|
|
|
|
+ self.hangup_code = hangup_code # 挂机原因
|
|
|
|
+ self.answer_time = answer_time # 接听时间
|
|
|
|
+ self.end_time = end_time # 最后一侧电话挂机时间
|
|
|
|
+ self.talk_time = talk_time # 通话时长(秒)
|
|
|
|
+ self.frist_queue_time = frist_queue_time # 第一次进队列时间
|
|
|
|
+ self.queue_start_time = queue_start_time # 进入技能组时间
|
|
|
|
+ self.queue_end_time = queue_end_time # 出技能组时间
|
|
|
|
+ self.overflow_count = overflow_count # 溢出次数
|
|
|
|
+ self.uuid1 = uuid1 # uuid1
|
|
|
|
+ self.uuid2 = uuid2 # uuid2
|
|
|
|
+ self.cdr_notify_url = cdr_notify_url # 话单通知地址
|
|
|
|
+ self.queue_level = queue_level # 排队等级,默认是进队列时间
|
|
|
|
+ self.device_list = device_list # 当前通话的设备
|
|
|
|
+ self.device_info_map = device_info_map, # K-V
|
|
|
|
+ self.follow_data = follow_data # 呼叫随路数据(作为落单数据)
|
|
|
|
+ self.process_data = process_data # 模块流程间数据
|
|
|
|
+ self.next_commands = next_commands # 执行下一步命令
|
|
|
|
+ self.call_details = call_details # 电话流程
|
|
|
|
+
|
|
|
|
+ # def __repr__(self):
|
|
|
|
+ # return (f"CallInfo(core_uuid={self.core_uuid}, call_id={self.call_id}, conference={self.conference}, "
|
|
|
|
+ # f"company_id={self.company_id}, group_id={self.group_id}, hidden_customer={self.hidden_customer}, "
|
|
|
|
+ # f"caller_display={self.caller_display}, caller={self.caller}, called_display={self.called_display}, "
|
|
|
|
+ # f"called={self.called}, number_location={self.number_location}, agent_key={self.agent_key}, "
|
|
|
|
+ # f"agent_name={self.agent_name}, login_type={self.login_type}, ivr_id={self.ivr_id}, task_id={self.task_id}, "
|
|
|
|
+ # f"media_host={self.media_host}, cti_host={self.cti_host}, client_host={self.client_host}, record={self.record}, "
|
|
|
|
+ # f"record2={self.record2}, record_time={self.record_time}, call_time={self.call_time}, call_type={self.call_type}, "
|
|
|
|
+ # f"direction={self.direction}, answer_flag={self.answer_flag}, wait_time={self.wait_time}, "
|
|
|
|
+ # f"answer_count={self.answer_count}, hangup_dir={self.hangup_dir}, sdk_hangup={self.sdk_hangup}, "
|
|
|
|
+ # f"hangup_code={self.hangup_code}, answer_time={self.answer_time}, end_time={self.end_time}, "
|
|
|
|
+ # f"talk_time={self.talk_time}, frist_queue_time={self.frist_queue_time}, queue_start_time={self.queue_start_time}, "
|
|
|
|
+ # f"queue_end_time={self.queue_end_time}, overflow_count={self.overflow_count}, uuid1={self.uuid1}, uuid2={self.uuid2}, "
|
|
|
|
+ # f"cdr_notify_url={self.cdr_notify_url}, queue_level={self.queue_level})")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class DeviceInfo:
|
|
|
|
+ def __init__(self, call_id=None, conference=None, device_id=None, agent_key=None, agent_name=None, device_type=None,
|
|
|
|
+ cdr_type=None, from_agent=None, caller=None, called=None, display=None, called_location=None,
|
|
|
|
+ caller_location=None, call_time=None, ring_start_time=None, ring_end_time=None, answer_time=None,
|
|
|
|
+ bridge_time=None, end_time=None, talk_time=None, sip_protocol=None, channel_name=None,
|
|
|
|
+ hangup_cause=None, ring_cause=None, sip_status=None, record=None, record_time=None,
|
|
|
|
+ record_start_time=None, state=None):
|
|
|
|
+ self.call_id = call_id # 通话唯一标识
|
|
|
|
+ self.conference = conference # 会议模式
|
|
|
|
+ self.device_id = device_id # 设备id
|
|
|
|
+ self.agent_key = agent_key # 坐席
|
|
|
|
+ self.agent_name = agent_name # 坐席
|
|
|
|
+ self.device_type = device_type # 1:坐席,2:客户,3:外线
|
|
|
|
+ self.cdr_type = cdr_type # 1:呼入,2:外呼,3:内呼,4:转接,5:咨询,6:监听,7:强插,8:耳语
|
|
|
|
+ self.from_agent = from_agent # 咨询或转接来源
|
|
|
|
+ self.caller = caller # 主叫
|
|
|
|
+ self.called = called # 被叫
|
|
|
|
+ self.display = display # 显号
|
|
|
|
+ self.called_location = called_location # 被叫归属地
|
|
|
|
+ self.caller_location = caller_location # 被叫归属地
|
|
|
|
+ self.call_time = call_time # 呼叫开始时间
|
|
|
|
+ self.ring_start_time = ring_start_time # 振铃开始时间
|
|
|
|
+ self.ring_end_time = ring_end_time # 振铃结束时间
|
|
|
|
+ self.answer_time = answer_time # 接通时间
|
|
|
|
+ self.bridge_time = bridge_time # 桥接时间
|
|
|
|
+ self.end_time = end_time # 结束时间
|
|
|
|
+ self.talk_time = talk_time # 通话时长
|
|
|
|
+ self.sip_protocol = sip_protocol # 信令协议(tcp/udp)
|
|
|
|
+ self.channel_name = channel_name # 呼叫地址
|
|
|
|
+ self.hangup_cause = hangup_cause # 挂机原因
|
|
|
|
+ self.ring_cause = ring_cause # 回铃音识别
|
|
|
|
+ self.sip_status = sip_status # sip状态
|
|
|
|
+ self.record = record # 录音地址
|
|
|
|
+ self.record_time = record_time # 录音时长
|
|
|
|
+ self.record_start_time = record_start_time # 录音开始时间
|
|
|
|
+ self.state = state # 当前设备状态
|
|
|
|
+
|
|
|
|
+ # def __repr__(self):
|
|
|
|
+ # return (f"DeviceInfo(call_id={self.call_id}, conference={self.conference}, device_id={self.device_id}, "
|
|
|
|
+ # f"agent_key={self.agent_key}, agent_name={self.agent_name}, device_type={self.device_type}, "
|
|
|
|
+ # f"cdr_type={self.cdr_type}, from_agent={self.from_agent}, caller={self.caller}, called={self.called}, "
|
|
|
|
+ # f"display={self.display}, called_location={self.called_location}, caller_location={self.caller_location}, "
|
|
|
|
+ # f"call_time={self.call_time}, ring_start_time={self.ring_start_time}, ring_end_time={self.ring_end_time}, "
|
|
|
|
+ # f"answer_time={self.answer_time}, bridge_time={self.bridge_time}, end_time={self.end_time}, "
|
|
|
|
+ # f"talk_time={self.talk_time}, sip_protocol={self.sip_protocol}, channel_name={self.channel_name}, "
|
|
|
|
+ # f"hangup_cause={self.hangup_cause}, ring_cause={self.ring_cause}, sip_status={self.sip_status}, "
|
|
|
|
+ # f"record={self.record}, record_time={self.record_time}, record_start_time={self.record_start_time}, "
|
|
|
|
+ # f"state={self.state})")
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class NextCommand:
|
|
|
|
+
|
|
|
|
+ def __init__(self, deviceId, nextType, nextValue):
|
|
|
|
+ # 记录执行设备
|
|
|
|
+ self.deviceId = deviceId
|
|
|
|
+ # 下一步执行命令
|
|
|
|
+ self.nextType = nextType
|
|
|
|
+ # 执行参数
|
|
|
|
+ self.nextValue = nextValue
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class CallDetail:
|
|
|
|
+ def __init__(self, id=None, cts=None, start_time=None, end_time=None, call_id=None,
|
|
|
|
+ detail_index=None, transfer_type=None, transfer_id=None, reason=None,
|
|
|
|
+ month=None, ext1=None, ext2=None, status=None):
|
|
|
|
+ self.id = id # PK
|
|
|
|
+ self.cts = cts # 创建时间
|
|
|
|
+ self.start_time = start_time # 开始时间
|
|
|
|
+ self.end_time = end_time # 结束时间
|
|
|
|
+ self.call_id = call_id # 通话ID
|
|
|
|
+ self.detail_index = detail_index # 顺序
|
|
|
|
+ self.transfer_type = transfer_type # 类型
|
|
|
|
+ self.transfer_id = transfer_id # 转接ID
|
|
|
|
+ self.reason = reason # 出队列原因
|
|
|
|
+ self.month = month # 月份
|
|
|
|
+ self.ext1 = ext1 # 扩展字段1
|
|
|
|
+ self.ext2 = ext2 # 扩展字段2
|
|
|
|
+ self.status = status # 状态
|
|
|
|
+
|
|
|
|
+ # def __repr__(self):
|
|
|
|
+ # return (f"CallDetail(id={self.id}, cts={self.cts}, start_time={self.start_time}, "
|
|
|
|
+ # f"end_time={self.end_time}, call_id={self.call_id}, detail_index={self.detail_index}, "
|
|
|
|
+ # f"transfer_type={self.transfer_type}, transfer_id={self.transfer_id}, reason={self.reason}, "
|
|
|
|
+ # f"month={self.month}, ext1={self.ext1}, ext2={self.ext2}, status={self.status})")
|
|
|
|
+
|