ceshi.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import json
  2. from urllib.parse import urlparse
  3. from typing import Dict, Any, Optional
  4. import queue
  5. import threading
  6. import traceback
  7. import mmh3
  8. def murmur3_32(player_file):
  9. if isinstance(player_file, list):
  10. player_file = ','.join(player_file)
  11. return abs(mmh3.hash(player_file))
  12. #机器人外呼
  13. class BotChatRequest:
  14. def __init__(self, node_id=None, user_id=None, session_id=None, record_id=None,
  15. task_id=None, asr_text=None, key_input=None, ext:Dict={}):
  16. self.node_id = node_id # 节点id
  17. self.user_id = user_id # 用户id
  18. self.session_id = session_id # 会话id
  19. self.record_id = record_id # 唯一标识
  20. self.task_id = task_id # 机器人任务id
  21. self.event_type = None # 1:电话接通,2:用户语音asr结果上传,3:用户按键输入,4:用户挂断电话,5:读取外呼结果(可在外呼过程中调用,不一定在结束之后),6:用户不说话超时,7:TTS或录音文件播放完毕或被打断,8:ASR错误导致挂断电话,9:TTS错误导致挂断电话,10:其它系统错误导致挂断电话
  22. self.asr_text = asr_text # asr识别的文本
  23. self.ext = ext
  24. def to_json_string(self):
  25. return json.dumps(self.__dict__, ensure_ascii=False)
  26. @classmethod
  27. def from_json(cls, json_string):
  28. data = json.loads(json_string)
  29. return cls(**data)
  30. # def __repr__(self):
  31. # return (f"OutboundRobotRequestParams(node_id={self.node_id}, user_id={self.user_id}, "
  32. # f"session_id={self.session_id}, record_id={self.record_id}, task_id={self.task_id}, "
  33. # f"event_type={self.event_type}, asr_text={self.asr_text}, key_input={self.key_input})")
  34. class ChatAction:
  35. def __init__(self, action_code=None, action_content=None):
  36. self.action_code = action_code # normal:正常通话;hang:挂断;transfer:转人工
  37. self.action_content = action_content # 动作内容
  38. def to_json_string(self):
  39. return json.dumps(self.__dict__, ensure_ascii=False)
  40. @classmethod
  41. def from_json(cls, json_data):
  42. return cls(
  43. action_code=json_data.get("action_code"),
  44. action_content=json_data.get("action_content")
  45. )
  46. class ChatContent:
  47. def __init__(self, content_type=None, content=None, voice_url=None, voice_content=None):
  48. self.content_type = content_type # 播放类型
  49. self.content = content # 播放内容
  50. self.voice_url = voice_url # 语音地址
  51. self.voice_content = voice_content # 语音文本
  52. def to_json_string(self):
  53. return json.dumps(self.__dict__, ensure_ascii=False)
  54. @classmethod
  55. def from_json(cls, json_data):
  56. return cls(
  57. content_type=json_data.get("content_type"),
  58. content=json_data.get("content"),
  59. voice_url=json_data.get("voice_url"),
  60. voice_content=json_data.get("voice_content")
  61. )
  62. class ChatMessage:
  63. def __init__(self, node_id=None, contents=None, interruptable=None, wait_time=None,
  64. action=None, talk_time_out=None):
  65. self.node_id = node_id # 节点id
  66. self.contents = contents if contents is not None else [] # 内容列表
  67. self.interruptable = interruptable # 是否可打断
  68. self.wait_time = wait_time # 用户静默时长
  69. self.action = action # 动作代码
  70. self.talk_time_out = talk_time_out # 用户通话时长
  71. def to_json_string(self):
  72. return json.dumps({
  73. "node_id": self.node_id,
  74. "contents": [content.__dict__ for content in self.contents],
  75. "interruptable": self.interruptable,
  76. "wait_time": self.wait_time,
  77. "action": self.action.__dict__ if self.action else None,
  78. "talk_time_out": self.talk_time_out
  79. }, ensure_ascii=False)
  80. @classmethod
  81. def from_json(cls, json_data):
  82. contents = [ChatContent.from_json(item) for item in json_data.get("contents", [])]
  83. action = ChatAction.from_json(json_data.get("action", {})) if json_data.get("action") else None
  84. return cls(
  85. node_id=json_data.get("node_id"),
  86. contents=contents,
  87. interruptable=json_data.get("interruptable"),
  88. wait_time=json_data.get("wait_time"),
  89. action=action,
  90. talk_time_out=json_data.get("talk_time_out")
  91. )
  92. class ChatResponse:
  93. def __init__(self, data=None, message=None, code=None):
  94. self.data = data if data is not None else ChatMessage()
  95. self.message = message
  96. self.code = code
  97. def to_json_string(self):
  98. return json.dumps({
  99. "data": json.loads(self.data.to_json_string()),
  100. "message": self.message,
  101. "code": self.code
  102. }, ensure_ascii=False)
  103. @classmethod
  104. def from_json(cls, json_string):
  105. data = json.loads(json_string)
  106. response_data = ChatMessage.from_json(data.get("data", {}))
  107. return cls(
  108. data=response_data,
  109. message=data.get("message"),
  110. code=data.get("code")
  111. )
  112. class ToTextBotAgent:
  113. def __init__(self, event_type, user_asr_text):
  114. if not user_asr_text:
  115. print("ASR文本为空,终止执行。")
  116. return
  117. self.request_data = BotChatRequest(
  118. node_id="1",
  119. user_id="139311",
  120. session_id="1",
  121. record_id="2",
  122. task_id="ceshi",
  123. asr_text=user_asr_text
  124. )
  125. self.cur_player_file = None
  126. self.message_queue = queue.Queue(maxsize=3)
  127. # 发送请求并处理响应
  128. self.test_request(self.request_data,event_type)
  129. self.wait_time = None
  130. def to_hang(self, action_content):
  131. print('todo ')
  132. def transfer_people(self):
  133. print('todo 转人工')
  134. def handling_release(self, message: ChatMessage):
  135. print('handling_release', message)
  136. if message:
  137. action = message.action
  138. action_code = action.action_code
  139. print(f"ActionCode: {action_code}", message)
  140. if action_code == 'hang': # 挂断
  141. action_content = action.action_content
  142. self.to_hang(action_content)
  143. elif action_code == 'transfer': # 转人工
  144. self.transfer_people()
  145. elif action_code == 'normal': # 正常通话
  146. self.message_queue.put(message)
  147. print(f"成功获取响应: ActionCode: {message}")
  148. else:
  149. print("文本机器人接口调用失败")
  150. # 模拟接口请求返回
  151. def test_request(self, params: BotChatRequest,event_type):
  152. print("test_request::params=", params)
  153. response_data = {
  154. "node_id": "1.0",
  155. "contents": [],
  156. "interruptable": False,
  157. "wait_time": "6",
  158. "action": {
  159. "action_code": "normal",
  160. "action_content": "正常通话"
  161. },
  162. "talk_time_out": ""
  163. }
  164. print("event_type:", event_type)
  165. if event_type == '1':
  166. response_data['contents'].append({
  167. "content_type": "voice",
  168. "content": "",
  169. "voice_url": '/code/src/core/voip/test111.wav',
  170. "voice_content": "五一北京到上海的高铁票还有吗?"
  171. })
  172. elif event_type == '2':
  173. response_data['contents'].append({
  174. "content_type": "voice",
  175. "content": "",
  176. "voice_url": '/code/src/core/voip/test222.wav',
  177. "voice_content": "测试第二个录音文件"
  178. })
  179. # response = {
  180. # "data": response_data,
  181. # "message": "success",
  182. # "code": 200
  183. # }
  184. try:
  185. # 转换为JSON字符串并解析
  186. # response_json = json.dumps(response)
  187. parsed_response = ChatMessage.from_json(response_data)
  188. print(f"Response in test_request: {parsed_response}") # 确认response
  189. self.handling_release(parsed_response)
  190. except Exception as e:
  191. print(f"Error in test_request: {e}")
  192. traceback.print_exc() # 打印完整的错误信息
  193. return None
  194. def get_player_file(self):
  195. try:
  196. # player_file = self.call.player_queue.get(block=False)
  197. message = self.message_queue.get(block=False)
  198. player_file = [item.voice_url for item in message.contents if item.content_type == 'voice']
  199. wait_time = message.wait_time
  200. return player_file, wait_time
  201. except:
  202. pass
  203. def send_bot_speaker(self, player_file):
  204. if not player_file :
  205. return
  206. print(type(player_file))
  207. player_id = murmur3_32(player_file)
  208. print('send_bot_speaker:', player_id)
  209. def ceshi(self):
  210. message_queue_size = self.message_queue.qsize()
  211. if (message_queue_size > 0 and not self.cur_player_file) :
  212. self.cur_player_file, self.wait_time = self.get_player_file()
  213. print('cur_player_file:', self.cur_player_file , 'wait_time=', self.wait_time)
  214. self.send_bot_speaker(self.cur_player_file)
  215. if __name__ == "__main__":
  216. # 运行主函数
  217. # asyncio.run(main())
  218. # bot = ToTextBotAgent("1",'sddsd')
  219. # bot.ceshi()
  220. wait_time =None
  221. if wait_time and wait_time != "0":
  222. print('wait_time:', wait_time)