Files
msime-windows/engine/local_modes/quick_phrase_query.cpp
T
fanlusky a7779d2b05 refactor(engine): 将 engine 从 submodule 内嵌为仓内一等组件
`vendor/MetasequoiaImeEngine` submodule 改为 `engine/` 目录,导入的是
product-lock.json 原本钉住的提交 c810d201,逐文件核对过 blob,因此这是一次
搬迁而不是引擎升级。引擎自己的嵌套 submodule(googlepinyinime-rev、utfcpp、
miniaudio)按各自 gitlink 一并展开,来源与提交见 engine/UPSTREAM.md。

Windows 专门化裁掉了不属于本产品的部分:whisper.cpp 与本地推理 provider、
macOS 示例宿主、整个 dictionary/ 建库流水线、上游 CI 与 release-please 配置。
词库仍按 product-lock.json 在构建时取发布产物。

引擎不再进 product-lock.json:没有 gitlink 就没有可比对的东西,锁里写一个上游
commit 等于宣称这棵树仍等于上游,而第一个 Windows 专门化改动落地时这句话就假了。
verify-contracts / verify-checkout 随之移除,verify-published 保留。

CI 与工具链:引擎源码并入根 scripts/format.sh(删掉引擎自己的那份,避免两套排除
列表分叉);引擎 voice.yml 里的 silero_vad.onnx 摘要校验移到本仓 lock job;
engine-bump-triage 工作流与其测试删除;gitsubmodule 的 dependabot 频率由 daily
改为 monthly。

README、README.en、AGENTS.md、CONTRIBUTING、docs/product-release.md 及各子目录
文档同步说明新的位置与边界。
2026-09-12 03:40:48 +08:00

118 lines
3.7 KiB
C++

#include "../contracts/assets/assets.h"
#include "quick_phrase_query.h"
#include "../core/data_path.h"
#include <sqlite3.h>
#include <algorithm>
#include <memory>
namespace metasequoia::local_modes
{
namespace
{
struct DatabaseCloser
{
void operator()(sqlite3 *database) const
{
if (database != nullptr)
{
sqlite3_close(database);
}
}
};
struct StatementCloser
{
void operator()(sqlite3_stmt *statement) const
{
if (statement != nullptr)
{
sqlite3_finalize(statement);
}
}
};
using Database = std::unique_ptr<sqlite3, DatabaseCloser>;
using Statement = std::unique_ptr<sqlite3_stmt, StatementCloser>;
bool valid_prefix(const std::string &prefix)
{
return !prefix.empty() && std::all_of(prefix.begin(), prefix.end(),
[](unsigned char character) { return character >= 'a' && character <= 'z'; });
}
QuickPhraseQueryResult query_failure(const char *diagnostic)
{
return {{}, std::string(diagnostic)};
}
} // namespace
QuickPhraseQueryResult query_quick_phrases(const std::string &prefix, int limit)
{
return query_quick_phrases(prefix, data_file_path(metasequoia::assets::main_dictionary), limit);
}
QuickPhraseQueryResult query_quick_phrases(const std::string &prefix, const std::filesystem::path &database_path,
int limit)
{
if (!valid_prefix(prefix) || limit <= 0)
{
return {};
}
if (database_path.empty())
{
return query_failure("Quick phrase database is unavailable.");
}
sqlite3 *raw_database = nullptr;
if (sqlite3_open_v2(path_to_utf8(database_path).c_str(), &raw_database,
SQLITE_OPEN_READONLY | SQLITE_OPEN_FULLMUTEX, nullptr) != SQLITE_OK)
{
if (raw_database != nullptr)
{
sqlite3_close(raw_database);
}
return query_failure("Quick phrase database is unavailable.");
}
Database database(raw_database);
sqlite3_busy_timeout(database.get(), 1000);
constexpr const char *kSql = "SELECT key,value,weight FROM quick_parases WHERE key>=?1 AND key<?2 "
"ORDER BY weight DESC,key,value LIMIT ?3";
sqlite3_stmt *raw_statement = nullptr;
if (sqlite3_prepare_v2(database.get(), kSql, -1, &raw_statement, nullptr) != SQLITE_OK)
{
return query_failure("Quick phrase database could not be queried.");
}
Statement statement(raw_statement);
std::string upper_bound = prefix;
upper_bound.push_back(static_cast<char>(0x7f));
if (sqlite3_bind_text(statement.get(), 1, prefix.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK ||
sqlite3_bind_text(statement.get(), 2, upper_bound.c_str(), -1, SQLITE_TRANSIENT) != SQLITE_OK ||
sqlite3_bind_int(statement.get(), 3, limit) != SQLITE_OK)
{
return query_failure("Quick phrase database could not be queried.");
}
QuickPhraseQueryResult result;
int step_result = SQLITE_ROW;
while ((step_result = sqlite3_step(statement.get())) == SQLITE_ROW)
{
const auto *key = reinterpret_cast<const char *>(sqlite3_column_text(statement.get(), 0));
const auto *value = reinterpret_cast<const char *>(sqlite3_column_text(statement.get(), 1));
if (key != nullptr && value != nullptr)
{
result.candidates.emplace_back(key, value, sqlite3_column_int64(statement.get(), 2),
CandidateSource::QuickPhrase);
}
}
if (step_result != SQLITE_DONE)
{
return query_failure("Quick phrase database could not be queried.");
}
return result;
}
} // namespace metasequoia::local_modes