impress_voice_input/src/app/config_manager.cpp
impressionyang f4b7149435 feat: 支持手动指定日志目录和调试音频目录
- 新增 app.log_dir 配置项,支持通过设置页面或命令行 (-l/--log-dir) 指定日志目录
- 调试音频目录 (audio.debug_dir) 已正确传入 StreamingAudioWriter
- 设置页面新增"通用设置"分组,包含日志目录选择
- 未设置时使用系统默认 AppDataLocation 路径

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 14:00:23 +08:00

169 lines
4.9 KiB
C++

#include "config_manager.h"
#include "utils/logger.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStandardPaths>
#include <QDir>
static const char* const kTag = "ConfigManager";
namespace impress {
ConfigManager::ConfigManager(QObject* parent)
: QObject(parent)
{}
bool ConfigManager::load(const QString& path) {
QMutexLocker locker(&mutex_);
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
LOG_ERROR(kTag, QString("无法打开配置文件: %1").arg(path));
return false;
}
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
if (error.error != QJsonParseError::NoError) {
LOG_ERROR(kTag, QString("JSON 解析错误: %1").arg(error.errorString()));
return false;
}
config_ = doc.object().toVariantMap();
configPath_ = path;
LOG_INFO(kTag, QString("配置已加载: %1").arg(path));
return true;
}
bool ConfigManager::save() {
if (configPath_.isEmpty()) {
// 自动生成默认路径
QString appDataDir = QStandardPaths::writableLocation(
QStandardPaths::AppDataLocation);
QDir().mkpath(appDataDir);
configPath_ = appDataDir + "/config.json";
}
return saveAs(configPath_);
}
bool ConfigManager::saveAs(const QString& path) {
QMutexLocker locker(&mutex_);
QFile file(path);
if (!file.open(QIODevice::WriteOnly)) {
LOG_ERROR(kTag, QString("无法写入配置文件: %1").arg(path));
return false;
}
QJsonDocument doc(QJsonObject::fromVariantMap(config_));
file.write(doc.toJson(QJsonDocument::Indented));
configPath_ = path;
LOG_INFO(kTag, QString("配置已保存: %1").arg(path));
return true;
}
void ConfigManager::loadDefaults() {
{
QMutexLocker locker(&mutex_);
config_ = QVariantMap{
{"app", QVariantMap{
{"log_dir", ""}
}},
{"stt", QVariantMap{
{"model_path", ""},
{"model_type", "sense_voice"},
{"tokens_path", ""},
{"device", "cpu"},
{"num_threads", 4},
{"sample_rate", 16000},
{"language", "zh"},
{"streaming", true},
{"beam_size", 5},
{"temperature", 0.0},
{"debug_save_audio", false},
{"capslock_voice_enabled", false}
}},
{"audio", QVariantMap{
{"input_device", -1},
{"buffer_size_ms", 20},
{"chunk_duration_ms", 3000},
{"padding_ms", 500},
{"debug_dir", ""}
}},
{"ui", QVariantMap{
{"theme", "light"},
{"font_size", 14},
{"show_waveform", true},
{"show_confidence", true}
}},
{"shortcuts", QVariantMap{
{"voice_hotkey", "CapsLock"}
}}
};
}
emit configChanged();
}
QVariant ConfigManager::get(const QString& key, const QVariant& defaultValue) const {
QMutexLocker locker(&mutex_);
return getValue(config_, key.split('.'), 0, defaultValue);
}
QVariant ConfigManager::getValue(const QVariantMap& map, const QStringList& parts,
int index, const QVariant& defaultValue)
{
if (index >= parts.size() || !map.contains(parts[index])) {
return defaultValue;
}
if (index == parts.size() - 1) {
return map[parts[index]];
}
auto childMap = map[parts[index]].toMap();
return getValue(childMap, parts, index + 1, defaultValue);
}
void ConfigManager::set(const QString& key, const QVariant& value) {
{
QMutexLocker locker(&mutex_);
setValue(config_, key.split('.'), 0, value);
}
// 锁释放后再发射信号,防止槽函数中调用 get() 时死锁
emit configChanged();
}
void ConfigManager::setBatch(const QMap<QString, QVariant>& pairs) {
{
QMutexLocker locker(&mutex_);
for (auto it = pairs.constBegin(); it != pairs.constEnd(); ++it) {
setValue(config_, it.key().split('.'), 0, it.value());
}
}
// 锁释放后再发射信号,只发射一次
emit configChanged();
}
void ConfigManager::setValue(QVariantMap& map, const QStringList& parts,
int index, const QVariant& value)
{
if (index >= parts.size()) return;
if (index == parts.size() - 1) {
map.insert(parts[index], value);
return;
}
if (!map.contains(parts[index]) || !map[parts[index]].canConvert<QVariantMap>()) {
map.insert(parts[index], QVariantMap());
}
auto childMap = map[parts[index]].toMap();
setValue(childMap, parts, index + 1, value);
map[parts[index]] = childMap;
}
void ConfigManager::resetToDefaults() {
loadDefaults();
LOG_INFO(kTag, "配置已重置为默认值");
}
} // namespace impress