Переглянути джерело

fix: 修改语音机器人逻辑

余尚辉 4 місяців тому
батько
коміт
68023ad53a
3 змінених файлів з 579 додано та 54 видалено
  1. 533 0
      logs/flask.log
  2. 2 2
      src/core/callcenter/esl/client.py
  3. 44 52
      src/core/voip/bot.py

Різницю між файлами не показано, бо вона завелика
+ 533 - 0
logs/flask.log


+ 2 - 2
src/core/callcenter/esl/client.py

@@ -34,7 +34,7 @@ class InboundClient:
 
     def __init__(self, agent, logger):
         self.con = None
-        self.thread_num = 32
+        self.thread_num = 12
         self.is_stopping = False
         self.logger = logger
         self.bot_agent = agent
@@ -300,7 +300,7 @@ class InboundClient:
         msg.addHeader("call-command", EXECUTE)
         msg.addHeader("execute-app-name", HANGUP)
         msg.addHeader("execute-app-arg", NORMAL_CLEARING)
-        self.logger.info("hangup_call挂机 hangup call: {}, device: {}, ctiCauseEnum:{}", call_id, device_id, case_enum)
+        self.logger.info("hangup_call挂机 hangup call: %s, device: %s, ctiCauseEnum: %s", call_id, device_id, case_enum)
         self.send_args(device_id, SET, EslEventUtil.SIP_H_P_LIBRA_HANGUP_CAUSE + "=" + case_enum.description)
         self.con.sendEvent(msg)
 

+ 44 - 52
src/core/voip/bot.py

@@ -71,6 +71,7 @@ class MyAudioMediaPort(pj.AudioMediaPort):
         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()
@@ -79,29 +80,26 @@ class MyAudioMediaPort(pj.AudioMediaPort):
             if asr_text and play_complete:
                 self.call.cur_player_file = None
                 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)
-
+                if self.call.inputType == '1.0' and current_time - self.call.inputLongStart > 35:
+                    self.user_asr_texts.append(self.call.digit)
+                    user_asr_text = asr_text if len(self.user_asr_texts) == 1 else '###'.join(self.user_asr_texts)
+                    self.call.chat(user_asr_text)
+                else:
+                    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)
 
-            #超时处理
-            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},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 :
+            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)
 
-            # 如果为超长类型的按键服务 超过30s未输入完成执行超时操作
-            if self.call.inputType == '1.0' and play_complete and not asr_text:
-                self.call.wait_time_check(current_time, 30)
-
             message_queue_size = self.call.message_queue.qsize()
             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)
                 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.send_bot_speaker(self.call.cur_player_file)
-
                 # 重置播放完成标志和超时计时器,确保新的播放从头开始计时
                 self.call.reset_wait_time()
+                self.call.send_bot_speaker(self.call.cur_player_file)
                 #播放完毕执行的动作
                 self.call.say_end_action(self.call.action)
         except:
@@ -123,9 +121,10 @@ class MyAudioMediaPort(pj.AudioMediaPort):
     def get_player_file(self):
         try:
             message = self.call.message_queue.get(block=False)
-            # player_file = [f"http://{SERVE_HOST}{item.voice_url}" for item in message.contents if item.content_type == 'voice']
             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()
@@ -204,44 +203,39 @@ class MyCall(pj.Call):
         self.call_phone, self.callIdString = self.get_phone()
 
         # 超时设置
-        self.play_start_time = time.time()  # 记录播放开始时间
-        self.play_complete_flag = False  # 播放完成标志
+        self.play_start_time = time.time()  # 倒计时开始时间
+        self.play_complete_flag = False  # 倒计时开始标志
 
         self.txtLock = False
-
-
-
-    # 开始说话
-    def begin_callback(self, message, *args):
-        self.reset_wait_time()
-        print("开始说话")
+        self.inputLongStart = 0  #长按键开始时间
 
     def wait_time_check(self, current_time, wait_time):
-        if not hasattr(self, 'play_complete_flag') or self.txtLock:
-            self.play_complete_flag = False
-            self.play_start_time = time.time()
-        # 播放完成后开始计时
-        if not self.play_complete_flag:
-            self.play_complete_flag = True
-            self.play_start_time = current_time
-        # 检查超时时间是否已到
-        print("current_time:", current_time, self.play_start_time)
-        elapsed_time = current_time - self.play_start_time
-        wait_time = int(wait_time)
-        if elapsed_time >  wait_time:
-            if wait_time >= 30:
-                print("DTMF:超时", self.digit)
-                self.user_asr_text_queue.put(f"DTMF({self.digit})DTMF")
-            else:
-                print("DTMF:超时6shehehehehehhehhehehe")
+        try:
+            # 确保 wait_time 是整数类型
+            wait_time = int(wait_time)
+            # 如果播放尚未完成,重置标志并返回
+            if not self.play_complete_flag:
+                self.play_complete_flag = True
+                self.play_start_time = current_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.play_complete_flag = False
+                self.reset_wait_time()
+
+        except ValueError as e:
+            print(f"无效的等待时间参数: {wait_time}, 错误: {e}")
+            self.reset_wait_time()
 
     def reset_wait_time(self):
         self.play_complete_flag = False  # 重置播放完成标志
-        # self.play_start_time = time.time()  # 重新开始计时
-        self.digit = ""  # 重新把超长类型按键内容digit置为空
-
+        self.play_start_time = None  # 重置开始计时时间
+        print("计时器已重置")
     def get_phone(self):
         import re
         call_info = self.getInfo()
@@ -259,15 +253,14 @@ class MyCall(pj.Call):
         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
-                # print(f"Received DTMF digit12: {self.digit}")
             else:
                 self.user_asr_text_queue.put(f"DTMF({self.digit})DTMF")
-                # print(f"Received DTMF digit34: {self.digit}")
         else:
             print(f"Received DTMF digit: {digit}")
             self.user_asr_text_queue.put(f"DTMF({digit})DTMF")
@@ -291,7 +284,6 @@ class MyCall(pj.Call):
 
         if call_info.state == pj.PJSIP_INV_STATE_DISCONNECTED:
             print("通话结束", self.user_part)
-            sys.stdout.flush()  # 强制刷新输出缓冲区
             if self.audio_port:
                 self.audio_port = None  # 或调用相关销毁方法
             if self.player:
@@ -324,6 +316,7 @@ 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)
@@ -335,6 +328,7 @@ class MyCall(pj.Call):
         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 内容
@@ -351,7 +345,7 @@ class MyCall(pj.Call):
         self.player_complete_dict[player_id] = True
 
     def bot_say_hello(self):
-        print('bot_say_hello, come in ')
+        # print('bot_say_hello, come in ')
         self.chat(user_asr_text="start")
 
     def chat(self, user_asr_text=None):
@@ -410,7 +404,6 @@ class ToTextBotAgent:
                 response_data = response.json()
                 if "data" in response_data and response_data["code"]==0:
                     data = response_data["data"]
-                    print(f"响应数据:{data}")
                     parsed_response = ChatMessage.from_json(data)
                     self.call_agent.message_queue.put(parsed_response)
                     sys.stdout.flush()  # 强制刷新输出缓冲区
@@ -419,10 +412,9 @@ class ToTextBotAgent:
             else:
                 # 错误处理
                 print(f"请求失败,状态码: {response.status_code}, 响应内容: {response.text}")
-            self.call_agent.txtLock = False
         except requests.RequestException as e:
             print(f"请求发生异常: {e}")
-            self.call_agent.txtLock = False
+
 
 # 模拟接口请求返回
     def test_request(self, params: BotChatRequest):
@@ -501,7 +493,7 @@ class BotAgent:
     def create_pjsua2(self):
         # Create and initialize the library
         ep_cfg = pj.EpConfig()
-        ep_cfg.uaConfig.threadCnt = 32
+        ep_cfg.uaConfig.threadCnt = 12
         ep_cfg.uaConfig.mainThreadOnly = False
         ep_cfg.uaConfig.maxCalls = 20
         ep_cfg.uaConfig.maxAccounts = 20

Деякі файли не було показано, через те що забагато файлів було змінено