#!/usr/bin/env python3 #1
# encoding: utf-8 #2
# @Author: liang #3
# @Date: 2025/04/16 #4

import time #6
import rospy #7
import rosnode  #8
import threading #9
from config import * #10
from speech import awake #11
from speech import speech #12
from std_msgs.msg import Bool, Int32, String #13
from large_models.srv import SetInt32, SetInt32Response #14
from std_srvs.srv import SetBool, SetBoolResponse, Trigger, TriggerResponse #15


class VocalDetect(object): #18
    def __init__(self, name): #19
        # Initialize ROS node （初始化ROS节点） #20
        rospy.init_node(name, anonymous=False) #21

        self.running = True #23
        self.language = os.environ["ASR_LANGUAGE"] #24

        # Get parameters, use default values if not set （获取参数，如果没有设置则使用默认值） #26
        self.awake_method = rospy.get_param('~awake_method', 'xf') #27
        self.mic_type = rospy.get_param('~mic_type', 'mic6_circle') #28
        self.port = rospy.get_param('~port', '/dev/ring_mic') #29
        self.awake_word = rospy.get_param('~awake_word', 'xiao3 huan4 xiao3 huan4') #30
        self.enable_setting = rospy.get_param('~enable_setting', False) #31
        self.enable_wakeup = rospy.get_param('~enable_wakeup', True) #32
        self.mode = rospy.get_param('~mode', 1) #33

        # Initialize the corresponding object based on the wake-up method （根据唤醒方法初始化相应的对象） #35
        if self.awake_method == 'xf': #36
            # Comment out the parts related to circular microphone （注释掉环形麦克风相关的部分） #37
            # self.kws = awake.CircleMic(port, awake_word, mic_type, enable_setting) #38
            pass #39
        else: #40
            self.kws = awake.WonderEchoPro(self.port)  #41

        # Initialize ASR （初始化ASR） #43
        if self.language == 'Chinese': #44
            self.asr = speech.RealTimeASR() #45
        else: #46
            self.asr = speech.RealTimeOpenAIASR() #47
            self.asr.update_session(model=asr_model, language='en') #48
        
        # Create publisher （创建发布者） #50
        self.asr_pub = rospy.Publisher('~asr_result', String, queue_size=1) #51
        self.wakeup_pub  = rospy.Publisher('~wakeup', Bool, queue_size=1) #52
        self.awake_angle_pub = rospy.Publisher('~angle', Int32, queue_size=1) #53
        
        # Create service （创建服务） #55
        self.set_mode_service = rospy.Service('~set_mode', SetInt32, self.set_mode_srv) #56
        self.enable_wakeup_service = rospy.Service('~enable_wakeup', SetBool, self.enable_wakeup_srv) #57
        self.init_finish_service = rospy.Service('~init_finish', Trigger, self.get_node_state) #58
        
        # Start thread to handle publishing callbacks （启动线程以处理发布回调） #60
        threading.Thread(target=self.pub_callback, daemon=True).start() #61
        
        rospy.loginfo('\033[1;32m%s\033[0m' % 'VocalDetect 启动成功') #63

    def get_node_state(self, request): #65
        # Service callback: return node status （服务回调，返回节点状态） #66
        response = TriggerResponse() #67
        response.success = True #68
        response.message = "VocalDetect 正在运行中。" #69
        return response #70

    def record(self, mode, angle=None): #72
        # Start recording and perform ASR recognition （开启录音并进行ASR识别） #73
        if self.language == 'Chinese': #74
            asr_result = self.asr.asr(model=asr_model) #75
        else: #76
            asr_result = self.asr.asr() #77
        if asr_result:  #78
            speech.play_audio(dong_audio_path) #79
            if self.awake_method == 'xf' and self.mode == 1:  #80
                msg = Int32() #81
                msg.data = int(angle) #82
                self.awake_angle_pub.publish(msg) #83
            asr_msg = String() #84
            asr_msg.data = asr_result #85
            self.asr_pub.publish(asr_msg) #86
            self.enable_wakeup = False #87
            rospy.loginfo('\033[1;32m%s\033[0m' % ('publish asr result:' + asr_result)) #88
        else: #89
            rospy.loginfo('\033[1;32m%s\033[0m' % 'no voice detect') #90
            speech.play_audio(dong_audio_path) #91
            if mode != 3: #92
                speech.play_audio(no_voice_audio_path) #93


    def pub_callback(self): #96
        # Main loop for wake-up detection （唤醒检测的主循环） #97
        while self.running: #98
            if self.enable_wakeup: #99
                if self.mode == 1: #100
                    result = self.kws.wakeup() #101
                    if result: #102
                        self.wakeup_pub.publish(Bool(data=True)) #103
                        speech.play_audio(wakeup_audio_path)  # Play wake-up audio （唤醒播放） #104
                        self.record(self.mode, result) #105
                    else: #106
                        rospy.sleep(0.02) #107
                elif self.mode == 2: #108
                    self.record(self.mode) #109
                    self.mode = 0 #110
                elif self.mode == 3: #111
                    self.record(self.mode) #112
                else: #113
                    rospy.sleep(0.02) #114
            else: #115
                rospy.sleep(0.02) #116
        rospy.signal_shutdown('Stopping VocalDetect') #117

    def enable_wakeup_srv(self, request): #119
        """ #120
        Service callback: enable or disable wake-up detection （服务回调，启用或禁用唤醒检测） #121
        """ #122
        rospy.loginfo('\033[1;32m%s\033[0m' % 'enable_wakeup') #123
        self.enable_wakeup = request.data         #124
        return SetBoolResponse(success=True, message="Wakeup state set to: " + str(self.enable_wakeup)) #125

    def set_mode_srv(self, request): #127
        """ #128
        Service callback: set mode （服务回调，设置模式） #129
        """ #130
        rospy.loginfo('\033[1;32m%s\033[0m' % 'set_mode') #131
        self.mode = int(request.data) #132
        if self.mode == 2: #133
            self.enable_wakeup = True #134
        return SetInt32Response(success=True) #135


def main(): #138
    node = VocalDetect('vocal_detect') #139
    try: #140
        rospy.spin() #141
    except KeyboardInterrupt: #142
        rospy.loginfo('节点已关闭') #143


if __name__ == "__main__": #146
    main() #147
