|
@@ -18,6 +18,7 @@ import requests
|
|
|
from src.core.callcenter.api import BotChatRequest,ChatMessage
|
|
|
|
|
|
from src.core import singleton_keys
|
|
|
+from src.core.callcenter.snowflake import Snowflake
|
|
|
|
|
|
calls = {}
|
|
|
# recording_file = '/code/src/core/voip/incoming_call.wav'
|
|
@@ -70,26 +71,32 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
|
# print("Received audio frame:", frame.buf, frame.size)
|
|
|
if self.asr: # 如果ASR实例存在,则发送音频数据
|
|
|
self.asr.send_audio(frame.buf)
|
|
|
-
|
|
|
- current_time = time.time() # 实时当前时间
|
|
|
try:
|
|
|
asr_text = self.get_asr_text()
|
|
|
play_complete = self.call.is_play_complete()
|
|
|
- if asr_text and not play_complete:
|
|
|
- self.user_asr_texts.append(asr_text)
|
|
|
- if asr_text and play_complete:
|
|
|
- self.call.cur_player_file = None
|
|
|
- self.user_asr_texts.append(asr_text)
|
|
|
- if self.call.inputType == '1.0' and current_time - self.call.inputLongStart > 35:
|
|
|
- self.user_asr_texts.append(self.call.digit)
|
|
|
+ current_time = time.time() # 实时当前时间
|
|
|
+ if self.call.inputType == '1.0':
|
|
|
+ time_difference = int(current_time - self.call.inputLongStart)
|
|
|
+ # print('current_time - self.call.inputLongStart:',time_difference > 35, self.call.txtLock , play_complete)
|
|
|
+ if int(current_time - self.call.inputLongStart) > 35 and play_complete and not self.call.txtLock:
|
|
|
+ self.user_asr_texts.append(f"DTMF({self.call.digit})DTMF")
|
|
|
user_asr_text = asr_text if len(self.user_asr_texts) == 1 else '###'.join(self.user_asr_texts)
|
|
|
+ self.user_asr_texts.clear()
|
|
|
self.call.chat(user_asr_text)
|
|
|
- else:
|
|
|
+ # print("测试超长", user_asr_text)
|
|
|
+ elif asr_text:
|
|
|
+ self.user_asr_texts.append(asr_text)
|
|
|
+ if time_difference > int(self.call.wait_time):
|
|
|
+ self.call.reset_wait_time()
|
|
|
+ else:
|
|
|
+ if asr_text and not play_complete:
|
|
|
+ self.user_asr_texts.append(asr_text)
|
|
|
+ if asr_text and play_complete:
|
|
|
+ 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)
|
|
|
self.user_asr_texts.clear()
|
|
|
self.call.chat(user_asr_text)
|
|
|
|
|
|
- # 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:
|
|
|
self.call.wait_time_check(current_time, self.call.wait_time)
|
|
|
|
|
@@ -99,17 +106,13 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
|
self.call.cur_player_file, self.call.wait_time, self.call.inputType,self.call.action, self.call.node_id = self.get_player_file()
|
|
|
# 重置播放完成标志和超时计时器,确保新的播放从头开始计时
|
|
|
self.call.reset_wait_time()
|
|
|
+ self.call.txtLock = False
|
|
|
self.call.send_bot_speaker(self.call.cur_player_file)
|
|
|
#播放完毕执行的动作
|
|
|
self.call.say_end_action(self.call.action)
|
|
|
except:
|
|
|
pass
|
|
|
|
|
|
- # def is_play_complete(self):
|
|
|
- # if self.call.cur_player_file:
|
|
|
- # player_id = murmur3_32(self.call.cur_player_file)
|
|
|
- # return self.call.player_complete_dict.get(player_id)
|
|
|
-
|
|
|
def get_asr_text(self):
|
|
|
try:
|
|
|
asr_text = self.call.user_asr_text_queue.get(block=False)
|
|
@@ -123,8 +126,6 @@ class MyAudioMediaPort(pj.AudioMediaPort):
|
|
|
message = self.call.message_queue.get(block=False)
|
|
|
player_file = [item.voice_url for item in message.contents if item.content_type == 'voice']
|
|
|
print('get_player_file:', player_file,message.wait_time, message.inputType, message.action, message.node_id)
|
|
|
- if message.inputType== '1.0':
|
|
|
- self.call.inputLongStart = time.time()
|
|
|
return player_file, message.wait_time, message.inputType, message.action, message.node_id
|
|
|
except Exception as e:
|
|
|
traceback.print_exc()
|
|
@@ -182,7 +183,10 @@ class MyCall(pj.Call):
|
|
|
self.player = None
|
|
|
self.asr = None
|
|
|
|
|
|
- print("mycall acc:", call_id)
|
|
|
+ self.snowflake = Snowflake(worker_id=1, data_center_id=1)
|
|
|
+ self.session_id = 'S' + str(self.snowflake.next_id())
|
|
|
+
|
|
|
+ print("self.session_id:", self.session_id)
|
|
|
# self.scripts = build_demo_script()
|
|
|
self.user_asr_text_queue = queue.Queue(maxsize=100)
|
|
|
self.message_queue = queue.Queue(maxsize=3)
|
|
@@ -207,7 +211,7 @@ class MyCall(pj.Call):
|
|
|
self.play_complete_flag = False # 倒计时开始标志
|
|
|
|
|
|
self.txtLock = False
|
|
|
- self.inputLongStart = 0 #长按键开始时间
|
|
|
+ self.inputLongStart = time.time() #长按键开始时间
|
|
|
|
|
|
def wait_time_check(self, current_time, wait_time):
|
|
|
try:
|
|
@@ -217,17 +221,11 @@ class MyCall(pj.Call):
|
|
|
if not self.play_complete_flag:
|
|
|
self.play_complete_flag = True
|
|
|
self.play_start_time = current_time
|
|
|
- print(f"开始计时: {self.play_start_time}")
|
|
|
-
|
|
|
- # 播放完成后,检查是否超时
|
|
|
+ # print(f"开始计时: {self.play_start_time}")
|
|
|
elapsed_time = current_time - self.play_start_time
|
|
|
- print(f"当前时间: {current_time}, 已过时间: {elapsed_time}, 最大等待时间: {wait_time}")
|
|
|
-
|
|
|
if elapsed_time >= wait_time:
|
|
|
- print("ASR输入超时")
|
|
|
- self.user_asr_text_queue.put("ASR408error")
|
|
|
- self.reset_wait_time()
|
|
|
-
|
|
|
+ # self.user_asr_text_queue.put("ASR408error")
|
|
|
+ self.chat('ASR408error')
|
|
|
except ValueError as e:
|
|
|
print(f"无效的等待时间参数: {wait_time}, 错误: {e}")
|
|
|
self.reset_wait_time()
|
|
@@ -235,7 +233,6 @@ class MyCall(pj.Call):
|
|
|
def reset_wait_time(self):
|
|
|
self.play_complete_flag = False # 重置播放完成标志
|
|
|
self.play_start_time = None # 重置开始计时时间
|
|
|
- print("计时器已重置")
|
|
|
def get_phone(self):
|
|
|
import re
|
|
|
call_info = self.getInfo()
|
|
@@ -250,24 +247,22 @@ class MyCall(pj.Call):
|
|
|
player_id = murmur3_32(self.cur_player_file)
|
|
|
return self.player_complete_dict.get(player_id)
|
|
|
def onDtmfDigit(self, prm):
|
|
|
- if not self.is_play_complete() or self.txtLock: # 判断是否播放完成 否则不记录用户说的内容
|
|
|
- return
|
|
|
- digit = prm.digit
|
|
|
- self.reset_wait_time()
|
|
|
- # 假设为超长类型按键 把用户输入的按键进行拼接 如果为# 则把用户输入所有按键放入队列并发送文本机器人
|
|
|
- # 如果为非正常按键服务 输入以后直接发送文本机器人
|
|
|
- if self.inputType == '1.0':
|
|
|
- if digit != '#':
|
|
|
- self.digit += digit
|
|
|
+ if self.is_play_complete() and not self.txtLock: # 判断是否播放完成 否则不记录用户说的内容
|
|
|
+ digit = prm.digit
|
|
|
+ self.reset_wait_time()
|
|
|
+ # 假设为超长类型按键 把用户输入的按键进行拼接 如果为# 则把用户输入所有按键放入队列并发送文本机器人
|
|
|
+ # 如果为非正常按键服务 输入以后直接发送文本机器人
|
|
|
+ if self.inputType == '1.0':
|
|
|
+ if digit != '#':
|
|
|
+ self.digit += digit
|
|
|
+ elif digit == '#':
|
|
|
+ # self.user_asr_text_queue.put(f"DTMF({self.digit})DTMF")
|
|
|
+ self.chat(f"DTMF({self.digit})DTMF")
|
|
|
else:
|
|
|
- self.user_asr_text_queue.put(f"DTMF({self.digit})DTMF")
|
|
|
- else:
|
|
|
- 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")
|
|
|
|
|
|
def onCallState(self, prm):
|
|
|
call_info = self.getInfo()
|
|
|
- # print("Call state text: ", dir(call_info))
|
|
|
print("Call state: %s, call id: %s, callcallIdString: %s ", call_info.state, call_info.id, call_info.callIdString)
|
|
|
|
|
|
# pj.PJSIP_INV_STATE_NULL
|
|
@@ -293,7 +288,7 @@ class MyCall(pj.Call):
|
|
|
|
|
|
def onCallMediaState(self, prm):
|
|
|
call_info = self.getInfo()
|
|
|
- print("Call Media state: ", call_info.stateText)
|
|
|
+ # print("Call Media state: ", call_info.stateText)
|
|
|
for media in call_info.media:
|
|
|
if media.type == pj.PJMEDIA_TYPE_AUDIO and \
|
|
|
(media.status == pj.PJSUA_CALL_MEDIA_ACTIVE):
|
|
@@ -316,7 +311,6 @@ class MyCall(pj.Call):
|
|
|
return
|
|
|
player_id = murmur3_32(player_file)
|
|
|
self.player_complete_dict[player_id] = False
|
|
|
- self.txtLock = False
|
|
|
# print('self.player_complete_dict[player_id]D:', player_id, player_file, self.player_complete_dict[player_id])
|
|
|
print(f"[DEBUG] Sending bot speaker, player_file: {player_file}, player_id: {player_id}")
|
|
|
self.player = MyAudioMediaPlayer(player_id, self.aud_med, on_complete=self.on_media_player_complete)
|
|
@@ -325,24 +319,23 @@ class MyCall(pj.Call):
|
|
|
self.player.startTransmit(self.aud_med)
|
|
|
|
|
|
def on_receiver_asr_result(self, message, *args):
|
|
|
- if not self.is_play_complete() or self.txtLock: # 判断是否播放完成 否则不记录用户说的内容
|
|
|
- print('机器人播放过程asr返回内容:',message)
|
|
|
- return
|
|
|
- self.reset_wait_time()
|
|
|
- message = json.loads(message)
|
|
|
- if message["header"]["status"] == 20000000:
|
|
|
- # 获取 result 内容
|
|
|
- result = message["payload"]["result"]
|
|
|
- print("asr返回内容Result:", result)
|
|
|
- self.user_asr_text_queue.put(result)
|
|
|
- else:
|
|
|
- print(f"Status is not {message['header']['status']}")
|
|
|
+ if self.is_play_complete() and not self.txtLock: # 判断是否播放完成 否则不记录用户说的内容
|
|
|
+ self.reset_wait_time()
|
|
|
+ message = json.loads(message)
|
|
|
+ if message["header"]["status"] == 20000000:
|
|
|
+ # 获取 result 内容
|
|
|
+ result = message["payload"]["result"]
|
|
|
+ print("asr返回内容Result:", result)
|
|
|
+ self.user_asr_text_queue.put(result)
|
|
|
+ else:
|
|
|
+ print(f"Status is not {message['header']['status']}")
|
|
|
|
|
|
|
|
|
|
|
|
def on_media_player_complete(self, player_id):
|
|
|
print('player complete')
|
|
|
self.player_complete_dict[player_id] = True
|
|
|
+ self.inputLongStart = time.time()
|
|
|
|
|
|
def bot_say_hello(self):
|
|
|
# print('bot_say_hello, come in ')
|
|
@@ -369,13 +362,11 @@ class ToTextBotAgent:
|
|
|
if not user_asr_text:
|
|
|
print("ASR文本为空,终止执行。")
|
|
|
return
|
|
|
-
|
|
|
self.call_agent = call_agent
|
|
|
self.request_data = BotChatRequest(
|
|
|
nodeId=self.call_agent.node_id,
|
|
|
userId=self.call_agent.call_phone,
|
|
|
- sessionId= self.call_agent.callIdString,
|
|
|
- # sessionId="23",
|
|
|
+ sessionId= self.call_agent.session_id,
|
|
|
recordId="",
|
|
|
taskId="10001",
|
|
|
asrText=user_asr_text,
|
|
@@ -418,7 +409,10 @@ class ToTextBotAgent:
|
|
|
|
|
|
# 模拟接口请求返回
|
|
|
def test_request(self, params: BotChatRequest):
|
|
|
+ if self.call_agent.txtLock:
|
|
|
+ return
|
|
|
print("test_request::params=", params)
|
|
|
+ self.call_agent.txtLock = True
|
|
|
response_data = {
|
|
|
"node_id": "1.0",
|
|
|
"contents": [],
|
|
@@ -427,7 +421,7 @@ class ToTextBotAgent:
|
|
|
"action_code": "normal",
|
|
|
"action_content": "正常通话"
|
|
|
},
|
|
|
- "input_type": "0"
|
|
|
+ "inputType": "0"
|
|
|
}
|
|
|
|
|
|
print("asrText:", params.asrText)
|
|
@@ -438,7 +432,7 @@ class ToTextBotAgent:
|
|
|
"voice_url": '/code/src/core/voip/scripts/1_00.wav',
|
|
|
"voice_content": "五一北京到上海的高铁票还有吗?"
|
|
|
})
|
|
|
- response_data['inputType'] = '1'
|
|
|
+ response_data['inputType'] = '1.0'
|
|
|
elif params.asrText == 'ASR408error': #超时执行
|
|
|
response_data['contents'].append({
|
|
|
"content_type": "voice",
|
|
@@ -446,7 +440,7 @@ class ToTextBotAgent:
|
|
|
"voice_url": '/code/src/core/voip/scripts/4_00.wav',
|
|
|
"voice_content": "waitTime超时"
|
|
|
})
|
|
|
- elif "DTMF" in params.asrText and self.call_agent.inputType =='1': #长按键超30s执行
|
|
|
+ elif "DTMF" in params.asrText and self.call_agent.inputType =='1.0': #长按键超30s执行
|
|
|
response_data['contents'].append({
|
|
|
"content_type": "voice",
|
|
|
"content": "",
|