|
@@ -15,7 +15,7 @@ from src.core.datasource import SIP_SERVER
|
|
from src.core.voip.constant import *
|
|
from src.core.voip.constant import *
|
|
|
|
|
|
import requests
|
|
import requests
|
|
-from src.core.callcenter.api import BotChatRequest, ChatResponse,ChatMessage
|
|
|
|
|
|
+from src.core.callcenter.api import BotChatRequest,ChatMessage
|
|
|
|
|
|
|
|
|
|
calls = {}
|
|
calls = {}
|
|
@@ -58,14 +58,10 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
self.asr = asr
|
|
self.asr = asr
|
|
|
|
|
|
self.user_asr_texts = []
|
|
self.user_asr_texts = []
|
|
- self.cur_player_file = None
|
|
|
|
-
|
|
|
|
|
|
|
|
self.play_start_time = None # 记录播放开始时间
|
|
self.play_start_time = None # 记录播放开始时间
|
|
self.play_complete_flag = False # 播放完成标志
|
|
self.play_complete_flag = False # 播放完成标志
|
|
|
|
|
|
-
|
|
|
|
- #self.dtmf_type = None #记录按键类型 1为长按键类型
|
|
|
|
def onFrameRequested(self, frame):
|
|
def onFrameRequested(self, frame):
|
|
print("Request audio frame:", frame)
|
|
print("Request audio frame:", frame)
|
|
|
|
|
|
@@ -81,27 +77,27 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
if asr_text and not play_complete:
|
|
if asr_text and not play_complete:
|
|
self.user_asr_texts.append(asr_text)
|
|
self.user_asr_texts.append(asr_text)
|
|
if asr_text and play_complete:
|
|
if asr_text and play_complete:
|
|
- self.cur_player_file = None
|
|
|
|
|
|
+ self.call.cur_player_file = None
|
|
self.user_asr_texts.append(asr_text)
|
|
self.user_asr_texts.append(asr_text)
|
|
user_asr_text = asr_text if len(self.user_asr_texts) == 1 else '###'.join(self.user_asr_texts)
|
|
user_asr_text = asr_text if len(self.user_asr_texts) == 1 else '###'.join(self.user_asr_texts)
|
|
self.user_asr_texts.clear()
|
|
self.user_asr_texts.clear()
|
|
- self.call.chat("2",user_asr_text)
|
|
|
|
|
|
+ self.call.chat(user_asr_text)
|
|
|
|
|
|
#超时处理
|
|
#超时处理
|
|
current_time = time.time()
|
|
current_time = time.time()
|
|
- # print(f'onFrameReceived:self.wait_time={self.call.wait_time}, self.call.digit ={self.call.digit},asr_text:{asr_text},play_complete:{play_complete}')
|
|
|
|
- if self.call.wait_time and self.call.wait_time != "0" and play_complete and not asr_text and self.call.digit == '':
|
|
|
|
|
|
+ print(f'onFrameReceived:self.wait_time={self.call.wait_time}, self.call.digit ={self.call.digit},asr_text:{asr_text},play_complete:{play_complete},self.call.inputType:{self.call.inputType}')
|
|
|
|
+ if self.call.wait_time and self.call.wait_time != "0" and play_complete and not asr_text and not self.call.digit :
|
|
self.wait_time_check(current_time, self.call.wait_time)
|
|
self.wait_time_check(current_time, self.call.wait_time)
|
|
|
|
|
|
# 如果为超长类型的按键服务 超过30s未输入完成执行超时操作
|
|
# 如果为超长类型的按键服务 超过30s未输入完成执行超时操作
|
|
- if self.call.dtmf_type=='1' and play_complete and not asr_text:
|
|
|
|
- self.wait_time_check(current_time, 30)
|
|
|
|
|
|
+ if self.call.inputType == '1' and play_complete and not asr_text:
|
|
|
|
+ self.wait_time_check(current_time, 15)
|
|
|
|
|
|
message_queue_size = self.call.message_queue.qsize()
|
|
message_queue_size = self.call.message_queue.qsize()
|
|
- if (message_queue_size > 0 and not self.cur_player_file) or (message_queue_size > 0 and play_complete):
|
|
|
|
|
|
+ if (message_queue_size > 0 and not self.call.cur_player_file) or (message_queue_size > 0 and play_complete):
|
|
print('onFrameReceived:message_queue_size=', message_queue_size, 'play_complete=', play_complete, asr_text)
|
|
print('onFrameReceived:message_queue_size=', message_queue_size, 'play_complete=', play_complete, asr_text)
|
|
- self.cur_player_file, self.call.wait_time, self.call.dtmf_type, self.call.action = self.get_player_file()
|
|
|
|
- self.call.send_bot_speaker(self.cur_player_file)
|
|
|
|
|
|
+ self.call.cur_player_file, self.call.wait_time, self.call.inputType,self.call.action, self.call.nodeId = self.get_player_file()
|
|
|
|
+ self.call.send_bot_speaker(self.call.cur_player_file)
|
|
|
|
|
|
# 重置播放完成标志和超时计时器,确保新的播放从头开始计时
|
|
# 重置播放完成标志和超时计时器,确保新的播放从头开始计时
|
|
self.play_complete_flag = False # 重置播放完成标志
|
|
self.play_complete_flag = False # 重置播放完成标志
|
|
@@ -111,12 +107,11 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
#播放完毕执行的动作
|
|
#播放完毕执行的动作
|
|
self.call.say_end_action(self.call.action)
|
|
self.call.say_end_action(self.call.action)
|
|
except:
|
|
except:
|
|
- traceback.print_exc()
|
|
|
|
pass
|
|
pass
|
|
|
|
|
|
def is_play_complete(self):
|
|
def is_play_complete(self):
|
|
- if self.cur_player_file:
|
|
|
|
- player_id = murmur3_32(self.cur_player_file)
|
|
|
|
|
|
+ if self.call.cur_player_file:
|
|
|
|
+ player_id = murmur3_32(self.call.cur_player_file)
|
|
return self.call.player_complete_dict.get(player_id)
|
|
return self.call.player_complete_dict.get(player_id)
|
|
|
|
|
|
def get_asr_text(self):
|
|
def get_asr_text(self):
|
|
@@ -130,12 +125,13 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
def get_player_file(self):
|
|
def get_player_file(self):
|
|
try:
|
|
try:
|
|
message = self.call.message_queue.get(block=False)
|
|
message = self.call.message_queue.get(block=False)
|
|
- player_file = [item.voice_url for item in message.contents if item.content_type == 'voice']
|
|
|
|
- wait_time = message.wait_time
|
|
|
|
- dtmf_type = message.dtmf_type
|
|
|
|
- action = message.action
|
|
|
|
- print('get_player_file:', player_file, wait_time,dtmf_type, action)
|
|
|
|
- return player_file, wait_time, dtmf_type, action
|
|
|
|
|
|
+ player_file = [item.voiceUrl for item in message.contents if item.contentType == 'voice']
|
|
|
|
+ # self.call.wait_time = message.waitTime
|
|
|
|
+ # self.call.inputType = message.inputType
|
|
|
|
+ # self.call.action = message.action
|
|
|
|
+ # self.call.nodeId = message.nodeId
|
|
|
|
+ print('get_player_file:', player_file,message.waitTime, message.inputType, message.action, message.nodeId)
|
|
|
|
+ return player_file, message.waitTime, message.inputType, message.action, message.nodeId
|
|
except Exception as e:
|
|
except Exception as e:
|
|
traceback.print_exc()
|
|
traceback.print_exc()
|
|
|
|
|
|
@@ -150,10 +146,14 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
# 检查超时时间是否已到
|
|
# 检查超时时间是否已到
|
|
if current_time - self.play_start_time > int(wait_time):
|
|
if current_time - self.play_start_time > int(wait_time):
|
|
self.play_complete_flag = False # 重置标志位,避免重复超时
|
|
self.play_complete_flag = False # 重置标志位,避免重复超时
|
|
- if wait_time == 30:
|
|
|
|
- self.call.chat("7", self.call.digit)
|
|
|
|
|
|
+ if wait_time == 15:
|
|
|
|
+ print("DTMF:超时",self.call.digit)
|
|
|
|
+ # self.call.chat(f"DTMF({self.call.digit})DTMF","1")
|
|
|
|
+ self.call.user_asr_text_queue.put(f"DTMF({self.call.digit})DTMF")
|
|
else:
|
|
else:
|
|
- self.call.chat("6", "ASR408error")
|
|
|
|
|
|
+ # self.call.chat("6", "ASR408error")
|
|
|
|
+ print("DTMF:超时6shehehehehehhehhehehe")
|
|
|
|
+ self.call.user_asr_text_queue.put("ASR408error")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -215,9 +215,12 @@ class MyCall(pj.Call):
|
|
self.player_complete_dict = {}
|
|
self.player_complete_dict = {}
|
|
|
|
|
|
self.wait_time = None
|
|
self.wait_time = None
|
|
- self.dtmf_type = None #记录按键类型 1为长按键类型
|
|
|
|
|
|
+ self.inputType = None #记录按键类型 1为长按键类型
|
|
self.digit = '' # 存储长按键内容
|
|
self.digit = '' # 存储长按键内容
|
|
self.action = None
|
|
self.action = None
|
|
|
|
+ self.nodeId= 'start'
|
|
|
|
+
|
|
|
|
+ self.cur_player_file = None #当前播放的文件
|
|
|
|
|
|
from src.core.voip.asr import TestSt
|
|
from src.core.voip.asr import TestSt
|
|
self.asr = TestSt(call_id, message_receiver=self.on_receiver_asr_result) # 创建ASR实例
|
|
self.asr = TestSt(call_id, message_receiver=self.on_receiver_asr_result) # 创建ASR实例
|
|
@@ -228,18 +231,16 @@ class MyCall(pj.Call):
|
|
digit = prm.digit
|
|
digit = prm.digit
|
|
# 假设为超长类型按键 把用户输入的按键进行拼接 如果为# 则把用户输入所有按键放入队列并发送文本机器人
|
|
# 假设为超长类型按键 把用户输入的按键进行拼接 如果为# 则把用户输入所有按键放入队列并发送文本机器人
|
|
# 如果为非正常按键服务 输入以后直接发送文本机器人
|
|
# 如果为非正常按键服务 输入以后直接发送文本机器人
|
|
- if self.dtmf_type == '1':
|
|
|
|
|
|
+ if self.inputType == '1':
|
|
if digit != '#':
|
|
if digit != '#':
|
|
self.digit += digit
|
|
self.digit += digit
|
|
print(f"Received DTMF digit12: {self.digit}")
|
|
print(f"Received DTMF digit12: {self.digit}")
|
|
else:
|
|
else:
|
|
self.user_asr_text_queue.put(f"DTMF({self.digit})DTMF")
|
|
self.user_asr_text_queue.put(f"DTMF({self.digit})DTMF")
|
|
- self.chat('3', self.digit)
|
|
|
|
print(f"Received DTMF digit34: {self.digit}")
|
|
print(f"Received DTMF digit34: {self.digit}")
|
|
else:
|
|
else:
|
|
print(f"Received DTMF digit: {digit}")
|
|
print(f"Received DTMF digit: {digit}")
|
|
self.user_asr_text_queue.put(f"DTMF({digit})DTMF")
|
|
self.user_asr_text_queue.put(f"DTMF({digit})DTMF")
|
|
- # self.chat('3', digit)
|
|
|
|
|
|
|
|
def onCallState(self, prm):
|
|
def onCallState(self, prm):
|
|
call_info = self.getInfo()
|
|
call_info = self.getInfo()
|
|
@@ -312,38 +313,38 @@ class MyCall(pj.Call):
|
|
|
|
|
|
def bot_say_hello(self):
|
|
def bot_say_hello(self):
|
|
print('bot_say_hello, come in ')
|
|
print('bot_say_hello, come in ')
|
|
- self.chat('1', user_asr_text="SAY_HELLO")
|
|
|
|
- def chat(self,event_type, user_asr_text=None):
|
|
|
|
|
|
+ self.chat(user_asr_text="start")
|
|
|
|
+
|
|
|
|
+ def chat(self, user_asr_text=None):
|
|
# 调用文本机器人接口
|
|
# 调用文本机器人接口
|
|
- ToTextBotAgent(event_type,user_asr_text,self)
|
|
|
|
|
|
+ ToTextBotAgent(user_asr_text,self)
|
|
|
|
|
|
def say_end_action(self, action):
|
|
def say_end_action(self, action):
|
|
- print('handling_release', action.action_code)
|
|
|
|
- action_code = action.action_code
|
|
|
|
- if action_code == 'hang': # 挂断
|
|
|
|
- action_content = action.action_content
|
|
|
|
- print(f'todo 挂电话:{action_content}')
|
|
|
|
- elif action_code == 'transfer': # 转人工
|
|
|
|
|
|
+ print('handling_release', action.actionCode)
|
|
|
|
+ actionCode = action.actionCode
|
|
|
|
+ if actionCode == 'hang': # 挂断
|
|
|
|
+ actionContent = action.actionContent
|
|
|
|
+ print(f'todo 挂电话:{actionContent}')
|
|
|
|
+ elif actionCode == 'transfer': # 转人工
|
|
print('todo 转人工')
|
|
print('todo 转人工')
|
|
|
|
|
|
class ToTextBotAgent:
|
|
class ToTextBotAgent:
|
|
- def __init__(self, event_type, user_asr_text, call_agent):
|
|
|
|
|
|
+ def __init__(self, user_asr_text, call_agent):
|
|
if not user_asr_text:
|
|
if not user_asr_text:
|
|
print("ASR文本为空,终止执行。")
|
|
print("ASR文本为空,终止执行。")
|
|
return
|
|
return
|
|
|
|
|
|
self.call_agent = call_agent
|
|
self.call_agent = call_agent
|
|
self.request_data = BotChatRequest(
|
|
self.request_data = BotChatRequest(
|
|
- node_id="1",
|
|
|
|
- user_id="139311",
|
|
|
|
- session_id="1",
|
|
|
|
- record_id="2",
|
|
|
|
- task_id="ceshi",
|
|
|
|
- asr_text=user_asr_text
|
|
|
|
|
|
+ nodeId=self.call_agent.nodeId,
|
|
|
|
+ userId="139311",
|
|
|
|
+ sessionId="1",
|
|
|
|
+ recordId="2",
|
|
|
|
+ taskId="ceshi",
|
|
|
|
+ asrText=user_asr_text
|
|
)
|
|
)
|
|
# 发送请求并处理响应
|
|
# 发送请求并处理响应
|
|
- self.test_request(self.request_data,event_type)
|
|
|
|
-
|
|
|
|
|
|
+ self.test_request(self.request_data)
|
|
|
|
|
|
|
|
|
|
def to_quest(self, request: BotChatRequest):
|
|
def to_quest(self, request: BotChatRequest):
|
|
@@ -356,7 +357,9 @@ class ToTextBotAgent:
|
|
if response.status_code == 200:
|
|
if response.status_code == 200:
|
|
# 成功,解析响应JSON
|
|
# 成功,解析响应JSON
|
|
response_data = response.json()
|
|
response_data = response.json()
|
|
- return ChatResponse.from_json(json.dumps(response_data)) # 转换为JSON字符串并解析
|
|
|
|
|
|
+ # return ChatResponse.from_json(json.dumps(response_data)) # 转换为JSON字符串并解析
|
|
|
|
+ parsed_response = ChatMessage.from_json(response_data)
|
|
|
|
+ self.call_agent.message_queue.put(parsed_response)
|
|
else:
|
|
else:
|
|
# 错误处理
|
|
# 错误处理
|
|
print(f"请求失败,状态码: {response.status_code}, 响应内容: {response.text}")
|
|
print(f"请求失败,状态码: {response.status_code}, 响应内容: {response.text}")
|
|
@@ -366,64 +369,60 @@ class ToTextBotAgent:
|
|
return None
|
|
return None
|
|
|
|
|
|
# 模拟接口请求返回
|
|
# 模拟接口请求返回
|
|
- def test_request(self, params: BotChatRequest,event_type):
|
|
|
|
|
|
+ def test_request(self, params: BotChatRequest):
|
|
print("test_request::params=", params)
|
|
print("test_request::params=", params)
|
|
response_data = {
|
|
response_data = {
|
|
- "node_id": "1.0",
|
|
|
|
|
|
+ "nodeId": "1.0",
|
|
"contents": [],
|
|
"contents": [],
|
|
- "interruptable": False,
|
|
|
|
- "wait_time": "6",
|
|
|
|
|
|
+ "waitTime": "6",
|
|
"action": {
|
|
"action": {
|
|
- "action_code": "normal",
|
|
|
|
- "action_content": "正常通话"
|
|
|
|
|
|
+ "actionCode": "normal",
|
|
|
|
+ "actionContent": "正常通话"
|
|
},
|
|
},
|
|
- "talk_time_out": "",
|
|
|
|
- "dtmf_type": '0'
|
|
|
|
|
|
+ "inputType": "0"
|
|
}
|
|
}
|
|
|
|
|
|
- print("event_type:", event_type)
|
|
|
|
- if event_type == '1':
|
|
|
|
|
|
+ print("asrText:", params.asrText)
|
|
|
|
+ if params.asrText == 'start': #欢迎语
|
|
|
|
+ response_data['contents'].append({
|
|
|
|
+ "contentType": "voice",
|
|
|
|
+ "content": "",
|
|
|
|
+ "voiceUrl": '/code/src/core/voip/scripts/1_00.wav',
|
|
|
|
+ "voiceContent": "五一北京到上海的高铁票还有吗?"
|
|
|
|
+ })
|
|
|
|
+ response_data['inputType'] = '1'
|
|
|
|
+ elif params.asrText == 'ASR408error': #超时执行
|
|
response_data['contents'].append({
|
|
response_data['contents'].append({
|
|
- "content_type": "voice",
|
|
|
|
|
|
+ "contentType": "voice",
|
|
"content": "",
|
|
"content": "",
|
|
- "voice_url": '/code/src/core/voip/scripts/1_00.wav',
|
|
|
|
- "voice_content": "五一北京到上海的高铁票还有吗?"
|
|
|
|
|
|
+ "voiceUrl": '/code/src/core/voip/scripts/4_00.wav',
|
|
|
|
+ "voiceContent": "waitTime超时"
|
|
})
|
|
})
|
|
- response_data['dtmf_type']= '1'
|
|
|
|
- elif event_type == '2':
|
|
|
|
- new_contents = [
|
|
|
|
|
|
+ elif "DTMF" in params.asrText and self.call_agent.inputType =='1': #长按键超30s执行
|
|
|
|
+ response_data['contents'].append({
|
|
|
|
+ "contentType": "voice",
|
|
|
|
+ "content": "",
|
|
|
|
+ "voiceUrl": '/code/src/core/voip/scripts/2_00.wav',
|
|
|
|
+ "voiceContent": "sds"
|
|
|
|
+ })
|
|
|
|
+ else :
|
|
|
|
+ response_data['contents'] = [
|
|
{
|
|
{
|
|
- "content_type": "voice",
|
|
|
|
|
|
+ "contentType": "voice",
|
|
"content": "",
|
|
"content": "",
|
|
- "voice_url": '/code/src/core/voip/test111.wav',
|
|
|
|
- "voice_content": "测试第二个录音文件"
|
|
|
|
|
|
+ "voiceUrl": '/code/src/core/voip/test111.wav',
|
|
|
|
+ "voiceContent": "测试第二个录音文件"
|
|
},
|
|
},
|
|
{
|
|
{
|
|
- "content_type": "voice",
|
|
|
|
|
|
+ "contentType": "voice",
|
|
"content": "",
|
|
"content": "",
|
|
- "voice_url": '/code/src/core/voip/test222.wav',
|
|
|
|
- "voice_content": "五一北京到上海的高铁票还有吗?"
|
|
|
|
|
|
+ "voiceUrl": '/code/src/core/voip/test222.wav',
|
|
|
|
+ "voiceContent": "五一北京到上海的高铁票还有吗?"
|
|
}
|
|
}
|
|
]
|
|
]
|
|
- response_data['contents']= new_contents
|
|
|
|
- elif event_type == '6':
|
|
|
|
- response_data['contents'].append({
|
|
|
|
- "content_type": "voice",
|
|
|
|
- "content": "",
|
|
|
|
- "voice_url": '/code/src/core/voip/scripts/4_00.wav',
|
|
|
|
- "voice_content": "sds"
|
|
|
|
- })
|
|
|
|
- elif event_type == '7':
|
|
|
|
- response_data['contents'].append({
|
|
|
|
- "content_type": "voice",
|
|
|
|
- "content": "",
|
|
|
|
- "voice_url": '/code/src/core/voip/scripts/2_00.wav',
|
|
|
|
- "voice_content": "sds"
|
|
|
|
- })
|
|
|
|
try:
|
|
try:
|
|
print(json.dumps(response_data['contents']))
|
|
print(json.dumps(response_data['contents']))
|
|
parsed_response = ChatMessage.from_json(response_data)
|
|
parsed_response = ChatMessage.from_json(response_data)
|
|
- # self.handling_message(parsed_response)
|
|
|
|
self.call_agent.message_queue.put(parsed_response)
|
|
self.call_agent.message_queue.put(parsed_response)
|
|
except Exception as e:
|
|
except Exception as e:
|
|
print(f"Error in test_request: {e}")
|
|
print(f"Error in test_request: {e}")
|
|
@@ -451,8 +450,8 @@ class BotAgent:
|
|
ep_cfg.uaConfig.maxCalls = 20
|
|
ep_cfg.uaConfig.maxCalls = 20
|
|
ep_cfg.uaConfig.maxAccounts = 20
|
|
ep_cfg.uaConfig.maxAccounts = 20
|
|
ep_cfg.medConfig.noVad = True
|
|
ep_cfg.medConfig.noVad = True
|
|
- ep_cfg.logConfig.level = 3
|
|
|
|
- ep_cfg.logConfig.consoleLevel = 3
|
|
|
|
|
|
+ ep_cfg.logConfig.level = 4
|
|
|
|
+ ep_cfg.logConfig.consoleLevel = 4
|
|
self.ep.libCreate()
|
|
self.ep.libCreate()
|
|
self.ep.libInit(ep_cfg)
|
|
self.ep.libInit(ep_cfg)
|
|
|
|
|