69 lines
2.5 KiB
Python
69 lines
2.5 KiB
Python
import logger
|
||
import pyttsx3
|
||
from PyQt5.QtWidgets import QWidget, QPushButton, QVBoxLayout, QLabel
|
||
from uas.io.base_io import BaseOutput, IOType, IOData
|
||
from uas.io.outputs.text_output import HAS_TTS
|
||
from uas.io.signals import io_signals
|
||
|
||
|
||
class SpeechOutput(BaseOutput):
|
||
def __init__(self):
|
||
super().__init__("speech_output", [IOType.TEXT, IOType.SPEECH])
|
||
self._engine = None
|
||
if HAS_TTS:
|
||
self._init_tts()
|
||
|
||
def _init_tts(self):
|
||
try:
|
||
self._engine = pyttsx3.init()
|
||
self._engine.setProperty("rate", 180)
|
||
self._engine.setProperty("volume", 0.9)
|
||
logger.info("✅ TTS 引擎初始化成功")
|
||
except Exception as e:
|
||
logger.error(f"TTS 初始化失败: {e}")
|
||
|
||
def render(self, data: IOData) -> None:
|
||
text = str(data.processed or data.raw)
|
||
self._tts_label.setText(f"朗读: {text[:80]}...")
|
||
if not self._mute_btn.isChecked() and self._engine:
|
||
try:
|
||
self._engine.say(text)
|
||
self._engine.runAndWait()
|
||
io_signals.tts_finished.emit(text)
|
||
except Exception as e:
|
||
logger.error(f"TTS 朗读失败: {e}")
|
||
# ─────────────────────────────────────────────────────────────────
|
||
# 语音输出(TTS)
|
||
# ─────────────────────────────────────────────────────────────────
|
||
|
||
class SpeechOutputWidget(QWidget, SpeechOutput):
|
||
"""
|
||
语音输出(TTS)组件
|
||
基于 pyttsx3,在独立 QThread 中朗读,不阻塞 UI
|
||
"""
|
||
|
||
def __init__(self, parent=None):
|
||
QWidget.__init__(self, parent)
|
||
SpeechOutput.__init__(self)
|
||
self._build_ui()
|
||
|
||
|
||
def _build_ui(self):
|
||
layout = QVBoxLayout(self)
|
||
layout.setContentsMargins(8, 8, 8, 8)
|
||
|
||
title = QLabel("🔊 语音输出 (TTS)")
|
||
title.setStyleSheet("font-weight: bold; font-size: 13px;")
|
||
layout.addWidget(title)
|
||
|
||
self._tts_label = QLabel("等待输出...")
|
||
self._tts_label.setWordWrap(True)
|
||
self._tts_label.setStyleSheet(
|
||
"background:#e8f5e9; padding:6px; border-radius:4px;"
|
||
)
|
||
layout.addWidget(self._tts_label)
|
||
|
||
self._mute_btn = QPushButton("🔇 静音")
|
||
self._mute_btn.setCheckable(True)
|
||
layout.addWidget(self._mute_btn)
|