├── LICENSE ├── README.md ├── chat_deepseek.py ├── deepseek └── config │ ├── __init__.py │ ├── device.yaml │ ├── get_remote_mqtt.py │ └── get_yaml_config.py ├── opus.dll └── requirements.txt /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Tang4109 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # python电脑版小智语音助手(直连虾哥服务器-感谢虾哥) 2 | 3 | 虾哥开源小智项目地址:https://github.com/78/xiaozhi-esp32 4 | 5 | 开发参考项目:https://github.com/zhh827/py-xiaozhi (感谢作者) 6 | 7 | 小智语音助手是一个基于Python开发的智能语音交互系统,支持实时语音对话功能。 8 | 9 | ## 功能特点 10 | 11 | - 实时语音对话 12 | - 加密音频传输 13 | - MQTT通信 14 | - 自动设备注册 15 | - TLS安全连接 16 | 17 | ## 系统要求 18 | 19 | - Python 3.7+ 20 | - Windows 10/11 21 | - 麦克风和扬声器 22 | 23 | ## 安装说明 24 | 25 | 1. 克隆项目到本地: 26 | 27 | ```bash 28 | git clone [项目地址] 29 | cd ChatBot 30 | windwos平台将opus.dll 拷贝到C:\Windows\System32 31 | ``` 32 | 33 | 2. 安装依赖: 34 | 35 | ```bash 36 | pip install -r requirements.txt 37 | ``` 38 | 39 | 注意:在Windows系统上,某些依赖可能需要额外的步骤: 40 | 41 | - PyAudio可能需要先安装Visual C++ Build Tools 42 | - opuslib可能需要手动安装opus编解码器 43 | 44 | ## 配置说明 45 | 46 | 1. 修改 `deepseek/config/device.yaml` 文件: 47 | 48 | ```yaml 49 | CONFIG_URL: 'https://api.tenclass.net/xiaozhi/ota/' 50 | DEVICE_ADDR: '你的设备MAC地址' 51 | ``` 52 | 53 | ## 使用方法 54 | 55 | 1. 运行主程序: 56 | 57 | ```bash 58 | python chat_deepseek.py 59 | 登录到控制面板地址:https://xiaozhi.me/login 60 | ``` 61 | 62 | 2. 操作说明: 63 | 64 | - 按住 F23 键进行语音对话(根据自己情况修改) 65 | - 松开 F23 键结束语音输入 66 | - 按 ESC 键退出程序 67 | 68 | ## 技术架构 69 | 70 | - 使用 MQTT 进行实时通信 71 | - 采用 AES-CTR 模式进行音频加密 72 | - 使用 Opus 编解码器进行音频压缩 73 | - PyAudio 处理音频输入输出 74 | - TLS/SSL 加密保护通信安全 75 | 76 | ## 注意事项 77 | 78 | 1. 确保设备有可用的麦克风和扬声器 79 | 2. 需要稳定的网络连接 80 | 3. 首次运行时会自动向服务器注册设备 81 | 82 | ## 许可证 83 | 84 | MIT License 85 | 86 | 本项目遵循原作者虾哥的开源项目 [xiaozhi-esp32](https://github.com/78/xiaozhi-esp32) 的 MIT 许可证,同时参考了 [py-xiaozhi](https://github.com/zhh827/py-xiaozhi) 项目的实现。 87 | 88 | 根据 MIT 许可证,您可以自由地使用、修改和分发本软件,但需要在所有副本中包含原始许可证和版权声明。 89 | 90 | 特别感谢: 91 | - 虾哥的 [xiaozhi-esp32](https://github.com/78/xiaozhi-esp32) 项目 92 | - zhh827 的 [py-xiaozhi](https://github.com/zhh827/py-xiaozhi) 项目 93 | 94 | 详细许可证内容请参见原项目:https://github.com/78/xiaozhi-esp32 95 | ## 作者 96 | - 罗辑 - 初始开发 97 | - Trae - 最新维护 98 | -------------------------------------------------------------------------------- /chat_deepseek.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created on 2025-02-27 5 | @author: 罗辑 6 | @description: chat主文件 7 | @last_modified: 2025-02-27 by Trae 8 | """ 9 | import json 10 | import time 11 | import requests 12 | import paho.mqtt.client as mqtt 13 | import threading 14 | import pyaudio 15 | import opuslib 16 | import socket 17 | from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 18 | from cryptography.hazmat.backends import default_backend 19 | import logging 20 | from pynput import keyboard as pynput_keyboard 21 | from deepseek.config.get_remote_mqtt import mqtt_info 22 | class VoiceBot: 23 | def __init__(self): 24 | # MQTT相关 25 | self.mqtt_info = {} 26 | self.mqttc = None 27 | self.aes_opus_info={} 28 | # 状态相关 29 | self.local_sequence = 0 30 | self.listen_state = None 31 | self.tts_state = None 32 | self.key_state = None 33 | self.conn_state = False 34 | 35 | # 音频相关 36 | self.audio = pyaudio.PyAudio() 37 | self.udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 38 | self.recv_audio_thread = threading.Thread() 39 | self.send_audio_thread = threading.Thread() 40 | 41 | def aes_ctr_encrypt(self, key, nonce, plaintext): 42 | # 1. 创建 AES-CTR 模式的加密器 43 | cipher = Cipher( 44 | algorithms.AES(key), # 使用AES算法,传入密钥 45 | modes.CTR(nonce), # 使用CTR模式,传入nonce(计数器初始值) 46 | backend=default_backend() # 使用默认的加密后端 47 | ) 48 | 49 | # 2. 获取加密器实例 50 | encryptor = cipher.encryptor() 51 | 52 | # 3. 加密数据 53 | return encryptor.update(plaintext) + encryptor.finalize() 54 | 55 | def aes_ctr_decrypt(self, key, nonce, ciphertext): 56 | # 1. 创建 AES-CTR 模式的解密器 57 | cipher = Cipher( 58 | algorithms.AES(key), # 使用AES算法,传入密钥 59 | modes.CTR(nonce), # 使用CTR模式,传入nonce(计数器初始值) 60 | backend=default_backend() # 使用默认的加密后端 61 | ) 62 | 63 | # 2. 获取解密器实例 64 | decryptor = cipher.decryptor() 65 | 66 | # 3. 解密数据 67 | plaintext = decryptor.update(ciphertext) + decryptor.finalize() 68 | 69 | return plaintext 70 | 71 | def transmit_audio(self): 72 | # 1. 获取配置参数 73 | key = self.aes_opus_info['udp']['key'] 74 | nonce = self.aes_opus_info['udp']['nonce'] 75 | server_ip = self.aes_opus_info['udp']['server'] 76 | server_port = self.aes_opus_info['udp']['port'] 77 | 78 | # 获取音频参数 79 | sample_rate = self.aes_opus_info['audio_params']['sample_rate'] # 采样率 80 | frame_duration = self.aes_opus_info['audio_params']['frame_duration'] # 帧时长(ms) 81 | 82 | # 计算每帧采样点数 83 | frame_size = int(sample_rate * frame_duration / 1000) # 采样率 * 帧时长(秒) 84 | # frame_size=960 85 | 86 | # 2. 初始化音频编码器和麦克风 87 | encoder = opuslib.Encoder(sample_rate, 1, opuslib.APPLICATION_AUDIO) 88 | mic = self.audio.open( 89 | format=pyaudio.paInt16, 90 | channels=1, 91 | rate=sample_rate, 92 | input=True, 93 | frames_per_buffer=frame_size # 使用计算出的帧大小 94 | ) 95 | 96 | try: 97 | while True: 98 | if self.listen_state == "stop": 99 | continue 100 | time.sleep(0.1) 101 | 102 | data = mic.read(frame_size) # 使用计算出的帧大小 103 | encoded_data = encoder.encode(data, frame_size) # 使用计算出的帧大小 104 | 105 | # 5. 生成新的nonce并加密 106 | self.local_sequence += 1 107 | # 组装新的nonce:前4字节 + 数据长度(4字节) + 中间部分 + 序列号(8字节) 108 | new_nonce = nonce[0:4] + format(len(encoded_data), '04x') + nonce[8:24] + format(self.local_sequence, '08x') 109 | 110 | # 6. 加密音频数据 111 | encrypt_encoded_data = self.aes_ctr_encrypt( 112 | bytes.fromhex(key), 113 | bytes.fromhex(new_nonce), 114 | bytes(encoded_data) 115 | ) 116 | 117 | # 7. 组装并发送数据包 118 | data = bytes.fromhex(new_nonce) + encrypt_encoded_data # nonce + 加密数据 119 | self.udp_socket.sendto(data, (server_ip, server_port)) # 发送到服务器 120 | 121 | except Exception as e: 122 | print(f"发送音频错误: {e}") 123 | finally: 124 | # 8. 清理资源 125 | self.local_sequence = 0 126 | self.udp_socket = None 127 | mic.stop_stream() 128 | mic.close() 129 | 130 | def receive_audio(self): 131 | # 1. 获取配置参数 132 | key = self.aes_opus_info['udp']['key'] # 解密密钥 133 | nonce = self.aes_opus_info['udp']['nonce'] # 加密用的 nonce 134 | sample_rate = self.aes_opus_info['audio_params']['sample_rate'] # 采样率 135 | frame_duration = self.aes_opus_info['audio_params']['frame_duration'] # 帧时长 136 | frame_num = int(frame_duration / (1000 / sample_rate)) # 计算每帧样本数 137 | 138 | # 2. 初始化音频解码器和播放器 139 | decoder = opuslib.Decoder(sample_rate, 1) # Opus 解码器 140 | spk = self.audio.open( # 打开音频输出流 141 | format=pyaudio.paInt16, # 16位音频格式 142 | channels=1, # 单声道 143 | rate=sample_rate, # 采样率 144 | output=True, # 输出模式 145 | frames_per_buffer=frame_num # 缓冲区大小 146 | ) 147 | 148 | try: 149 | while True: 150 | # 3. 接收加密的音频数据 151 | data, server = self.udp_socket.recvfrom(4096) # 从UDP接收数据,4096(4KB)是一个比较常见的缓冲区大小 152 | encrypt_encoded_data = data 153 | 154 | # 4. 解密过程 155 | # 分离nonce(前16字节)和加密数据 156 | split_encrypt_encoded_data_nonce = encrypt_encoded_data[:16] 157 | split_encrypt_encoded_data = encrypt_encoded_data[16:] 158 | 159 | # 5. 解密:将加密的数据还原为原始的 Opus 编码数据 160 | decrypt_data = self.aes_ctr_decrypt( 161 | bytes.fromhex(key), 162 | split_encrypt_encoded_data_nonce, 163 | split_encrypt_encoded_data 164 | ) 165 | 166 | # 6. 解码:将 Opus 编码的音频数据解码为原始的PCM音频数据 167 | pcm_audio = decoder.decode(decrypt_data, frame_num) 168 | 169 | # 7. 播放:将PCM音频数据写入音频设备 170 | spk.write(pcm_audio) 171 | 172 | except Exception as e: 173 | print(f"接收音频错误: {e}") 174 | finally: 175 | # 8. 清理资源 176 | self.udp_socket = None 177 | spk.stop_stream() 178 | spk.close() 179 | 180 | def handle_mqtt_connect(self, client, userdata, flags, rc, properties=None): 181 | """ 182 | MQTT连接成功的回调函数 183 | 184 | Args: 185 | client: MQTT客户端实例 186 | userdata: 用户定义的数据 187 | flags: 包含broker返回的标志的字典 188 | rc: 连接结果的返回码(0表示连接成功) 189 | properties: MQTT v5 的连接属性 190 | """ 191 | print("连接服务器成功,请按住对话键开始聊天吧^_^") 192 | 193 | def handle_mqtt_message(self, client, userdata, message, properties=None): 194 | """ 195 | 处理接收到的MQTT消息的回调函数 196 | 197 | Args: 198 | client: MQTT客户端实例 199 | userdata: 用户定义的数据 200 | message: 收到的消息对象,包含主题(topic)和负载(payload) 201 | properties: MQTT v5 的消息属性 202 | """ 203 | msg = json.loads(message.payload) # 解析收到的JSON消息 204 | # print(msg) 205 | # 只输出 llm 类型的消息中的 text 206 | if 'text' in msg and msg.get('type') == 'tts' and msg.get('state')=='sentence_start': 207 | print(f"小智: {msg['text']}") 208 | if 'text' in msg and msg.get('type') == 'stt': 209 | print(f"我: {msg['text']}") 210 | 211 | # 1. 处理hello消息:服务器确认连接 212 | if msg['type'] == 'hello': 213 | self.aes_opus_info = msg # # 用服务器返回的配置更新aes_opus_info 214 | self.udp_socket.connect((msg['udp']['server'], msg['udp']['port'])) # 建立UDP连接 215 | self.conn_state = True # 更新连接状态 216 | 217 | # 启动接收音频线程(如果未启动) 218 | if not self.recv_audio_thread.is_alive(): 219 | self.recv_audio_thread = threading.Thread(target=self.receive_audio) # target 参数指定线程要执行的函数,self.receive_audio 是传递函数引用 220 | self.recv_audio_thread.start() #在创建线程时,我们传递函数引用而不是执行函数,让线程在启动时(调用 start() 方法时)才执行该函数。 221 | else: 222 | print("接收音频线程正在运行") 223 | 224 | # 启动发送音频线程(如果未启动) 225 | if not self.send_audio_thread.is_alive(): 226 | self.send_audio_thread = threading.Thread(target=self.transmit_audio) # target 参数指定线程要执行的函数 227 | self.send_audio_thread.start() 228 | else: 229 | print("发送音频线程正在运行") 230 | 231 | # 2. 处理TTS状态消息 232 | if msg['type'] == 'tts': 233 | self.tts_state = msg['state'] # 更新TTS播放状态 234 | 235 | # 3. 处理goodbye消息:结束会话 236 | if (msg['type'] == 'goodbye' and 237 | self.udp_socket and 238 | 'session_id' in msg and 239 | 'session_id' in self.aes_opus_info and 240 | msg['session_id'] == self.aes_opus_info['session_id']): 241 | 242 | print(f"收到结束会话消息") 243 | self.aes_opus_info['session_id'] = None # 清除会话ID 244 | 245 | def publish_mqtt_message(self, message): 246 | """发布MQTT消息到指定主题""" 247 | # 如果消息中包含text字段,则输出 248 | if 'text' in message: 249 | print(f">>> {message['text']}") 250 | self.mqttc.publish( 251 | self.mqtt_info['publish_topic'], 252 | json.dumps(message) 253 | ) 254 | 255 | def handle_voice_input_start(self, event): 256 | """ 257 | 处理开始语音输入的事件(当用户按下触发键时) 258 | 259 | Args: 260 | event: 键盘事件对象 261 | """ 262 | if self.key_state == "press": 263 | return 264 | self.key_state = "press" 265 | 266 | # 判断是否需要发送hello消息建立连接 267 | if self.conn_state is False or not self.aes_opus_info.get('session_id'): 268 | # 构造并发送hello消息,建立UDP连接 269 | hello_msg = { 270 | "type": "hello", 271 | "version": 3, 272 | "transport": "udp", 273 | "audio_params": { 274 | "format": "opus", 275 | "sample_rate": 16000, 276 | "channels": 1, 277 | "frame_duration": 60 278 | } 279 | } 280 | self.publish_mqtt_message(hello_msg) 281 | # print(f"发送hello消息: {hello_msg}") 282 | # 等待服务器的hello响应 283 | return # 等待服务器hello响应后再继续 284 | 285 | # 如果正在播放TTS,发送abort消息中断播放 286 | if self.tts_state == "start" or self.tts_state == "sentence_start": 287 | abort_msg = {"type": "abort"} 288 | self.publish_mqtt_message(abort_msg) 289 | print(f"发送中断消息:{abort_msg}") 290 | 291 | # 发送开始监听消息 292 | msg = { 293 | "session_id": self.aes_opus_info['session_id'], 294 | "type": "listen", 295 | "state": "start", 296 | "mode": "manual" 297 | } 298 | self.publish_mqtt_message(msg) 299 | 300 | def handle_voice_input_end(self, event): 301 | """ 302 | 处理结束语音输入的事件(当用户释放触发键时) 303 | 304 | Args: 305 | event: 键盘事件对象 306 | """ 307 | self.key_state = "release" 308 | 309 | # 检查是否有有效的会话 310 | if not self.aes_opus_info.get('session_id'): 311 | return # 如果没有有效的会话ID,直接返回 312 | 313 | # 发送停止监听消息 314 | msg = { 315 | "session_id": self.aes_opus_info['session_id'], 316 | "type": "listen", 317 | "state": "stop" 318 | } 319 | # print(f"发送停止监听消息: {msg}") 320 | self.publish_mqtt_message(msg) 321 | 322 | def on_press(self, key): 323 | """ 324 | 键盘按键按下事件的回调函数 325 | 326 | Args: 327 | key: pynput自动传入的按键对象,可能是以下两种类型: 328 | 1. pynput.keyboard.Key: 特殊键(如空格、ESC等) 329 | 2. pynput.keyboard.KeyCode: 字符键(如字母、数字等) 330 | """ 331 | #改用空格键 332 | # if key == pynput_keyboard.Key.space: 333 | # self.handle_voice_input_start(None) 334 | if key == pynput_keyboard.Key.f23: 335 | self.handle_voice_input_start(None) 336 | # 如果要使用字符键,可以这样: 337 | # if hasattr(key, 'char') and key.char == 'a': 338 | # self.handle_voice_input_start(None) 339 | 340 | def on_release(self, key): 341 | """ 342 | 键盘按键释放事件的回调函数 343 | 344 | Args: 345 | key: 同上,pynput自动传入的按键对象 346 | """ 347 | # if key == pynput_keyboard.Key.space: 348 | # self.handle_voice_input_end(None) 349 | if key == pynput_keyboard.Key.f23: 350 | self.handle_voice_input_end(None) 351 | if key == pynput_keyboard.Key.esc: 352 | return False # 返回False会停止监听 353 | 354 | def initialize_mqtt_client(self): 355 | """初始化MQTT客户端配置""" 356 | # 创建 MQTT v5 客户端 357 | self.mqttc = mqtt.Client( 358 | client_id=self.mqtt_info['client_id'], 359 | protocol=mqtt.MQTTv5, # 指定使用 MQTT v5 协议 360 | callback_api_version=mqtt.CallbackAPIVersion.VERSION2 # 明确指定使用 V2 回调 API 361 | ) 362 | 363 | # 设置回调函数 364 | self.mqttc.on_connect = self.handle_mqtt_connect 365 | self.mqttc.on_message = self.handle_mqtt_message 366 | 367 | # 1. 配置 MQTT 客户端的 TLS/SSL 加密连接参数:是客户端对服务器连接的要求和期望 368 | self.mqttc.tls_set( 369 | ca_certs=None, # 使用系统的 CA 证书来验证服务器 370 | certfile=None, # 客户端不提供证书 371 | keyfile=None, # 客户端不提供密钥 372 | cert_reqs=mqtt.ssl.CERT_REQUIRED, # 要求服务器必须提供有效证书 373 | tls_version=mqtt.ssl.PROTOCOL_TLS, # 要求服务器使用现代 TLS 协议 374 | ciphers=None # 接受默认的加密算法 375 | ) 376 | # 2. 使用用户名密码进行身份验证 377 | self.mqttc.username_pw_set( 378 | username=self.mqtt_info['username'], 379 | password=self.mqtt_info['password'] 380 | ) 381 | 382 | # 3. 连接到加密的 MQTT 端口(8883是标准的 MQTT over TLS 端口) 383 | self.mqttc.connect(host=self.mqtt_info['endpoint'], port=8883) # 连接到MQTT服务器:服务器地址,从配置中获取,8883-使用标准的 MQTT over TLS 端口 384 | self.mqttc.loop_forever() # 开始消息循环 385 | ''' 386 | 启动一个永久运行的消息循环 387 | 作用: 388 | 保持与服务器的连接 389 | 自动处理消息的收发 390 | 处理所有回调函数(on_connect, on_message 等) 391 | 自动重连(如果连接断开) 392 | 这是一个阻塞调用,会一直运行直到程序结束 393 | ''' 394 | 395 | def start(self): 396 | """启动语音机器人服务""" 397 | self.mqtt_info=mqtt_info 398 | # 创建监听器时,指定回调函数 399 | listener = pynput_keyboard.Listener( 400 | on_press=self.on_press, # 不需要手动传参,pynput会自动传入key 401 | on_release=self.on_release # 不需要手动传参,pynput会自动传入key 402 | ) 403 | listener.start() 404 | 405 | self.initialize_mqtt_client() 406 | 407 | 408 | if __name__ == "__main__": 409 | voicebot = VoiceBot() 410 | voicebot.start() 411 | -------------------------------------------------------------------------------- /deepseek/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tang4109/ChatBot/2bab2dd9edfbf3f007733dcca0acdd5066599820/deepseek/config/__init__.py -------------------------------------------------------------------------------- /deepseek/config/device.yaml: -------------------------------------------------------------------------------- 1 | # 用于检查更新的服务器地址 2 | CONFIG_URL: 'https://api.tenclass.net/xiaozhi/ota/' 3 | # 设备MAC 4 | DEVICE_ADDR: 'f7:e1:3b:12:a8:d5' #自己随机设置一个类似格式的地址 -------------------------------------------------------------------------------- /deepseek/config/get_remote_mqtt.py: -------------------------------------------------------------------------------- 1 | """ 2 | Created on 2025-02-27 3 | @author: 罗辑 4 | @description: mqtt读取模块 5 | @last_modified: 2025-02-27 by Trae 6 | """ 7 | import requests 8 | import json 9 | import logging 10 | from deepseek.config.get_yaml_config import config 11 | 12 | def get_mqtt_info(): 13 | """获取配置信息和MQTT连接参数""" 14 | header = { 15 | 'Device-Id': config['DEVICE_ADDR'], # 设备标识符,使用MAC地址作为唯一标识 16 | 'Content-Type': 'application/json' # 指定请求体的数据格式为JSON 17 | } 18 | 19 | post_data = { 20 | "application": { # 应用程序信息 21 | "name": "xiaozhi", # 应用程序名称,这里是"小智" 22 | "version": "0.9.9" # 应用程序版本号 23 | }, 24 | "board": { # 设备信息 25 | "type": "pc-client", # 设备类型,这里表示是PC客户端 26 | "mac": config['DEVICE_ADDR'] # 设备的MAC地址,用于唯一标识设备 27 | } 28 | } 29 | # 发送POST请求获取配置 30 | response = requests.post(config['CONFIG_URL'], headers=header, data=json.dumps(post_data)) 31 | # 从响应中提取MQTT配置信息 32 | mqtt_info = response.json()['mqtt'] 33 | ''' 34 | 这个过程的作用是: 35 | 设备注册:向服务器注册设备信息 36 | 获取配置:获取MQTT连接所需的所有参数 37 | 身份验证:通过MAC地址验证设备身份 38 | 版本控制:上报当前版本,服务器可以决定是否需要更新 39 | 这是整个系统的初始化步骤,为后续的MQTT连接和音频传输做准备。 40 | ''' 41 | return mqtt_info 42 | mqtt_info = get_mqtt_info() 43 | -------------------------------------------------------------------------------- /deepseek/config/get_yaml_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: UTF-8 -*- 3 | """ 4 | Created on 2025-02-27 5 | @author: 罗辑 6 | @description: YAML配置文件读取模块 7 | @last_modified: 2025-02-27 by Trae 8 | """ 9 | import yaml 10 | import os 11 | 12 | def get_yaml_config(file_name): 13 | """读取yaml配置文件""" 14 | config_path = os.path.join(os.path.dirname(__file__), file_name) 15 | with open(config_path, 'r', encoding='utf-8') as f: 16 | config = yaml.safe_load(f) 17 | return config 18 | 19 | config = get_yaml_config('device.yaml') 20 | # print(config) 21 | -------------------------------------------------------------------------------- /opus.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tang4109/ChatBot/2bab2dd9edfbf3f007733dcca0acdd5066599820/opus.dll -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | paho-mqtt>=1.6.1 2 | pyaudio>=0.2.13 3 | opuslib>=3.0.1 4 | pynput>=1.7.6 5 | requests>=2.31.0 6 | pyyaml>=6.0.1 7 | cryptography>=41.0.0 --------------------------------------------------------------------------------