使用pyqt5 pyserial TTS模型vosk开发的语音串口工具

项目概述

这是一个集成了语音识别和串口通信功能的智能控制工具,旨在通过自然语言语音指令实现对硬件设备的远程控制。该工具采用pyqt5 GUI 界面设计,支持多种串口参数配置,能够实时识别语音指令并通过串口发送控制设备的指令集命令。

核心功能

1、智能语音识别:集成 Vosk 本地语音识别引擎,支持离线使用
2、灵活的串口配置:支持波特率、校验位、停止位、流控制等完整参数设置
3、实时状态显示:动态显示识别过程和系统状态
4、历史记录查看:完整记录所有识别结果和操作日志
5、用户友好界面:采用 PyQt5 构建的图形界面

代码如下:

主程序入口
import sys
from PyQt5.QtWidgets import QApplication
from ui import MainWindow

#主程序入口

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())
语音识别具体实现
import vosk
import pyaudio
from PyQt5.QtCore import pyqtSignal, QThread

#VOSK语音识别模块

class SpeechRecognitionThread(QThread):
    recognized_signal = pyqtSignal(str)
    current_text_signal = pyqtSignal(str)

    def __init__(self, serial_connection, model_path):
        super().__init__()
        self.serial_connection = serial_connection
        self.model_path = 'model/voskmodelsmallcn'
        self.stop_flag = False

    def run(self):
        try:
            model = vosk.Model(self.model_path)
            recognizer = vosk.KaldiRecognizer(model, 16000)
            recognizer.SetWords(True)

            p = pyaudio.PyAudio()
            stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, frames_per_buffer=4000)

            while not self.stop_flag:
                data = stream.read(4000)
                if recognizer.AcceptWaveform(data):
                    result = recognizer.Result()
                    self.recognized_signal.emit(result)
                    self.process_command(result)
                else:
                    partial_result = recognizer.PartialResult()
                    self.current_text_signal.emit(partial_result)

            stream.stop_stream()
            stream.close()
            p.terminate()

        except Exception as e:
            self.recognized_signal.emit(f"语音识别错误: {str(e)}")

    def stop(self):
        self.stop_flag = True

    def process_command(self, result):
        command = result.lower()
        if "打开 冻结" in command:
            self.send_serial_command("\x02OFZ:1\x03")
        elif "关闭 冻结" in command:
            self.send_serial_command("\x02OFZ:0\x03")

    def send_serial_command(self, command):
        try:
            if self.serial_connection and self.serial_connection.is_open:
                self.serial_connection.write(command.encode())
                self.recognized_signal.emit(f"发送指令: {command}")
            else:
                self.recognized_signal.emit("串口未打开")
        except Exception as e:
            self.recognized_signal.emit(f"发送指令错误: {str(e)}")
GUI界面
from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QWidget, QLabel, QPushButton, QLineEdit, QComboBox, QTextEdit
from PyQt5.QtCore import QCoreApplication
from serial_config import SerialConfig
from speech_recognition import SpeechRecognitionThread
import serial
import serial.tools.list_ports

# UI模块

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("语音控制工具")
        self.setGeometry(200, 200, 500, 400)

        self.serial_config = SerialConfig()
        self.serial_connection = None

        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout()

        self.port_label = QLabel("串口号:")
        self.layout.addWidget(self.port_label)

        self.port_input = QComboBox()
        self.layout.addWidget(self.port_input)
        self.populate_ports()

        self.baudrate_label = QLabel("波特率:")
        self.layout.addWidget(self.baudrate_label)

        self.baudrate_input = QLineEdit("19200")
        self.layout.addWidget(self.baudrate_input)

        self.parity_label = QLabel("效验位:")
        self.layout.addWidget(self.parity_label)

        self.parity_input = QComboBox()
        self.parity_input.addItems(["None", "Even", "Odd"])
        self.layout.addWidget(self.parity_input)

        self.stopbits_label = QLabel("停止位:")
        self.layout.addWidget(self.stopbits_label)

        self.stopbits_input = QComboBox()
        self.stopbits_input.addItems(["1", "1.5", "2"])
        self.layout.addWidget(self.stopbits_input)

        self.flowcontrol_label = QLabel("流控制:")
        self.layout.addWidget(self.flowcontrol_label)

        self.flowcontrol_input = QComboBox()
        self.flowcontrol_input.addItems(["None", "Xon/Xoff", "RTS/CTS", "DTR/DSR"])
        self.layout.addWidget(self.flowcontrol_input)

        self.start_button = QPushButton("开始语音识别")
        self.start_button.clicked.connect(self.start_recognition)
        self.layout.addWidget(self.start_button)

        self.stop_button = QPushButton("停止语音识别")
        self.stop_button.clicked.connect(self.stop_recognition)
        self.layout.addWidget(self.stop_button)

        self.status_label = QLabel("状态: 等待开始")
        self.layout.addWidget(self.status_label)

        self.output_text = QTextEdit()
        self.output_text.setReadOnly(True)
        self.layout.addWidget(self.output_text)

        container = QWidget()
        container.setLayout(self.layout)
        self.setCentralWidget(container)

    def populate_ports(self):
        try:
            ports = serial.tools.list_ports.comports()
            for port in ports:
                self.port_input.addItem(port.device)
        except Exception as e:
            self.status_label.setText(f"串口获取错误: {str(e)}")

    def start_recognition(self):
        try:
            self.serial_config.port = self.port_input.currentText()
            self.serial_config.baudrate = int(self.baudrate_input.text())
            self.serial_config.parity = self.get_parity(self.parity_input.currentText())
            self.serial_config.stopbits = self.get_stopbits(self.stopbits_input.currentText())
            self.serial_config.flowcontrol = self.get_flowcontrol(self.flowcontrol_input.currentText())

            self.serial_connection = serial.Serial(self.serial_config.port, self.serial_config.baudrate,
                                                   parity=self.serial_config.parity,
                                                   stopbits=self.serial_config.stopbits,
                                                   bytesize=self.serial_config.bytesize, timeout=1)

            self.status_label.setText(f"状态: 串口 {self.serial_config.port} 已打开")

            model_path = "model/voskmodelsmallcn"  # 本地模型路径
            self.recognition_thread = SpeechRecognitionThread(self.serial_connection, model_path)
            self.recognition_thread.recognized_signal.connect(self.update_output)
            self.recognition_thread.current_text_signal.connect(self.update_status)
            self.recognition_thread.start()
        except Exception as e:
            self.status_label.setText(f"启动识别错误: {str(e)}")

    def stop_recognition(self):
        try:
            if self.recognition_thread:
                self.recognition_thread.stop()
                self.recognition_thread.wait()
            if self.serial_connection and self.serial_connection.is_open:
                self.serial_connection.close()
            self.status_label.setText("状态: 语音识别已停止")
        except Exception as e:
            self.status_label.setText(f"停止识别错误: {str(e)}")

        QCoreApplication.quit()

    def update_status(self, text):
        self.status_label.setText(f"当前识别: {text}")

    def update_output(self, text):
        self.output_text.append(text)

    def get_parity(self, parity):
        if parity == "None":
            return serial.PARITY_NONE
        elif parity == "Even":
            return serial.PARITY_EVEN
        elif parity == "Odd":
            return serial.PARITY_ODD

    def get_stopbits(self, stopbits):
        if stopbits == "1":
            return serial.STOPBITS_ONE
        elif stopbits == "1.5":
            return serial.STOPBITS_ONE_POINT_FIVE
        elif stopbits == "2":
            return serial.STOPBITS_TWO

    def get_flowcontrol(self, flowcontrol):
        if flowcontrol == "None":
            return False
        elif flowcontrol == "Xon/Xoff":
            return serial.XONXOFF
        elif flowcontrol == "RTS/CTS":
            return serial.RTSCTS
        elif flowcontrol == "DTR/DSR":
            return serial.DTRDSR

Serial配置界面
import serial

#配置串口

class SerialConfig:
    def __init__(self):
        self.port = None
        self.baudrate = 19200
        self.parity = serial.PARITY_NONE
        self.stopbits = serial.STOPBITS_ONE
        self.flowcontrol = False
        self.bytesize = 8  # 数据位,默认8
posted @ 2025-11-03 14:08  小神龙_007  阅读(6)  评论(0)    收藏  举报