刘威 5 月之前
父節點
當前提交
5b0216c258
共有 3 個文件被更改,包括 85 次插入44 次删除
  1. 6 3
      src/core/callcenter/model.py
  2. 77 36
      src/core/voip/bot.py
  3. 2 5
      src/core/voip/constant.py

+ 6 - 3
src/core/callcenter/model.py

@@ -563,13 +563,14 @@ class ChatContent:
 
 class ChatMessage:
     def __init__(self, node_id=None, contents=None, interruptable=None, wait_time=None,
-                 action=None, talk_time_out=None):
+                 action=None, talk_time_out=None,dtmf_type=None):
         self.node_id = node_id   # 节点id
         self.contents = contents if contents is not None else []   # 内容列表
         self.interruptable = interruptable   # 是否可打断
         self.wait_time = wait_time   # 用户静默时长
         self.action = action        # 动作代码
         self.talk_time_out = talk_time_out     # 用户通话时长
+        self.dtmf_type = dtmf_type   # dtmf类型
 
     def to_json_string(self):
         return json.dumps({
@@ -578,7 +579,8 @@ class ChatMessage:
             "interruptable": self.interruptable,
             "wait_time": self.wait_time,
             "action": self.action.__dict__ if self.action else None,
-            "talk_time_out": self.talk_time_out
+            "talk_time_out": self.talk_time_out,
+            "dtmf_type": self.dtmf_type
         }, ensure_ascii=False)
 
     @classmethod
@@ -591,7 +593,8 @@ class ChatMessage:
             interruptable=json_data.get("interruptable"),
             wait_time=json_data.get("wait_time"),
             action=action,
-            talk_time_out=json_data.get("talk_time_out")
+            talk_time_out=json_data.get("talk_time_out"),
+            dtmf_type=json_data.get("dtmf_type")
         )
 
 

+ 77 - 36
src/core/voip/bot.py

@@ -57,11 +57,13 @@ class MyAudioMediaPort(pj.AudioMediaPort):
 
         self.user_asr_texts = []
         self.cur_player_file = None
-        self.wait_time = None
+
 
         self.play_start_time = None  # 记录播放开始时间
         self.play_complete_flag = False  # 播放完成标志
 
+
+        #self.dtmf_type = None   #记录按键类型 1为长按键类型
     def onFrameRequested(self, frame):
         print("Request audio frame:", frame)
 
@@ -85,19 +87,27 @@ class MyAudioMediaPort(pj.AudioMediaPort):
 
             #超时处理
             current_time = time.time()
-            if self.wait_time and self.wait_time != "0" and play_complete and not asr_text:
-                print('ssdsdsd',play_complete,asr_text)
-                self.wait_time_check(current_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 == '':
+                self.wait_time_check(current_time, self.call.wait_time)
+
+            # 如果为超长类型的按键服务 超过30s未输入完成执行超时操作
+            if self.call.dtmf_type=='1' and play_complete and not asr_text:
+                self.wait_time_check(current_time, 30)
 
             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):
                 print('onFrameReceived:message_queue_size=', message_queue_size, 'play_complete=', play_complete, asr_text)
-                self.cur_player_file, self.wait_time= self.get_player_file()
+                self.cur_player_file, self.call.wait_time, self.call.dtmf_type, action= self.get_player_file()
                 self.call.send_bot_speaker(self.cur_player_file)
 
                 # 重置播放完成标志和超时计时器,确保新的播放从头开始计时
                 self.play_complete_flag = False  # 重置播放完成标志
                 self.play_start_time = time.time()  # 重新开始计时
+                self.call.digit = ""   #重新把超长类型按键内容digit置为空
+
+                #播放完毕执行的动作
+                self.call.say_end_action(action)
         except:
             pass
 
@@ -119,23 +129,29 @@ 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']
             wait_time = message.wait_time
-            return player_file, 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
         except Exception as e:
-            print(f"sdsd: {e}")
             traceback.print_exc()
 
-    def wait_time_check(self,current_time):
+    def wait_time_check(self,current_time,wait_time):
         if not hasattr(self, 'play_complete_flag'):
-                self.play_complete_flag = False
-                self.play_start_time = 0
+            self.play_complete_flag = False
+            self.play_start_time = 0
         # 播放完成后开始计时
         if not self.play_complete_flag:
             self.play_complete_flag = True
             self.play_start_time = current_time
         # 检查超时时间是否已到
-        if current_time - self.play_start_time > int(self.wait_time):
-                self.play_complete_flag = False  # 重置标志位,避免重复超时
-                self.call.chat("6", "重新请求文本机器人")
+        if current_time - self.play_start_time > int(wait_time):
+            self.play_complete_flag = False  # 重置标志位,避免重复超时
+            if wait_time == 30:
+                self.call.chat("7", self.call.digit)
+            else:
+                self.call.chat("6", "")
+
 
 
 class MyAudioMediaPlayer(pj.AudioMediaPlayer):
@@ -195,6 +211,10 @@ class MyCall(pj.Call):
         self.message_queue = queue.Queue(maxsize=3)
         self.player_complete_dict = {}
 
+        self.wait_time = None
+        self.dtmf_type = None #记录按键类型 1为长按键类型
+        self.digit = '' # 存储长按键内容
+
         from src.core.voip.asr import TestSt
         self.asr = TestSt(call_id, message_receiver=self.on_receiver_asr_result)  # 创建ASR实例
         self.asr.start()  # 启动ASR线程
@@ -202,8 +222,20 @@ class MyCall(pj.Call):
 
     def onDtmfDigit(self, prm):
         digit = prm.digit
-        print(f"Received DTMF digit: {digit}")
-        self.user_asr_text_queue.put(f"DTMF({digit})DTMF")
+        # 假设为超长类型按键 把用户输入的按键进行拼接 如果为# 则把用户输入所有按键放入队列并发送文本机器人
+        # 如果为非正常按键服务 输入以后直接发送文本机器人
+        if self.dtmf_type == '1':
+            if digit != '#':
+                self.digit += digit
+                print(f"Received DTMF digit12: {self.digit}")
+            else:
+                self.user_asr_text_queue.put(f"DTMF({self.digit})DTMF")
+                self.chat('3', self.digit)
+                print(f"Received DTMF digit34: {self.digit}")
+        else:
+            print(f"Received DTMF digit: {digit}")
+            self.user_asr_text_queue.put(f"DTMF({digit})DTMF")
+            # self.chat('3', digit)
 
     def onCallState(self, prm):
         call_info = self.getInfo()
@@ -259,7 +291,16 @@ class MyCall(pj.Call):
 
     def on_receiver_asr_result(self, message, *args):
         print('asr返回内容:',message)
-        self.user_asr_text_queue.put(message)
+        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')
@@ -272,6 +313,14 @@ class MyCall(pj.Call):
         # 调用文本机器人接口
         ToTextBotAgent(event_type,user_asr_text,self)
 
+    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('todo 转人工')
 
 class ToTextBotAgent:
     def __init__(self, event_type, user_asr_text, call_agent):
@@ -291,25 +340,7 @@ class ToTextBotAgent:
         # 发送请求并处理响应
         self.test_request(self.request_data,event_type)
 
-    def to_hang(self, action_content):
-        user_part = self.call_agent.user_part_pool.get()
-        self.call_agent.hangup(user_part, action_content)
 
-    def handling_message(self, message: ChatMessage):
-        print('handling_release', message)
-        if message:
-            action = message.action
-            action_code = action.action_code
-            if action_code == 'hang':  # 挂断
-                action_content = action.action_content
-                self.to_hang(action_content)
-            elif action_code == 'transfer':  # 转人工
-                print('todo 转人工')
-            elif action_code == 'normal':  # 正常通话
-                self.call_agent.message_queue.put(message)
-                print(f"成功获取响应: ActionCode: {message.wait_time}")
-        else:
-            print("文本机器人接口调用失败")
 
     def to_quest(self, request: BotChatRequest):
         # 将实体类转换为JSON字符串
@@ -342,7 +373,8 @@ class ToTextBotAgent:
                 "action_code": "normal",
                 "action_content": "正常通话"
             },
-            "talk_time_out": ""
+            "talk_time_out": "",
+            "dtmf_type": '0'
         }
 
         print("event_type:", event_type)
@@ -353,6 +385,7 @@ class ToTextBotAgent:
                 "voice_url": '/code/src/core/voip/scripts/1_00.wav',
                 "voice_content": "五一北京到上海的高铁票还有吗?"
             })
+            response_data['dtmf_type']= '1'
         elif event_type == '2':
             new_contents = [
                 {
@@ -376,10 +409,18 @@ class ToTextBotAgent:
                 "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:
             print(json.dumps(response_data['contents']))
             parsed_response = ChatMessage.from_json(response_data)
-            self.handling_message(parsed_response)
+            # self.handling_message(parsed_response)
+            self.call_agent.message_queue.put(parsed_response)
         except Exception as e:
             print(f"Error in test_request: {e}")
             traceback.print_exc()  # 打印完整的错误信息

+ 2 - 5
src/core/voip/constant.py

@@ -10,12 +10,9 @@ player_script_dir = '/code/src/core/voip/scripts/'
 
 
 def murmur3_32(player_file):
-    newplayer_file = ''
     if isinstance(player_file, list):
-        newplayer_file = ','.join(player_file)
-    else:
-        newplayer_file = player_file
-    return abs(mmh3.hash(newplayer_file))
+        player_file = ','.join(player_file)
+    return abs(mmh3.hash(player_file))
 
 
 def build_audio_format():