feat(gui): expose the streaming and debug options in the advanced page
These were command-line only. Add them to the settings dialog so the whole feature set is reachable without arguments: stream mode, window limit, segment limit, prefix-rollback token count, cold-start chunk count, max tokens per step, thread count, verbose logging and the model directory. The streaming group is grouped and greyed out for streaming-ONNX models, which only use the commit granularity. The backend fingerprint now includes them, so changing one restarts the recogniser; appearance changes still apply live. Also add a test-only --settings-tab so a specific page can be screenshotted. 设置「高级」页补上原来只有命令行才有的选项:流式策略/滑窗上限/单段最长/前缀回滚 token 数/冷启动 chunk 数/单段最多生成 token/线程数/详细日志/模型目录。流式那一组 单独成组,选了流式 ONNX 模型时置灰(它们只用「更新粒度」)。这些值纳入「后端指纹」, 改动会重启识别后端;外观类改动仍然即时生效。另加测试用 --settings-tab 以便给单个 页签截图。
This commit is contained in:
1 parent
d234b9658d
commit
6c04071bb5
8 files changed
+252
-25
No files matched your search
+59
-12
@@ -13,7 +13,9 @@
|
||||
#include <QPainter>
|
||||
#include <QPixmap>
|
||||
#include <QPushButton>
|
||||
#include <QStringList>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTabWidget>
|
||||
#include <QTimer>
|
||||
|
||||
#include "appcli.h"
|
||||
@@ -66,6 +68,25 @@ bool hasUsableModel()
|
||||
return m && ModelStore::isInstalled(*m);
|
||||
}
|
||||
|
||||
// 后端相关设置的「指纹」:这些值变了就必须重建后端(外观类改动不需要)。
|
||||
QString backendKeyOf(const lc::AppSettings & c)
|
||||
{
|
||||
return QStringList{ c.modelId,
|
||||
c.language,
|
||||
c.captureDevice,
|
||||
c.modelDir,
|
||||
c.streamMode,
|
||||
QString::number(c.chunkSec),
|
||||
QString::number(c.streamWindowSec),
|
||||
QString::number(c.streamSegmentSec),
|
||||
QString::number(c.unfixedTokens),
|
||||
QString::number(c.unfixedChunks),
|
||||
QString::number(c.maxTokens),
|
||||
QString::number(c.threads),
|
||||
QString::number(c.verbose ? 1 : 0) }
|
||||
.join(QLatin1Char('|'));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
@@ -95,6 +116,7 @@ int main(int argc, char ** argv)
|
||||
parser.addOption(QCommandLineOption("screenshot-delay", "截图前等待秒数", "sec", "6"));
|
||||
parser.addOption(QCommandLineOption("no-tray", "不创建托盘图标(测试用)"));
|
||||
parser.addOption(QCommandLineOption("screenshot-settings", "打开设置对话框截图后退出", "path"));
|
||||
parser.addOption(QCommandLineOption("settings-tab", "截图设置对话框时先切到某个页签(0-2 或 模型/显示/高级)", "tab"));
|
||||
parser.addOption(QCommandLineOption("settings-autoclose", "复现用:自动操作设置对话框(reject|close|accept|ok|apply)", "how"));
|
||||
parser.addOption(QCommandLineOption("quit-after", "运行若干秒后优雅退出(测试退出路径用)", "sec"));
|
||||
parser.process(app);
|
||||
@@ -102,12 +124,28 @@ int main(int argc, char ** argv)
|
||||
if (parser.isSet("asr-model")) cfg.modelId = parser.value("asr-model");
|
||||
if (parser.isSet("language")) cfg.language = parser.value("language");
|
||||
if (parser.isSet("opacity")) cfg.opacityPercent = parser.value("opacity").toInt();
|
||||
if (parser.isSet("model-dir")) lc::models::ModelStore::setRootOverride(parser.value("model-dir"));
|
||||
if (parser.isSet("model-dir")) cfg.modelDir = parser.value("model-dir");
|
||||
if (!cfg.modelDir.isEmpty()) lc::models::ModelStore::setRootOverride(cfg.modelDir);
|
||||
|
||||
// 仅用于验证渲染:打开设置对话框截图后退出
|
||||
if (parser.isSet("screenshot-settings")) {
|
||||
const QString path = parser.value("screenshot-settings");
|
||||
lc::SettingsDialog dlg(!hasUsableModel());
|
||||
// 可选:先切页签,便于给某个页单独截图
|
||||
const QString tab = parser.value("settings-tab");
|
||||
if (!tab.isEmpty()) {
|
||||
if (auto * tw = dlg.findChild<QTabWidget *>()) {
|
||||
bool numeric = false;
|
||||
const int n = tab.toInt(&numeric);
|
||||
if (numeric) {
|
||||
tw->setCurrentIndex(qBound(0, n, tw->count() - 1));
|
||||
} else {
|
||||
for (int i = 0; i < tw->count(); ++i) {
|
||||
if (tw->tabText(i) == tab) { tw->setCurrentIndex(i); break; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dlg.show();
|
||||
QTimer::singleShot(1200, &dlg, [&dlg, path] {
|
||||
dlg.grab().save(path);
|
||||
@@ -173,14 +211,24 @@ int main(int argc, char ** argv)
|
||||
return false;
|
||||
}
|
||||
std::string err;
|
||||
asr = lc::app::makeAsrForModel(*m, cfg.language, cfg.threads,
|
||||
parser.isSet("verbose"), &err);
|
||||
asr = lc::app::makeAsrForModel(*m, cfg.language, cfg.threads, cfg.maxTokens,
|
||||
cfg.verbose || parser.isSet("verbose"), &err);
|
||||
if (!asr) {
|
||||
qCritical("加载模型失败: %s", err.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// 流式参数:只有 llama 后端(Qwen3-ASR)用得到大部分参数,
|
||||
// 流式 ONNX 只关心「更新粒度」。
|
||||
lc::StreamOptions sop;
|
||||
sop.windowSec = cfg.streamWindowSec;
|
||||
sop.maxUtteranceSec = cfg.streamSegmentSec;
|
||||
sop.unfixedTokenNum = cfg.unfixedTokens;
|
||||
sop.unfixedChunkNum = cfg.unfixedChunks;
|
||||
sop.maxTokensPerStep = cfg.maxTokens;
|
||||
sop.incremental = (cfg.streamMode != QLatin1String("append")
|
||||
&& cfg.streamMode != QLatin1String("window"));
|
||||
sop.appendOnly = (cfg.streamMode == QLatin1String("append"));
|
||||
if (asr->kind() == lc::AsrKind::NativeStreaming) {
|
||||
sop.chunkSec = (cfg.chunkSec > 0.0) ? cfg.chunkSec : 0.32;
|
||||
} else if (cfg.chunkSec > 0.0) {
|
||||
@@ -207,28 +255,27 @@ int main(int argc, char ** argv)
|
||||
qWarning("采集失败: %s", qUtf8Printable(m));
|
||||
});
|
||||
|
||||
// 后端相关项(模型/语言/采集设备)变化才需要重启;外观类改动即时生效
|
||||
const auto backendKey = [&cfg] {
|
||||
return cfg.modelId + QLatin1Char('|') + cfg.language + QLatin1Char('|') + cfg.captureDevice;
|
||||
};
|
||||
QString activeKey = backendKey();
|
||||
// 后端相关项(模型/语言/采集设备/流式参数)变化才需要重启;外观类改动即时生效
|
||||
QString activeKey = backendKeyOf(cfg);
|
||||
|
||||
const auto openSettings = [&] {
|
||||
lc::SettingsDialog dlg(false);
|
||||
QObject::connect(&dlg, &lc::SettingsDialog::settingsApplied, &window, [&] {
|
||||
lc::models::ModelStore::setRootOverride(cfg.modelDir);
|
||||
applyAppearance(window, cfg); // 透明度/字号等立刻可见
|
||||
if (backendKey() != activeKey) {
|
||||
if (startTranscriber()) activeKey = backendKey();
|
||||
if (backendKeyOf(cfg) != activeKey) {
|
||||
if (startTranscriber()) activeKey = backendKeyOf(cfg);
|
||||
}
|
||||
});
|
||||
if (dlg.exec() == QDialog::Accepted) {
|
||||
lc::models::ModelStore::setRootOverride(cfg.modelDir);
|
||||
applyAppearance(window, cfg);
|
||||
if (backendKey() != activeKey) {
|
||||
if (backendKeyOf(cfg) != activeKey) {
|
||||
if (!startTranscriber()) {
|
||||
QMessageBox::warning(&window, QObject::tr("启动失败"),
|
||||
QObject::tr("模型加载失败,请检查设置。"));
|
||||
} else {
|
||||
activeKey = backendKey();
|
||||
activeKey = backendKeyOf(cfg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user