ソースを参照

fix: pyttsx3 单线程队列播报避免 runAndWait 冲突;增加到达工位语音提示

lsfoo 4 ヶ月 前
親
コミット
995a33c6b9
2 ファイル変更、28 行追加、5 行削除
  1. 5 0
      .vscode/settings.json
  2. 23 5
      hookvision/main_window.py

+ 5 - 0
.vscode/settings.json

@@ -0,0 +1,5 @@
+{
+    "python-envs.defaultEnvManager": "ms-python.python:conda",
+    "python-envs.defaultPackageManager": "ms-python.python:conda",
+    "editor.fontFamily": "Fira Code Retina"
+}

+ 23 - 5
hookvision/main_window.py

@@ -1,6 +1,7 @@
 import os
 import os
 import logging
 import logging
 import threading
 import threading
+import queue
 from PySide6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
 from PySide6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                                QPushButton, QLabel, QGridLayout, QScrollArea,
                                QPushButton, QLabel, QGridLayout, QScrollArea,
                                QToolButton, QFrame, QApplication, QCheckBox)
                                QToolButton, QFrame, QApplication, QCheckBox)
@@ -57,7 +58,10 @@ class MainWindow(QMainWindow):
         self.tts_engine = pyttsx3.init()
         self.tts_engine = pyttsx3.init()
         self.tts_engine.setProperty('rate', 150)
         self.tts_engine.setProperty('rate', 150)
         self.last_voice_state = None
         self.last_voice_state = None
-        self.voice_enabled = True  # 默认开启
+        self.voice_enabled = True
+        self._voice_queue = queue.Queue()
+        self._voice_thread = threading.Thread(target=self._voice_worker, daemon=True)
+        self._voice_thread.start()
 
 
         self.setWindowTitle(config.app_name)
         self.setWindowTitle(config.app_name)
 
 
@@ -269,6 +273,21 @@ class MainWindow(QMainWindow):
     def on_voice_toggle(self, state):
     def on_voice_toggle(self, state):
         self.voice_enabled = (state == Qt.Checked)
         self.voice_enabled = (state == Qt.Checked)
 
 
+    def _speak(self, msg: str):
+        self._voice_queue.put(msg)
+
+    def _voice_worker(self):
+        while True:
+            msg = self._voice_queue.get()
+            if msg is None:
+                break
+            try:
+                self.tts_engine.say(msg)
+                self.tts_engine.runAndWait()
+            except Exception as e:
+                logging.warning(f"语音播报失败: {e}")
+            self._voice_queue.task_done()
+
     # ---------- 工位图标 ----------
     # ---------- 工位图标 ----------
     def get_bucket_icon(self, is_active):
     def get_bucket_icon(self, is_active):
         icon_dir = os.path.join(os.path.dirname(__file__), "..", "assets")
         icon_dir = os.path.join(os.path.dirname(__file__), "..", "assets")
@@ -428,6 +447,8 @@ class MainWindow(QMainWindow):
     def activate_bucket(self, bucket: BucketModel):
     def activate_bucket(self, bucket: BucketModel):
         if self.active_bucket == bucket:
         if self.active_bucket == bucket:
             return
             return
+        if bucket and self.voice_enabled:
+            self._speak(f"到达{bucket.description}")
         if self.left_player:
         if self.left_player:
             self.left_player.stop()
             self.left_player.stop()
             self.left_player = None
             self.left_player = None
@@ -736,10 +757,7 @@ class MainWindow(QMainWindow):
         # 语音播报(带开关和防重复)
         # 语音播报(带开关和防重复)
         if self.voice_enabled and state in (HookState.HOOKING, HookState.READY) and state != self.last_voice_state:
         if self.voice_enabled and state in (HookState.HOOKING, HookState.READY) and state != self.last_voice_state:
             msg = "挂包中" if state == HookState.HOOKING else "挂包成功"
             msg = "挂包中" if state == HookState.HOOKING else "挂包成功"
-            def speak():
-                self.tts_engine.say(msg)
-                self.tts_engine.runAndWait()
-            threading.Thread(target=speak, daemon=True).start()
+            self._speak(msg)
             self.last_voice_state = state
             self.last_voice_state = state
 
 
     # ---------- 定时任务 ----------
     # ---------- 定时任务 ----------