Преглед изворни кода

feat: 测试文本机器人接口

余尚辉 пре 3 месеци
родитељ
комит
80b313567d
3 измењених фајлова са 71 додато и 54 уклоњено
  1. 1 0
      docker-compose.yml
  2. 20 20
      src/core/callcenter/api.py
  3. 50 34
      src/core/voip/bot.py

+ 1 - 0
docker-compose.yml

@@ -6,6 +6,7 @@ services:
     network_mode: host
     volumes:
       - /home/hongshan/voice-gateway-service:/code
+      - /root/aibot/dm/voice:root/aibot/dm/voice
     environment:
       - SERVE_HOST=192.168.100.159
 #    ports:

+ 20 - 20
src/core/callcenter/api.py

@@ -678,7 +678,7 @@ class RouteGateway(BaseApi):
 # 机器人外呼
 class BotChatRequest:
     def __init__(self, nodeId=None, userId=None, sessionId=None, taskId=None, asrText=None, recordId=None,
-                 ext: Dict = {}):
+                 ext: Optional[str] = None):
         self.nodeId = nodeId  # 节点id
         self.userId = userId  # 用户id
         self.sessionId = sessionId  # 会话id
@@ -702,9 +702,9 @@ class BotChatRequest:
 
 
 class ChatAction:
-    def __init__(self, actionCode=None, actionContent=None):
-        self.actionCode = actionCode  # normal:正常通话;hang:挂断;transfer:转人工
-        self.actionContent = actionContent  # 动作内容
+    def __init__(self, action_code=None, action_content=None):
+        self.action_code = action_code  # normal:正常通话;hang:挂断;transfer:转人工
+        self.action_content = action_content  # 动作内容
 
     def to_json_string(self):
         return json.dumps(self.__dict__, ensure_ascii=False)
@@ -712,17 +712,17 @@ class ChatAction:
     @classmethod
     def from_json(cls, json_data):
         return cls(
-            actionCode=json_data.get("actionCode"),
-            actionContent=json_data.get("actionContent")
+            action_code=json_data.get("action_code"),
+            action_content=json_data.get("action_content")
         )
 
 
 class ChatContent:
-    def __init__(self, contentType=None, content=None, voiceUrl=None, voiceContent=None):
-        self.contentType = contentType  # 播放类型
+    def __init__(self, content_type=None, content=None, voice_url=None, voice_content=None):
+        self.content_type = content_type  # 播放类型
         self.content = content  # 播放内容
-        self.voiceUrl = voiceUrl  # 语音地址
-        self.voiceContent = voiceContent  # 语音文本
+        self.voice_url = voice_url  # 语音地址
+        self.voice_content = voice_content  # 语音文本
 
     def to_json_string(self):
         return json.dumps(self.__dict__, ensure_ascii=False)
@@ -730,27 +730,27 @@ class ChatContent:
     @classmethod
     def from_json(cls, json_data):
         return cls(
-            contentType=json_data.get("contentType"),
+            content_type=json_data.get("content_type"),
             content=json_data.get("content"),
-            voiceUrl=json_data.get("voiceUrl"),
-            voiceContent=json_data.get("voiceContent")
+            voice_url=json_data.get("voice_url"),
+            voice_content=json_data.get("voice_content")
         )
 
 
 class ChatMessage:
-    def __init__(self, nodeId=None, contents=None, waitTime=None,
+    def __init__(self, node_id=None, contents=None, wait_time=None,
                  action=None, inputType=None):
-        self.nodeId = nodeId  # 节点id
+        self.node_id = node_id  # 节点id
         self.contents = contents if contents is not None else []  # 内容列表
-        self.waitTime = waitTime  # 用户静默时长
+        self.wait_time = wait_time  # 用户静默时长
         self.action = action  # 动作代码
         self.inputType = inputType  # dtmf类型
 
     def to_json_string(self):
         return json.dumps({
-            "nodeId": self.nodeId,
+            "node_id": self.node_id,
             "contents": [content.__dict__ for content in self.contents],
-            "waitTime": self.waitTime,
+            "wait_time": self.wait_time,
             "action": self.action.__dict__ if self.action else None,
             "inputType": self.inputType
         }, ensure_ascii=False)
@@ -760,9 +760,9 @@ class ChatMessage:
         contents = [ChatContent.from_json(item) for item in json_data.get("contents", [])]
         action = ChatAction.from_json(json_data.get("action", {})) if json_data.get("action") else None
         return cls(
-            nodeId=json_data.get("nodeId"),
+            node_id=json_data.get("node_id"),
             contents=contents,
-            waitTime=json_data.get("waitTime"),
+            wait_time=json_data.get("wait_time"),
             action=action,
             inputType=json_data.get("inputType")
         )

+ 50 - 34
src/core/voip/bot.py

@@ -11,7 +11,7 @@ import traceback
 import pjsua2 as pj
 from enum import Enum
 
-from src.core.datasource import SIP_SERVER
+from src.core.datasource import SIP_SERVER, SERVE_HOST
 from src.core.voip.constant import *
 
 import requests
@@ -86,18 +86,18 @@ class MyAudioMediaPort(pj.AudioMediaPort):
 
             #超时处理
             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}')
+            # 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)
 
             # 如果为超长类型的按键服务 超过30s未输入完成执行超时操作
             if self.call.inputType == '1' and play_complete and not asr_text:
-                self.wait_time_check(current_time, 15)
+                self.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.nodeId = self.get_player_file()
+                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)
 
                 # 重置播放完成标志和超时计时器,确保新的播放从头开始计时
@@ -126,13 +126,13 @@ class MyAudioMediaPort(pj.AudioMediaPort):
     def get_player_file(self):
         try:
             message = self.call.message_queue.get(block=False)
-            player_file = [item.voiceUrl for item in message.contents if item.contentType == 'voice']
+            player_file = [item.voice_url for item in message.contents if item.content_type == '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
+            print('get_player_file:', player_file,message.wait_time, message.inputType, message.action, message.node_id)
+            return player_file, message.wait_time, message.inputType, message.action, message.node_id
         except Exception as e:
             traceback.print_exc()
 
@@ -147,12 +147,10 @@ class MyAudioMediaPort(pj.AudioMediaPort):
         # 检查超时时间是否已到
         if current_time - self.play_start_time > int(wait_time):
             self.play_complete_flag = False  # 重置标志位,避免重复超时
-            if wait_time == 15:
+            if wait_time == 30:
                 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:
-                # self.call.chat("6", "ASR408error")
                 print("DTMF:超时6shehehehehehhehhehehe")
                 self.call.user_asr_text_queue.put("ASR408error")
 
@@ -219,7 +217,7 @@ class MyCall(pj.Call):
         self.inputType = None #记录按键类型 1为长按键类型
         self.digit = '' # 存储长按键内容
         self.action = None
-        self.nodeId= 'start'
+        self.node_id= 'start'
 
         self.cur_player_file = None   #当前播放的文件
 
@@ -227,6 +225,18 @@ class MyCall(pj.Call):
         self.asr = TestSt(call_id, message_receiver=self.on_receiver_asr_result)  # 创建ASR实例
         self.asr.start()  # 启动ASR线程
 
+        self.call_phone = self.get_phone()
+
+    def get_phone(self):
+        import re
+        call_info = self.getInfo()
+        match = re.match(r'"(\d+)" <sip:(\d+)@', call_info.remoteUri)
+        if match:
+            print("Phone Number:", match.group(1))
+            return match.group(1)  # 假设显示名称部分是手机号
+        else:
+            return ""
+            print("Failed to parse the phone number from remoteUri.")
     def is_play_complete(self):    #语音机器人是否播放结束
         if self.cur_player_file:
             player_id = murmur3_32(self.cur_player_file)
@@ -250,7 +260,7 @@ class MyCall(pj.Call):
 
     def onCallState(self, prm):
         call_info = self.getInfo()
-        print("Call state: ", call_info.stateText)
+        print("Call state: ",call_info.state)
 
         # pj.PJSIP_INV_STATE_NULL
         # pj.PJSIP_INV_STATE_CALLING
@@ -329,12 +339,12 @@ class MyCall(pj.Call):
         ToTextBotAgent(user_asr_text,self)
 
     def say_end_action(self, action):
-        print('handling_release', action.actionCode)
-        actionCode = action.actionCode
-        if actionCode == 'hang':  # 挂断
-            actionContent = action.actionContent
-            print(f'todo 挂电话:{actionContent}')
-        elif actionCode == 'transfer':  # 转人工
+        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:
@@ -345,37 +355,43 @@ class ToTextBotAgent:
 
         self.call_agent = call_agent
         self.request_data = BotChatRequest(
-            nodeId=self.call_agent.nodeId,
-            userId="139311",
-            sessionId="1",
-            recordId="2",
-            taskId="ceshi",
-            asrText=user_asr_text
+            nodeId=self.call_agent.node_id,
+            userId=self.call_agent.call_phone,
+            sessionId="1334343434",
+            recordId="",
+            taskId="10001",
+            asrText=user_asr_text,
+            ext= None
         )
         # 发送请求并处理响应
-        self.test_request(self.request_data)
+        # self.test_request(self.request_data)
+        self.to_quest(self.request_data)
 
 
     def to_quest(self, request: BotChatRequest):
         # 将实体类转换为JSON字符串
         headers = {'Content-Type': 'application/json'}
-        request_json = request.to_json_string()
+        request_data = request.to_json_string()
+        url = f"http://{SERVE_HOST}:40072/botservice"
         # 发送POST请求
+        print(f"请求数据:{request_data},url:{url}")
         try:
-            response = requests.post('http://example.com/api', data=request_json, headers=headers)  # 使用占位URL
+            response = requests.post(url=url,  json=json.loads(request_data), headers=headers, timeout=10)  # 使用占位URL
+            print(f"原始响应内容:{response.text}")
             if response.status_code == 200:
-                # 成功,解析响应JSON
                 response_data = response.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)
+                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)
+                else:
+                    print("响应中没有 'data' 字段")
             else:
                 # 错误处理
                 print(f"请求失败,状态码: {response.status_code}, 响应内容: {response.text}")
-                return None
         except requests.RequestException as e:
-            traceback.print_exc()
-            return None
+            print(f"请求发生异常: {e}")
 
 # 模拟接口请求返回
     def test_request(self, params: BotChatRequest):