#!/usr/bin/env python3 # coding=utf-8 from utils.logger import logger from core.aiui.recorder import Recorder import handlers.aiui.pyaiui as pyaiui from handlers.aiui.pyAIUIConstant import AIUIConstant import json5 import os import sys import random import json from threading import Thread import time from handlers.aiui.EventListener import EventListener, EventData from pathlib import Path CHUNK = 2048 # 使用相对路径配置 script_path = Path(__file__).resolve() BASE_DIR = script_path.parent.parent.parent cfg_file = os.path.join(BASE_DIR, "config", "aiui", "cfg", "aiui.cfg") WAITING = 0 ABORT = -1 ALLOW = 1 def read_json5(path): try: with open(path, "r", encoding="utf-8") as f: return json5.loads(f.read()) except Exception as e: logger.error("{},{}".format(e, __file__)) return None class AIUINode(): def __init__(self, event_listener, debug=False, wakeup_mute=False): self.agent_status = None event_listener.set_agent(self) self.event_listener = event_listener self.agent = pyaiui.IAIUIAgent.createAgent(json5.dumps( read_json5(cfg_file), quote_keys=True), event_listener) self.__recorder_ = None self.is_recording = False self.recorder_states = WAITING # -1:中断状态;0:等待状态;1:允许录音状态 self.wakeup_mute = wakeup_mute self.is_hlw = False self.set_is_hlw() self.running = True def text_to_speak_multiple_options_callback(self, text, vcn="qige", speed=50, pitch=50, volume=50): self.cmd_tts(text, vcn, speed, pitch, volume) return True def direct_control_callback(self, text): self.event_listener.EventNLP(EventData({"text": text})) return True def text_to_speak_callback(self, text): self.cmd_tts(text) return True def set_is_hlw(self): # 简化HLW检测逻辑 self.is_hlw = False def cmd_tts(self, text, vcn="qige", speed=50, pitch=50, volume=50): text = pyaiui.Buffer.create(bytes(text, encoding="utf-8")) TTSMsg = pyaiui.IAIUIMessage.create( AIUIConstant.CMD_TTS, 1, 0, "text_encoding=utf-8,vcn={},ent=x,speed={},pitch={},volume={}".format(vcn, speed, pitch, volume), text) self.agent.sendMessage(TTSMsg) TTSMsg.destroy() def cmd_tts_stop(self): text = pyaiui.Buffer.create(bytes("", encoding="utf-8")) TTSMsg = pyaiui.IAIUIMessage.create( AIUIConstant.CMD_TTS, 2, 0, "text_encoding=utf-8,vcn=qige,ent=x", text) self.agent.sendMessage(TTSMsg) TTSMsg.destroy() def wakeup_callback(self, msg=None): self.recorder_states = ABORT # 中断上一次录音等待 self.getState() if self.is_recording: self.reset_wakeup_agent() self.is_recording = False if self.agent_status != AIUIConstant.STATE_WORKING: self.wakeup_agent() # 简化唤醒处理,直接开始录音 logger.info("🎤 AIUI唤醒,开始录音") self.recorder_states = ALLOW # 直接允许录音 Thread(target=self.__wait_play_to_start_record).start() def __wait_play_to_start_record(self): # 简化等待逻辑,直接开始录音 self.recorder_states = ALLOW # 直接赋值允许录音 self.start_record() def start_record(self): logger.info("开始录音...") self.is_recording = True if self.is_hlw == False: logger.info("启动非HLW录音模式") # 使用连续录音循环 import threading threading.Thread(target=self.__continuous_record, daemon=True).start() else: logger.info("HLW录音模式已启用") @property def __recorder(self): if self.__recorder_ == None: self.__recorder_ = Recorder(CHUNK) return self.__recorder_ def __start_record(self): """单次录音会话""" logger.info("录音流已启动,开始接收音频数据...") audio_count = 0 for data in self.__recorder.read(): if self.is_recording: audio_count += 1 if audio_count % 100 == 0: # 每100个音频块记录一次 logger.info(f"已接收 {audio_count} 个音频块") self.audio_stream_callback(data) else: logger.info("录音已停止") break logger.info(f"录音流结束,总共接收 {audio_count} 个音频块") def __continuous_record(self): """连续录音循环""" while self.running and self.recorder_states == ALLOW: self.is_recording = True self.__start_record() # 录音结束后短暂等待 if self.running and self.recorder_states == ALLOW: logger.info("等待重新开始录音...") time.sleep(1) def audio_stream_callback(self, data): if self.is_recording: if self.is_hlw: audio_buffer = pyaiui.Buffer.create(data.data) self.record_stream_call_back(data.data) else: audio_buffer = pyaiui.Buffer.create(data) self.record_stream_call_back(data) self.cmd_write_audio(audio_buffer) else: logger.debug("录音已停止,跳过音频数据处理") def record_stream_call_back(self, buffer): pass def wakeup_agent(self): wakeup_msg = pyaiui.IAIUIMessage.create(AIUIConstant.CMD_WAKEUP) self.agent.sendMessage(wakeup_msg) wakeup_msg.destroy() def reset_wakeup_agent(self): reset_wakeup_msg = pyaiui.IAIUIMessage.create( AIUIConstant.CMD_RESET_WAKEUP) self.agent.sendMessage(reset_wakeup_msg) reset_wakeup_msg.destroy() def getState(self): get_state_msg = pyaiui.IAIUIMessage.create(AIUIConstant.CMD_GET_STATE) self.agent.sendMessage(get_state_msg) get_state_msg.destroy() def cmd_write_audio(self, audio_buffer): writeMsg = pyaiui.IAIUIMessage.create( AIUIConstant.CMD_WRITE, 0, 0, "data_type=audio", audio_buffer) self.agent.sendMessage(writeMsg) writeMsg.destroy() # 添加调试日志,每1000个音频块记录一次 if hasattr(self, '_audio_sent_count'): self._audio_sent_count += 1 else: self._audio_sent_count = 1 if self._audio_sent_count % 1000 == 0: logger.info(f"已发送 {self._audio_sent_count} 个音频块给AIUI引擎") def cmd_write_text(self, text): text = pyaiui.Buffer.create(bytes(text, encoding="utf-8")) writeMsg = pyaiui.IAIUIMessage.create( AIUIConstant.CMD_WRITE, 0, 0, "data_type=text", text) self.agent.sendMessage(writeMsg) writeMsg.destroy() def stop_write(self): writeMsgStop = pyaiui.IAIUIMessage.create( AIUIConstant.CMD_STOP_WRITE, params="data_type=audio") self.agent.sendMessage(writeMsgStop) writeMsgStop.destroy() def start(self, spin=True): self.cmd_tts_stop() # 唤醒AIUI引擎 logger.info("正在唤醒AIUI引擎...") self.wakeup_agent() # 等待引擎启动 time.sleep(1) # 设置录音状态为允许录音 logger.info("设置录音状态为允许录音...") self.recorder_states = ALLOW # 启动录音 logger.info("正在启动录音...") self.start_record() if spin: # 是否阻塞运行 while self.running: time.sleep(0.1) def shutdown(self): self.running = False def load_sn(): return "yd-00:00:00:00:00:01" pyaiui.AIUISetting.setSystemInfo("sn", load_sn())