From baec3482a770d72044d30a1507c257691e27b4d1 Mon Sep 17 00:00:00 2001 From: impressionyang Date: Wed, 13 May 2026 11:13:15 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=9B=86=E6=88=90=E8=AF=AD=E9=9F=B3?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=9C=8D=E5=8A=A1=E5=88=B0=E4=B8=BB=E7=AA=97?= =?UTF-8?q?=E5=8F=A3=E5=92=8C=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主窗口新增 VoiceInputService 生命周期管理,支持通过配置页面 的开关动态启停 CapsLock 语音输入功能,窗口关闭时自动清理。 设置页面新增两个复选框: - 调试录音:保存每次识别的原始音频到临时文件夹 - 快捷语音:启用 CapsLock 长按语音输入 转写页面和 STT 测试页面同步配置中的调试音频开关到引擎。 Co-Authored-By: Claude Opus 4.6 --- src/ui/file_transcribe_page.cpp | 4 ++++ src/ui/main_window.cpp | 39 +++++++++++++++++++++++++++++++++ src/ui/main_window.h | 3 +++ src/ui/settings_page.cpp | 12 ++++++++++ src/ui/settings_page.h | 2 ++ src/ui/stt_test_page.cpp | 4 ++++ 6 files changed, 64 insertions(+) diff --git a/src/ui/file_transcribe_page.cpp b/src/ui/file_transcribe_page.cpp index d5f5c51..df5011c 100644 --- a/src/ui/file_transcribe_page.cpp +++ b/src/ui/file_transcribe_page.cpp @@ -174,6 +174,10 @@ void FileTranscribePage::onStartTranscribe() { return; } + // 从配置同步调试开关到引擎 + sttEngine_->setDebugSaveAudio( + configManager_->get("stt.debug_save_audio").toBool()); + isTranscribing_ = true; currentTaskIndex_ = 0; progressBar_->setVisible(true); diff --git a/src/ui/main_window.cpp b/src/ui/main_window.cpp index 37c1d60..268f5f2 100644 --- a/src/ui/main_window.cpp +++ b/src/ui/main_window.cpp @@ -2,6 +2,7 @@ #include "stt_test_page.h" #include "file_transcribe_page.h" #include "settings_page.h" +#include "core/voice_input_service.h" #include "app/config_manager.h" #include "utils/logger.h" @@ -26,6 +27,28 @@ MainWindow::MainWindow(ConfigManager* configManager, QWidget* parent) setupMenuBar(); loadStyleSheet(); + // 初始化语音输入服务 + voiceInputService_ = new VoiceInputService(configManager_, this); + connect(voiceInputService_, &VoiceInputService::statusChanged, + this, [this](const QString& status) { + LOG_DEBUG(kTag, QString("语音输入状态: %1").arg(status)); + }); + connect(voiceInputService_, &VoiceInputService::error, + this, [this](const QString& err) { + LOG_ERROR(kTag, err); + }); + connect(voiceInputService_, &VoiceInputService::recognitionResult, + this, [this](const QString& text) { + LOG_INFO(kTag, QString("语音识别结果: %1").arg(text)); + }); + + // 监听配置变化,动态启停语音输入服务 + connect(configManager_, &ConfigManager::configChanged, + this, &MainWindow::onVoiceInputConfigChanged); + + // 启动时检查配置 + onVoiceInputConfigChanged(); + LOG_INFO(kTag, "主窗口已创建"); } @@ -79,8 +102,24 @@ void MainWindow::loadStyleSheet() { } void MainWindow::closeEvent(QCloseEvent* event) { + if (voiceInputService_) { + voiceInputService_->stop(); + } LOG_INFO(kTag, "主窗口关闭"); QMainWindow::closeEvent(event); } +void MainWindow::onVoiceInputConfigChanged() { + if (!voiceInputService_) return; + + bool enabled = configManager_->get("stt.capslock_voice_enabled").toBool(); + if (enabled && !voiceInputService_->isRunning()) { + voiceInputService_->start(); + LOG_INFO(kTag, "CapsLock 语音输入已启用"); + } else if (!enabled && voiceInputService_->isRunning()) { + voiceInputService_->stop(); + LOG_INFO(kTag, "CapsLock 语音输入已关闭"); + } +} + } // namespace impress diff --git a/src/ui/main_window.h b/src/ui/main_window.h index 85395d2..5f34736 100644 --- a/src/ui/main_window.h +++ b/src/ui/main_window.h @@ -10,6 +10,7 @@ class ConfigManager; class STTTestPage; class FileTranscribePage; class SettingsPage; +class VoiceInputService; /** * @brief 主窗口 @@ -29,8 +30,10 @@ private: void setupUI(); void setupMenuBar(); void loadStyleSheet(); + void onVoiceInputConfigChanged(); ConfigManager* configManager_; + VoiceInputService* voiceInputService_; STTTestPage* sttPage_; FileTranscribePage* transcribePage_; SettingsPage* settingsPage_; diff --git a/src/ui/settings_page.cpp b/src/ui/settings_page.cpp index b4983de..b2eca74 100644 --- a/src/ui/settings_page.cpp +++ b/src/ui/settings_page.cpp @@ -83,6 +83,14 @@ void SettingsPage::setupUI() { streamingCheck_->setChecked(true); sttLayout->addRow("流式识别:", streamingCheck_); + debugSaveAudioCheck_ = new QCheckBox("保存调试音频到 /tmp/impress_audio_debug/", this); + debugSaveAudioCheck_->setToolTip("开启后,每次识别会将原始音频保存为 WAV 文件,用于调试音频质量问题"); + sttLayout->addRow("调试录音:", debugSaveAudioCheck_); + + capslockVoiceCheck_ = new QCheckBox("启用 CapsLock 长按语音输入", this); + capslockVoiceCheck_->setToolTip("长按 CapsLock 键 1 秒后触发录音,松开后自动转写并输入到光标位置"); + sttLayout->addRow("快捷语音:", capslockVoiceCheck_); + beamSizeSpin_ = new QSpinBox(this); beamSizeSpin_->setRange(1, 20); beamSizeSpin_->setValue(5); @@ -174,6 +182,8 @@ void SettingsPage::loadFromConfig() { sampleRateSpin_->setValue(configManager_->get("stt.sample_rate").toInt()); languageCombo_->setCurrentText(configManager_->get("stt.language").toString()); streamingCheck_->setChecked(configManager_->get("stt.streaming").toBool()); + debugSaveAudioCheck_->setChecked(configManager_->get("stt.debug_save_audio").toBool()); + capslockVoiceCheck_->setChecked(configManager_->get("stt.capslock_voice_enabled").toBool()); beamSizeSpin_->setValue(configManager_->get("stt.beam_size").toInt()); temperatureSpin_->setValue(configManager_->get("stt.temperature").toDouble()); @@ -196,6 +206,8 @@ void SettingsPage::saveToConfig() { configManager_->set("stt.sample_rate", sampleRateSpin_->value()); configManager_->set("stt.language", languageCombo_->currentText()); configManager_->set("stt.streaming", streamingCheck_->isChecked()); + configManager_->set("stt.debug_save_audio", debugSaveAudioCheck_->isChecked()); + configManager_->set("stt.capslock_voice_enabled", capslockVoiceCheck_->isChecked()); configManager_->set("stt.beam_size", beamSizeSpin_->value()); configManager_->set("stt.temperature", temperatureSpin_->value()); diff --git a/src/ui/settings_page.h b/src/ui/settings_page.h index c3f7b96..e57f130 100644 --- a/src/ui/settings_page.h +++ b/src/ui/settings_page.h @@ -51,6 +51,8 @@ private: QSpinBox* sampleRateSpin_; QComboBox* languageCombo_; QCheckBox* streamingCheck_; + QCheckBox* debugSaveAudioCheck_; + QCheckBox* capslockVoiceCheck_; QSpinBox* beamSizeSpin_; QDoubleSpinBox* temperatureSpin_; diff --git a/src/ui/stt_test_page.cpp b/src/ui/stt_test_page.cpp index bd12481..05374ab 100644 --- a/src/ui/stt_test_page.cpp +++ b/src/ui/stt_test_page.cpp @@ -135,6 +135,10 @@ void STTTestPage::onToggleRecording() { return; } + // 从配置同步调试开关到引擎 + sttEngine_->setDebugSaveAudio( + configManager_->get("stt.debug_save_audio").toBool()); + // 异步加载模型 if (!sttEngine_->isLoaded() || currentModelPath_ != modelPath) {