AIui_node.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. #!/usr/bin/env python3
  2. # coding=utf-8
  3. from utils.logger import logger
  4. from core.aiui.recorder import Recorder
  5. import handlers.aiui.pyaiui as pyaiui
  6. from handlers.aiui.pyAIUIConstant import AIUIConstant
  7. import json5
  8. import os
  9. import sys
  10. import random
  11. import json
  12. from threading import Thread
  13. import time
  14. from handlers.aiui.EventListener import EventListener, EventData
  15. from pathlib import Path
  16. CHUNK = 2048
  17. # 使用相对路径配置
  18. script_path = Path(__file__).resolve()
  19. BASE_DIR = script_path.parent.parent.parent
  20. cfg_file = os.path.join(BASE_DIR, "config", "aiui", "cfg", "aiui.cfg")
  21. WAITING = 0
  22. ABORT = -1
  23. ALLOW = 1
  24. def read_json5(path):
  25. try:
  26. with open(path, "r", encoding="utf-8") as f:
  27. return json5.loads(f.read())
  28. except Exception as e:
  29. logger.error("{},{}".format(e, __file__))
  30. return None
  31. class AIUINode():
  32. def __init__(self, event_listener, debug=False, wakeup_mute=False):
  33. self.agent_status = None
  34. event_listener.set_agent(self)
  35. self.event_listener = event_listener
  36. self.agent = pyaiui.IAIUIAgent.createAgent(json5.dumps(
  37. read_json5(cfg_file), quote_keys=True), event_listener)
  38. self.__recorder_ = None
  39. self.is_recording = False
  40. self.recorder_states = WAITING # -1:中断状态;0:等待状态;1:允许录音状态
  41. self.wakeup_mute = wakeup_mute
  42. self.is_hlw = False
  43. self.set_is_hlw()
  44. self.running = True
  45. def text_to_speak_multiple_options_callback(self, text, vcn="qige", speed=50, pitch=50, volume=50):
  46. self.cmd_tts(text, vcn, speed, pitch, volume)
  47. return True
  48. def direct_control_callback(self, text):
  49. self.event_listener.EventNLP(EventData({"text": text}))
  50. return True
  51. def text_to_speak_callback(self, text):
  52. self.cmd_tts(text)
  53. return True
  54. def set_is_hlw(self):
  55. # 简化HLW检测逻辑
  56. self.is_hlw = False
  57. def cmd_tts(self, text, vcn="qige", speed=50, pitch=50, volume=50):
  58. text = pyaiui.Buffer.create(bytes(text, encoding="utf-8"))
  59. TTSMsg = pyaiui.IAIUIMessage.create(
  60. AIUIConstant.CMD_TTS, 1, 0, "text_encoding=utf-8,vcn={},ent=x,speed={},pitch={},volume={}".format(vcn, speed, pitch, volume), text)
  61. self.agent.sendMessage(TTSMsg)
  62. TTSMsg.destroy()
  63. def cmd_tts_stop(self):
  64. text = pyaiui.Buffer.create(bytes("", encoding="utf-8"))
  65. TTSMsg = pyaiui.IAIUIMessage.create(
  66. AIUIConstant.CMD_TTS, 2, 0, "text_encoding=utf-8,vcn=qige,ent=x", text)
  67. self.agent.sendMessage(TTSMsg)
  68. TTSMsg.destroy()
  69. def wakeup_callback(self, msg=None):
  70. self.recorder_states = ABORT # 中断上一次录音等待
  71. self.getState()
  72. if self.is_recording:
  73. self.reset_wakeup_agent()
  74. self.is_recording = False
  75. if self.agent_status != AIUIConstant.STATE_WORKING:
  76. self.wakeup_agent()
  77. # 简化唤醒处理,直接开始录音
  78. logger.info("🎤 AIUI唤醒,开始录音")
  79. self.recorder_states = ALLOW # 直接允许录音
  80. Thread(target=self.__wait_play_to_start_record).start()
  81. def __wait_play_to_start_record(self):
  82. # 简化等待逻辑,直接开始录音
  83. self.recorder_states = ALLOW # 直接赋值允许录音
  84. self.start_record()
  85. def start_record(self):
  86. logger.info("开始录音...")
  87. self.is_recording = True
  88. if self.is_hlw == False:
  89. logger.info("启动非HLW录音模式")
  90. # 使用连续录音循环
  91. import threading
  92. threading.Thread(target=self.__continuous_record,
  93. daemon=True).start()
  94. else:
  95. logger.info("HLW录音模式已启用")
  96. @property
  97. def __recorder(self):
  98. if self.__recorder_ == None:
  99. self.__recorder_ = Recorder(CHUNK)
  100. return self.__recorder_
  101. def __start_record(self):
  102. """单次录音会话"""
  103. logger.info("录音流已启动,开始接收音频数据...")
  104. audio_count = 0
  105. for data in self.__recorder.read():
  106. if self.is_recording:
  107. audio_count += 1
  108. if audio_count % 100 == 0: # 每100个音频块记录一次
  109. logger.info(f"已接收 {audio_count} 个音频块")
  110. self.audio_stream_callback(data)
  111. else:
  112. logger.info("录音已停止")
  113. break
  114. logger.info(f"录音流结束,总共接收 {audio_count} 个音频块")
  115. def __continuous_record(self):
  116. """连续录音循环"""
  117. while self.running and self.recorder_states == ALLOW:
  118. self.is_recording = True
  119. self.__start_record()
  120. # 录音结束后短暂等待
  121. if self.running and self.recorder_states == ALLOW:
  122. logger.info("等待重新开始录音...")
  123. time.sleep(1)
  124. def audio_stream_callback(self, data):
  125. if self.is_recording:
  126. if self.is_hlw:
  127. audio_buffer = pyaiui.Buffer.create(data.data)
  128. self.record_stream_call_back(data.data)
  129. else:
  130. audio_buffer = pyaiui.Buffer.create(data)
  131. self.record_stream_call_back(data)
  132. self.cmd_write_audio(audio_buffer)
  133. else:
  134. logger.debug("录音已停止,跳过音频数据处理")
  135. def record_stream_call_back(self, buffer):
  136. pass
  137. def wakeup_agent(self):
  138. wakeup_msg = pyaiui.IAIUIMessage.create(AIUIConstant.CMD_WAKEUP)
  139. self.agent.sendMessage(wakeup_msg)
  140. wakeup_msg.destroy()
  141. def reset_wakeup_agent(self):
  142. reset_wakeup_msg = pyaiui.IAIUIMessage.create(
  143. AIUIConstant.CMD_RESET_WAKEUP)
  144. self.agent.sendMessage(reset_wakeup_msg)
  145. reset_wakeup_msg.destroy()
  146. def getState(self):
  147. get_state_msg = pyaiui.IAIUIMessage.create(AIUIConstant.CMD_GET_STATE)
  148. self.agent.sendMessage(get_state_msg)
  149. get_state_msg.destroy()
  150. def cmd_write_audio(self, audio_buffer):
  151. writeMsg = pyaiui.IAIUIMessage.create(
  152. AIUIConstant.CMD_WRITE, 0, 0, "data_type=audio", audio_buffer)
  153. self.agent.sendMessage(writeMsg)
  154. writeMsg.destroy()
  155. # 添加调试日志,每1000个音频块记录一次
  156. if hasattr(self, '_audio_sent_count'):
  157. self._audio_sent_count += 1
  158. else:
  159. self._audio_sent_count = 1
  160. if self._audio_sent_count % 1000 == 0:
  161. logger.info(f"已发送 {self._audio_sent_count} 个音频块给AIUI引擎")
  162. def cmd_write_text(self, text):
  163. text = pyaiui.Buffer.create(bytes(text, encoding="utf-8"))
  164. writeMsg = pyaiui.IAIUIMessage.create(
  165. AIUIConstant.CMD_WRITE, 0, 0, "data_type=text", text)
  166. self.agent.sendMessage(writeMsg)
  167. writeMsg.destroy()
  168. def stop_write(self):
  169. writeMsgStop = pyaiui.IAIUIMessage.create(
  170. AIUIConstant.CMD_STOP_WRITE, params="data_type=audio")
  171. self.agent.sendMessage(writeMsgStop)
  172. writeMsgStop.destroy()
  173. def start(self, spin=True):
  174. self.cmd_tts_stop()
  175. # 唤醒AIUI引擎
  176. logger.info("正在唤醒AIUI引擎...")
  177. self.wakeup_agent()
  178. # 等待引擎启动
  179. time.sleep(1)
  180. # 设置录音状态为允许录音
  181. logger.info("设置录音状态为允许录音...")
  182. self.recorder_states = ALLOW
  183. # 启动录音
  184. logger.info("正在启动录音...")
  185. self.start_record()
  186. if spin: # 是否阻塞运行
  187. while self.running:
  188. time.sleep(0.1)
  189. def shutdown(self):
  190. self.running = False
  191. def load_sn():
  192. return "yd-00:00:00:00:00:01"
  193. pyaiui.AIUISetting.setSystemInfo("sn", load_sn())