174 lines
7.9 KiB
Python
174 lines
7.9 KiB
Python
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
"""
|
|||
|
|
IO 模块完整演示
|
|||
|
|
─────────────────────────────────────────────────────────────────
|
|||
|
|
运行: python main.py
|
|||
|
|
依赖: pip install PyQt5 SpeechRecognition pyaudio pyttsx3
|
|||
|
|
─────────────────────────────────────────────────────────────────
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import logging
|
|||
|
|
import sys
|
|||
|
|
|
|||
|
|
from PyQt5.QtCore import Qt, QTimer, pyqtSlot
|
|||
|
|
from PyQt5.QtWidgets import (
|
|||
|
|
QApplication, QMainWindow, QWidget,
|
|||
|
|
QVBoxLayout, QSplitter,
|
|||
|
|
QTabWidget, QStatusBar
|
|||
|
|
)
|
|||
|
|
# ── 处理器 ────────────────────────────────────────────────────────
|
|||
|
|
from processors.text_processor import PIPELINE_PRESETS
|
|||
|
|
from uas.io.base_io import IOType
|
|||
|
|
from uas.io.dispatcher import IODispatcher
|
|||
|
|
# ── 核心模块 ──────────────────────────────────────────────────────
|
|||
|
|
from uas.io.signals import io_signals
|
|||
|
|
|
|||
|
|
from inputs.speech_input import SpeechInputWidget
|
|||
|
|
# ── 输入模块 ──────────────────────────────────────────────────────
|
|||
|
|
from inputs.text_input import TextInputWidget, ConsoleTextInput
|
|||
|
|
from outputs.speech_output import SpeechOutputWidget
|
|||
|
|
# ── 输出模块 ──────────────────────────────────────────────────────
|
|||
|
|
from outputs.text_output import TextOutputWidget
|
|||
|
|
|
|||
|
|
# ── 日志 ──────────────────────────────────────────────────────────
|
|||
|
|
logging.basicConfig(
|
|||
|
|
level = logging.DEBUG,
|
|||
|
|
format = "%(asctime)s [%(levelname)-8s] %(name)s - %(message)s",
|
|||
|
|
)
|
|||
|
|
logger = logging.getLogger("main")
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
# 主窗口
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
class MainWindow(QMainWindow):
|
|||
|
|
|
|||
|
|
def __init__(self):
|
|||
|
|
super().__init__()
|
|||
|
|
self.setWindowTitle("🛰️ IO 通信模块 — PyQt5 信号槽演示")
|
|||
|
|
self.resize(1100, 700)
|
|||
|
|
self._setup_dispatcher()
|
|||
|
|
self._setup_ui()
|
|||
|
|
self._connect_signals()
|
|||
|
|
self._auto_demo()
|
|||
|
|
|
|||
|
|
# ── 分发器初始化 ──────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def _setup_dispatcher(self):
|
|||
|
|
self.dispatcher = IODispatcher(max_threads=4, parent=self)
|
|||
|
|
# 注册文本处理链(full 预设)
|
|||
|
|
for proc in PIPELINE_PRESETS["full"]:
|
|||
|
|
self.dispatcher.register_processor(IOType.TEXT, proc)
|
|||
|
|
# 注册语音处理链
|
|||
|
|
for proc in PIPELINE_PRESETS["speech"]:
|
|||
|
|
self.dispatcher.register_processor(IOType.SPEECH, proc)
|
|||
|
|
self.dispatcher.start()
|
|||
|
|
logger.info("✅ 分发器已启动")
|
|||
|
|
|
|||
|
|
# ── UI 构建 ───────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def _setup_ui(self):
|
|||
|
|
central = QWidget()
|
|||
|
|
self.setCentralWidget(central)
|
|||
|
|
main_layout = QVBoxLayout(central)
|
|||
|
|
main_layout.setContentsMargins(6, 6, 6, 6)
|
|||
|
|
|
|||
|
|
# 水平分割:左=输入,右=输出
|
|||
|
|
splitter = QSplitter(Qt.Horizontal)
|
|||
|
|
|
|||
|
|
# ── 左侧:输入 Tab ────────────────────────────────────────
|
|||
|
|
input_tabs = QTabWidget()
|
|||
|
|
|
|||
|
|
self.text_input = TextInputWidget()
|
|||
|
|
self.speech_input = SpeechInputWidget()
|
|||
|
|
|
|||
|
|
input_tabs.addTab(self.text_input, "📝 文本输入")
|
|||
|
|
input_tabs.addTab(self.speech_input, "🎤 语音输入")
|
|||
|
|
splitter.addWidget(input_tabs)
|
|||
|
|
|
|||
|
|
# ── 右侧:输出 Tab ────────────────────────────────────────
|
|||
|
|
output_tabs = QTabWidget()
|
|||
|
|
|
|||
|
|
self.text_output = TextOutputWidget()
|
|||
|
|
self.speech_output = SpeechOutputWidget()
|
|||
|
|
|
|||
|
|
output_tabs.addTab(self.text_output, "📄 文本输出")
|
|||
|
|
output_tabs.addTab(self.speech_output, "🔊 语音输出")
|
|||
|
|
splitter.addWidget(output_tabs)
|
|||
|
|
|
|||
|
|
splitter.setSizes([420, 660])
|
|||
|
|
main_layout.addWidget(splitter)
|
|||
|
|
|
|||
|
|
# ── 状态栏 ────────────────────────────────────────────────
|
|||
|
|
self._status = QStatusBar()
|
|||
|
|
self.setStatusBar(self._status)
|
|||
|
|
self._status.showMessage("就绪 | IODispatcher 运行中")
|
|||
|
|
|
|||
|
|
# ── 信号连接 ──────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def _connect_signals(self):
|
|||
|
|
# 全局信号监听(用于状态栏更新)
|
|||
|
|
io_signals.input_received.connect(self._on_input_received)
|
|||
|
|
io_signals.input_processed.connect(self._on_processed)
|
|||
|
|
io_signals.error_occurred.connect(self._on_error)
|
|||
|
|
io_signals.speech_recognized.connect(self._on_speech_recognized)
|
|||
|
|
|
|||
|
|
@pyqtSlot(str, str, object)
|
|||
|
|
def _on_input_received(self, data_id: str, io_type: str, data):
|
|||
|
|
self._status.showMessage(
|
|||
|
|
f"📥 收到输入 [{io_type}] id={data_id[:8]} 正在处理..."
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
@pyqtSlot(str, str, object)
|
|||
|
|
def _on_processed(self, data_id: str, io_type: str, data):
|
|||
|
|
self._status.showMessage(
|
|||
|
|
f"✅ 处理完成 [{io_type}] id={data_id[:8]}"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
@pyqtSlot(str, str, str)
|
|||
|
|
def _on_error(self, data_id: str, source: str, msg: str):
|
|||
|
|
self._status.showMessage(f"❌ 错误 [{source}]: {msg}")
|
|||
|
|
|
|||
|
|
@pyqtSlot(str)
|
|||
|
|
def _on_speech_recognized(self, text: str):
|
|||
|
|
self._status.showMessage(f"🎤 语音识别: {text}")
|
|||
|
|
|
|||
|
|
# ── 自动演示 ──────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def _auto_demo(self):
|
|||
|
|
"""启动后自动注入几条测试消息"""
|
|||
|
|
demo_texts = [
|
|||
|
|
"Hello World!这是第一条测试消息。",
|
|||
|
|
"PyQt5 信号与槽机制实现异步IO分发?",
|
|||
|
|
"支持文本、语音、文件等多种输入输出类型!",
|
|||
|
|
]
|
|||
|
|
console_input = ConsoleTextInput(self)
|
|||
|
|
|
|||
|
|
def inject_next(idx=0):
|
|||
|
|
if idx < len(demo_texts):
|
|||
|
|
console_input.inject(demo_texts[idx])
|
|||
|
|
QTimer.singleShot(800, lambda: inject_next(idx + 1))
|
|||
|
|
|
|||
|
|
QTimer.singleShot(500, inject_next)
|
|||
|
|
|
|||
|
|
def closeEvent(self, event):
|
|||
|
|
self.dispatcher.stop()
|
|||
|
|
self.speech_input.stop()
|
|||
|
|
event.accept()
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
# 入口
|
|||
|
|
# ─────────────────────────────────────────────────────────────────
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
app = QApplication(sys.argv)
|
|||
|
|
app.setStyle("Fusion")
|
|||
|
|
win = MainWindow()
|
|||
|
|
win.show()
|
|||
|
|
sys.exit(app.exec_())
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
main()
|