即使在线程中使用 pyttsx3 时,pyQt5 的执行也会停止
pyQt5 execution stops when using pyttsx3 even with Threading
您好,实际上我正在编写一个应提供 GUI 以及语音识别命令的应用程序,该程序应以 TTS 格式回答。我写了一个小测试程序,因为我想用 pyQt5 学习线程,因为它需要保持 GUI 响应 - 这是我到目前为止的理解,它似乎工作除非它尝试 TTS。
现在我遇到了一个问题,只要我不输入 TTS,一切正常。但是对于 pyttsx3,.runAndWait() 函数会退出我的代码的执行。
这是有问题的代码:(GUI 有滑块来检查线程是否有效)
import sys
import speech_recognition as sr
import pyttsx3
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
recognizer = sr.Recognizer()
speaker = pyttsx3.init()
voices = speaker.getProperty('voices')
# speaker.setProperty('voice', voices[33].id)
# speaker.setProperty('rate', 190)
class DlgMain(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("Test")
self.btnStart = QPushButton("Start")
self.btnStart.clicked.connect(self.evt_btnStart_clicked)
self.dial = QSlider()
self.lcd = QLCDNumber()
self.dial.valueChanged.connect(self.lcd.display)
self.lytLCD = QHBoxLayout()
self.lytLCD.addWidget(self.dial)
self.lytLCD.addWidget(self.lcd)
self.lytMain = QVBoxLayout()
self.lytMain.addWidget(self.btnStart)
self.lytMain.addLayout(self.lytLCD)
self.setLayout(self.lytMain)
def evt_btnStart_clicked(self):
# In this function create an instance of the worker class
self.worker = WorkerThread()
self.worker.start()
# Catching our own "update" signal
#self.worker.update_progress.connect(self.evt_update_progress)
# Whatever should be run in the thread must now run in the worker class!
class WorkerThread(QThread):
# Create our own signal to send current info to GUI
#update_progress = pyqtSignal(int)
def run(self):
global recognizer
while True:
try:
with sr.Microphone(device_index=0) as source:
recognizer.adjust_for_ambient_noise(source, duration=.2)
print("Listening...")
recognizer.energy_threshold = 4000
audio = recognizer.listen(source)
print("Recognizing...")
message = recognizer.recognize_google(audio).lower()
speaker.say(message)
speaker.runAndWait()
# print(message)
except sr.UnknownValueError:
recognizer = sr.Recognizer()
if __name__ == '__main__':
app = QApplication(sys.argv)
dlgMain = DlgMain()
dlgMain.show()
sys.exit(app.exec_())
我是否必须为 TTS 提供自己的线程?或者我可以用 pyqtSignal 以某种方式解决这个问题吗?我真的不确定要搜索什么,到目前为止还没有找到类似的问题。
希望有人能帮助我。提前致谢!
好的,我自己解决了这个问题。实际上是 pyttsx3 中的 runAndWait() 函数破坏了程序。相反,我现在使用 gTTS、pydub、soundfile、playsound 和 pyrubberband 的组合。
说话功能现在看起来像这样:
from gtts import gTTS
from pydub import AudioSegment
import playsound
import soundfile as sf
import pyrubberband as pyrb
def speakMsg(message):
# Write the message to mp3
tts = gTTS(text=message, lang="en")
tts.save("clear_msg.mp3")
# Change the file to wav format so it can be edited
sound = AudioSegment.from_mp3("clear_msg.mp3")
sound.export("clear_msg.wav", format="wav")
# Make playback faster (and pitch it down)
data, samplerate = sf.read("clear_msg.wav")
data_stretch = pyrb.time_stretch(data, samplerate, 1.4)
data_shift = pyrb.pitch_shift(data_stretch, samplerate, 0)
# Safe it as new file and play it.
sf.write("edit_msg.wav", data_shift, samplerate, format='wav')
playsound.playsound("edit_msg.wav")
看似超级复杂的东西实际上性能惊人!而且该程序现在可以运行了:D
你只能用 gTTS 来做到这一点,但我认为 gTTS 的声音太慢了。所以我加快了速度并降低了音调,所以它不会变得太“花栗鼠”。这就是为什么我做了这么多额外的工作!
您好,实际上我正在编写一个应提供 GUI 以及语音识别命令的应用程序,该程序应以 TTS 格式回答。我写了一个小测试程序,因为我想用 pyQt5 学习线程,因为它需要保持 GUI 响应 - 这是我到目前为止的理解,它似乎工作除非它尝试 TTS。
现在我遇到了一个问题,只要我不输入 TTS,一切正常。但是对于 pyttsx3,.runAndWait() 函数会退出我的代码的执行。 这是有问题的代码:(GUI 有滑块来检查线程是否有效)
import sys
import speech_recognition as sr
import pyttsx3
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
recognizer = sr.Recognizer()
speaker = pyttsx3.init()
voices = speaker.getProperty('voices')
# speaker.setProperty('voice', voices[33].id)
# speaker.setProperty('rate', 190)
class DlgMain(QDialog):
def __init__(self):
super().__init__()
self.setWindowTitle("Test")
self.btnStart = QPushButton("Start")
self.btnStart.clicked.connect(self.evt_btnStart_clicked)
self.dial = QSlider()
self.lcd = QLCDNumber()
self.dial.valueChanged.connect(self.lcd.display)
self.lytLCD = QHBoxLayout()
self.lytLCD.addWidget(self.dial)
self.lytLCD.addWidget(self.lcd)
self.lytMain = QVBoxLayout()
self.lytMain.addWidget(self.btnStart)
self.lytMain.addLayout(self.lytLCD)
self.setLayout(self.lytMain)
def evt_btnStart_clicked(self):
# In this function create an instance of the worker class
self.worker = WorkerThread()
self.worker.start()
# Catching our own "update" signal
#self.worker.update_progress.connect(self.evt_update_progress)
# Whatever should be run in the thread must now run in the worker class!
class WorkerThread(QThread):
# Create our own signal to send current info to GUI
#update_progress = pyqtSignal(int)
def run(self):
global recognizer
while True:
try:
with sr.Microphone(device_index=0) as source:
recognizer.adjust_for_ambient_noise(source, duration=.2)
print("Listening...")
recognizer.energy_threshold = 4000
audio = recognizer.listen(source)
print("Recognizing...")
message = recognizer.recognize_google(audio).lower()
speaker.say(message)
speaker.runAndWait()
# print(message)
except sr.UnknownValueError:
recognizer = sr.Recognizer()
if __name__ == '__main__':
app = QApplication(sys.argv)
dlgMain = DlgMain()
dlgMain.show()
sys.exit(app.exec_())
我是否必须为 TTS 提供自己的线程?或者我可以用 pyqtSignal 以某种方式解决这个问题吗?我真的不确定要搜索什么,到目前为止还没有找到类似的问题。
希望有人能帮助我。提前致谢!
好的,我自己解决了这个问题。实际上是 pyttsx3 中的 runAndWait() 函数破坏了程序。相反,我现在使用 gTTS、pydub、soundfile、playsound 和 pyrubberband 的组合。
说话功能现在看起来像这样:
from gtts import gTTS
from pydub import AudioSegment
import playsound
import soundfile as sf
import pyrubberband as pyrb
def speakMsg(message):
# Write the message to mp3
tts = gTTS(text=message, lang="en")
tts.save("clear_msg.mp3")
# Change the file to wav format so it can be edited
sound = AudioSegment.from_mp3("clear_msg.mp3")
sound.export("clear_msg.wav", format="wav")
# Make playback faster (and pitch it down)
data, samplerate = sf.read("clear_msg.wav")
data_stretch = pyrb.time_stretch(data, samplerate, 1.4)
data_shift = pyrb.pitch_shift(data_stretch, samplerate, 0)
# Safe it as new file and play it.
sf.write("edit_msg.wav", data_shift, samplerate, format='wav')
playsound.playsound("edit_msg.wav")
看似超级复杂的东西实际上性能惊人!而且该程序现在可以运行了:D 你只能用 gTTS 来做到这一点,但我认为 gTTS 的声音太慢了。所以我加快了速度并降低了音调,所以它不会变得太“花栗鼠”。这就是为什么我做了这么多额外的工作!