Вывод текста записанного с микрофона, Python, Vosk

Имеется код небольшой программы, которая должна распознавать речь и переводить её в текст.

Всё хорошо работает за исключением того, что после того как текст высвечивается на экране, через пару секунд он исчезает/обновляется, а мне надо чтобы он оставался.
После нажатия кнопки end запись должна прекратиться.

main.py:

from gui import Ui_Dialog
from PyQt5 import QtWidgets
from vosk import Model, KaldiRecognizer

import pyaudio
import threading


import time


CHUNK = 1024  # определяет форму ауди сигнала
FRT = pyaudio.paInt16  # шестнадцатибитный формат задает значение амплитуды
CHAN = 1  # канал записи звука
RT = 44100  # частота
sec = 0
REC_SEC = 5  # длина записи
OUTPUT = "output.wav"
a = 50


class GuiProgram(Ui_Dialog):
    """ Класс контроллер - интерпретирует действия пользователя """

    def __init__(self, dialog: QtWidgets.QDialog) -> None:
        """ Вызывается при создании нового объекта класса """
        # Создание окна
        Ui_Dialog.__init__(self)
        # Установка пользовательского интерфейс
        self.setupUi(dialog)
        # Обработка нажатий клавиш
        self.strt_btn.clicked.connect(self.start_record)
        self.end_btn.clicked.connect(self.end_record)
        self.stream = None
        self.start_record = False
        self.frames = []
        self.pyaudio = pyaudio.PyAudio()
        self.xte = None

    def start_record(self):
        self.label.setText("Recording...")

        model = Model(r"vosk-model-small-ru-0.22")
        self.rec = KaldiRecognizer(model, 44100)
        self.pyaudio = pyaudio.PyAudio()
        self.stream = self.pyaudio.open(
            format=FRT,
            channels=CHAN,
            rate=RT,
            input=True,
            frames_per_buffer=CHUNK
        )
        self.start_record = True

        self.thread = threading.Thread(target=self.record)
        self.thread.start()

    def record(self):
        while self.start_record:
            data = self.stream.read(44100)
            if len(data) == 0:
                break

            self.label.setText(self.rec.Result()
                               if self.rec.AcceptWaveform(data)
                               else self.rec.PartialResult())

            self.xte = (self.rec.Result()
                               if self.rec.AcceptWaveform(data)
                               else self.rec.PartialResult())

        self.label.setText(self.rec.FinalResult())

    def end_record(self):
        self.start_record = False
        print("done")
        self.label.setText(self.xte)

Ответы (1 шт):

Автор решения: S. Nick

У меня не получилось проверить ваш код.
Строка model = Model(r"vosk-model-small-ru-0.22")
меня отругала: Folder 'vosk-model-en-us-0.22' does not contain model files...

И я не знаю все ли хорошо у вас работает, но я точно знаю, что взаимодействие с виджетами в дополнительном потоке не рекомендуется, т.к. это не безопасно.

Я не понимаю, почему вы решили отображать текст в виджете QLabel?
в котором setText(const QString &) удаляет все предыдущее содержимое.

Мне кажется, что ваш код должен выглядеть примерно так, проверьте.

import sys
from PyQt5 import QtWidgets, QtGui, QtCore  
from PyQt5.Qt import *

from vosk import Model, KaldiRecognizer                     # pip install vosk
import pyaudio


CHUNK = 1024           # определяет форму ауди сигнала
FRT = pyaudio.paInt16  # шестнадцатибитный формат задает значение амплитуды
CHAN = 1               # канал записи звука
RT = 44100             # частота
sec = 0                # ???
REC_SEC = 5            # длина записи
OUTPUT = "output.wav"  # ???
a = 50                 # ???


class RecordingThread(QThread):
    recorded_text = pyqtSignal(str)

    def __init__(self, stream, rec):
        super().__init__()
        self.stream = stream 
        self.rec = rec
        self.flag_record = True        
        self.xte = None                                              # ???
        
    def run(self):
        while self.flag_record:
            data = self.stream.read(44100)
            if not data:
                # нет данных
                self.recorded_text.emit(f'Нет данных ?')
            else:  
                self.xte = self.rec.Result() \
                    if self.rec.AcceptWaveform(data) \
                    else self.rec.PartialResult()
                self.recorded_text.emit(f'{self.xte}')
                
            self.msleep(100) # 100 мс, я не знаю какая пауза здесь нужна?  


class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        
        self.stream = None                # ?
        self.flag_record = False          # ?
        self.frames = []                  # ?
        self.pyaudio = pyaudio.PyAudio()
 
        self.start_btn = QPushButton('? Start')
        self.start_btn.setFont(QFont('Arial', 16))
        self.start_btn.clicked.connect(self.start_record)
        
        self.end_btn = QPushButton('? Stop')
        self.end_btn.setFont(QFont('Arial', 16))
        self.end_btn.setEnabled(False)
        self.end_btn.clicked.connect(self.end_record)

        self.result = QPlainTextEdit()
        self.result.setFont(QFont('Arial', 12))
        self.result.setReadOnly(True)
        
        layout = QGridLayout(self)
        layout.addWidget(self.start_btn, 0, 0)
        layout.addWidget(self.end_btn, 0, 1)
        layout.addWidget(self.result, 1, 0, 1, 2)

    def start_record(self):
        self.result.appendPlainText("Recording...")
        self.start_btn.setEnabled(False)
        self.end_btn.setEnabled(True)   

        model = Model(r"vosk-model-small-ru-0.22")
        
        self.rec = KaldiRecognizer(model, 44100)
        self.pyaudio = pyaudio.PyAudio()
        self.stream = self.pyaudio.open(
            format=FRT,
            channels=CHAN,
            rate=RT,
            input=True,
            frames_per_buffer=CHUNK
        )

        self.thread = RecordingThread(self.stream, self.rec)
        self.thread.recorded_text.connect(self.result.appendPlainText)
        self.thread.start()

    def end_record(self):
        self.thread.flag_record = False
        self.result.appendPlainText("End Recording.\n")
        self.start_btn.setEnabled(True)
        self.end_btn.setEnabled(False)
        
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = MainWindow()
    w.resize(500, 400)
    w.show()
    sys.exit(app.exec())

введите сюда описание изображения

→ Ссылка