From 6f55ec578018ce68bc549a6bc033997f94859fee Mon Sep 17 00:00:00 2001 From: impressionyang Date: Wed, 13 May 2026 14:19:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E6=A0=8F=E6=98=BE=E7=A4=BA=E6=A8=A1=E5=9E=8B=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E5=92=8C=E5=8A=A0=E8=BD=BD=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 主窗口底部状态栏实时显示模型加载状态: - 已就绪:绿色显示"模型已就绪: <文件名>" - 路径为空:红色显示"⚠️ 模型路径未设置" - 加载失败:橙色显示"⚠️ 模型加载失败: <文件名>" Application 新增 modelLoading 信号和 modelPath() 方法, 配置变化时自动刷新状态栏显示。 Co-Authored-By: Claude Opus 4.6 --- src/app/application.cpp | 7 +++++- src/app/application.h | 11 +++++++-- src/ui/main_window.cpp | 53 +++++++++++++++++++++++++++++++++++++++++ src/ui/main_window.h | 7 ++++++ 4 files changed, 75 insertions(+), 3 deletions(-) diff --git a/src/app/application.cpp b/src/app/application.cpp index 162d6d7..4f8f1a4 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -20,8 +20,9 @@ Application::Application(int& argc, char** argv) sttEngine_ = new SenseVoiceEngine(this); connect(sttEngine_, &SenseVoiceEngine::modelLoaded, this, [this](const QString& path) { modelLoaded_ = true; + modelPath_ = path; LOG_INFO(kTag, QString("全局模型已加载: %1").arg(path)); - emit modelLoaded(); + emit modelLoaded(path); }); connect(sttEngine_, &SenseVoiceEngine::modelLoadError, this, [this](const QString&, const QString& err) { modelLoaded_ = false; @@ -54,9 +55,12 @@ void Application::loadGlobalModel() { QString modelPath = configManager_->get("stt.model_path").toString(); if (modelPath.isEmpty()) { LOG_WARNING(kTag, "模型路径为空,请在配置中设置后重启"); + emit modelLoadError("模型路径未设置"); return; } + modelPath_ = modelPath; + QString tokensPath = configManager_->get("stt.tokens_path").toString(); QString device = configManager_->get("stt.device").toString(); int numThreads = configManager_->get("stt.num_threads").toInt(); @@ -65,6 +69,7 @@ void Application::loadGlobalModel() { sttEngine_->setDebugSaveAudio(debugSave); LOG_INFO(kTag, QString("正在异步加载全局模型: %1").arg(modelPath)); + emit modelLoading(modelPath); sttEngine_->loadModelAsync(modelPath, tokensPath, device, numThreads); } diff --git a/src/app/application.h b/src/app/application.h index ad4b410..a8ac9ae 100644 --- a/src/app/application.h +++ b/src/app/application.h @@ -26,12 +26,18 @@ public: /** @brief 获取全局 STT 引擎(共享实例) */ SenseVoiceEngine* sttEngine() const; + /** @brief 获取当前模型路径 */ + QString modelPath() const { return modelPath_; } + /** @brief 获取全局 STT 引擎加载状态 */ bool isModelLoaded() const; signals: - /** @brief 模型加载完成 */ - void modelLoaded(); + /** @brief 模型加载中(带路径) */ + void modelLoading(const QString& modelPath); + + /** @brief 模型加载完成(带路径) */ + void modelLoaded(const QString& modelPath); /** @brief 模型加载失败 */ void modelLoadError(const QString& error); @@ -41,6 +47,7 @@ private: std::unique_ptr configManager_; SenseVoiceEngine* sttEngine_ = nullptr; + QString modelPath_; bool modelLoaded_ = false; }; diff --git a/src/ui/main_window.cpp b/src/ui/main_window.cpp index 1d0baf9..fadc3b9 100644 --- a/src/ui/main_window.cpp +++ b/src/ui/main_window.cpp @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include static const char* const kTag = "MainWindow"; @@ -28,6 +31,7 @@ MainWindow::MainWindow(ConfigManager* configManager, setupUI(sttEngine); setupMenuBar(); + setupStatusBar(sttEngine); loadStyleSheet(); // 初始化语音输入服务(共享全局引擎) @@ -71,6 +75,29 @@ void MainWindow::setupUI(SenseVoiceEngine* sttEngine) { setCentralWidget(tabWidget_); } +void MainWindow::setupStatusBar(SenseVoiceEngine* sttEngine) { + sttEngine_ = sttEngine; + + auto* bar = statusBar(); + bar->setSizeGripEnabled(false); + + modelStatusLabel_ = new QLabel(this); + modelStatusLabel_->setStyleSheet( + "QLabel { padding: 2px 8px; font-size: 13px; }"); + bar->addPermanentWidget(modelStatusLabel_); + + // 连接全局引擎信号 + connect(sttEngine_, &SenseVoiceEngine::modelLoaded, + this, &MainWindow::updateModelStatus); + connect(sttEngine_, &SenseVoiceEngine::modelLoadError, + this, &MainWindow::updateModelStatus); + connect(sttEngine_, &SenseVoiceEngine::modelUnloaded, + this, &MainWindow::updateModelStatus); + + // 初始化显示 + updateModelStatus(); +} + void MainWindow::setupMenuBar() { // 文件菜单 auto* fileMenu = menuBar()->addMenu("文件"); @@ -112,9 +139,35 @@ void MainWindow::closeEvent(QCloseEvent* event) { QMainWindow::closeEvent(event); } +void MainWindow::updateModelStatus() { + if (!sttEngine_ || !modelStatusLabel_) return; + + QString modelPath = configManager_->get("stt.model_path").toString(); + QString modelName = modelPath.isEmpty() ? QString() : QFileInfo(modelPath).fileName(); + + if (sttEngine_->isLoaded()) { + QString statusText = modelName.isEmpty() ? "模型已就绪" : QString("模型已就绪: %1").arg(modelName); + modelStatusLabel_->setText(statusText); + modelStatusLabel_->setStyleSheet( + "QLabel { padding: 2px 8px; font-size: 13px; color: #27ae60; font-weight: bold; }"); + } else if (modelPath.isEmpty()) { + modelStatusLabel_->setText("⚠️ 模型路径未设置"); + modelStatusLabel_->setStyleSheet( + "QLabel { padding: 2px 8px; font-size: 13px; color: #e74c3c; }"); + } else { + modelStatusLabel_->setText( + QString("⚠️ 模型加载失败: %1").arg(modelName)); + modelStatusLabel_->setStyleSheet( + "QLabel { padding: 2px 8px; font-size: 13px; color: #e67e22; }"); + } +} + void MainWindow::onVoiceInputConfigChanged() { if (!voiceInputService_) return; + // 更新模型状态显示 + updateModelStatus(); + bool enabled = configManager_->get("stt.capslock_voice_enabled").toBool(); if (enabled && !voiceInputService_->isRunning()) { voiceInputService_->start(); diff --git a/src/ui/main_window.h b/src/ui/main_window.h index f5d6b70..e10e63d 100644 --- a/src/ui/main_window.h +++ b/src/ui/main_window.h @@ -4,6 +4,8 @@ #include #include +class QLabel; + namespace impress { class ConfigManager; @@ -17,6 +19,7 @@ class VoiceInputService; * @brief 主窗口 * * 使用 Tab 页导航管理三个功能页面,共享全局 STT 引擎。 + * 状态栏显示模型名称和加载状态。 */ class MainWindow : public QMainWindow { Q_OBJECT @@ -32,15 +35,19 @@ protected: private: void setupUI(SenseVoiceEngine* sttEngine); void setupMenuBar(); + void setupStatusBar(SenseVoiceEngine* sttEngine); void loadStyleSheet(); void onVoiceInputConfigChanged(); + void updateModelStatus(); ConfigManager* configManager_; + SenseVoiceEngine* sttEngine_; VoiceInputService* voiceInputService_; STTTestPage* sttPage_; FileTranscribePage* transcribePage_; SettingsPage* settingsPage_; QTabWidget* tabWidget_; + QLabel* modelStatusLabel_; }; } // namespace impress