feat: 添加状态栏显示模型名称和加载状态

主窗口底部状态栏实时显示模型加载状态:
- 已就绪:绿色显示"模型已就绪: <文件名>"
- 路径为空:红色显示"⚠️ 模型路径未设置"
- 加载失败:橙色显示"⚠️ 模型加载失败: <文件名>"

Application 新增 modelLoading 信号和 modelPath() 方法,
配置变化时自动刷新状态栏显示。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Alvin Young 2026-05-13 14:19:12 +08:00
parent ef97b962c3
commit 6f55ec5780
4 changed files with 75 additions and 3 deletions

View File

@ -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);
}

View File

@ -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> configManager_;
SenseVoiceEngine* sttEngine_ = nullptr;
QString modelPath_;
bool modelLoaded_ = false;
};

View File

@ -12,6 +12,9 @@
#include <QAction>
#include <QFile>
#include <QMessageBox>
#include <QStatusBar>
#include <QLabel>
#include <QFileInfo>
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();

View File

@ -4,6 +4,8 @@
#include <QTabWidget>
#include <memory>
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