Files
fanlusky 80b1fc42a1 feat(engine): 词格整句改用 kenlm 三元模型打分
词格原先的整句打分是一份没校准过的启发式 unigram,质量很差。这里内嵌 libime
在用的 kenlm 查询子集,改由它的三元模型 sc.lm 来打路径分。

- engine/ngram 只编 kenlm 的 query / trie-build 路径。不定义 WITH_THREADS,
  parallel_read.cc 因此退化成串行实现,整个子集零 Boost 依赖。
  KENLM_MAX_ORDER=3 必须与建模阶数一致,改它等于读不懂已发布的模型文件。
- ngram::LanguageModel 是唯一 include kenlm 头文件的地方,对外只给出一个纯
  std 的头,_HAS_AUTO_PTR_ETC 和 kenlm 的 include 目录都保持 PRIVATE。
- shared_language_model 按资源路径共享一份 mmap。kenlm 的查询是只读的且把
  上下文放在调用方的 State 里,所以并发会话不需要额外加锁。
- 模型缺失时 valid() 为假,词格退回原来的启发式打分:整句候选只是变差,不会
  停止工作。测试覆盖了缺模型降级与按路径共享。
- 出货的 ARPA 不带 <s>/</s>,所以解码从 null_state() 起算而非 begin_state()。

kenlm 是上游副本,不重排版、不进 clang-format,其 LGPL-2.1+ 与 BSD 例外清单
已补进 THIRD_PARTY_NOTICES.txt。googlepinyinime 那条 Fallback 整句路径不变。
2026-09-19 10:08:39 +08:00

43 lines
1.5 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
// 只在编译 kenlm 的 util/file.cc 时强制包含(见 CMakeLists.txt)。
//
// kenlm 的 Windows 分支用 _open(name, ...) 打开模型文件,而 _open 的窄字符路径
// 走的是进程 ANSI 代码页。本仓的路径一律是 UTF-8(RuntimePaths / data_path.h 的
// 约定),用户名带中文时资源目录就落在 ANSI 页外,_open 会直接失败。
//
// 这里在 namespace util 里提前声明同名函数:file.cc 的调用点是非限定的
// _open(...),非限定查找先看最内层的 util,于是解析到下面这两个重载,转成宽字符
// 调用。不改上游源码、不改进程代码页,与原先给 googlepinyinime 用的
// core/pinyin_file_io.h 是同一手法。
#ifdef _WIN32
#include <filesystem>
#include <io.h>
#include <share.h>
namespace util
{
// _wsopen_s 而不是弃用的 _wopen:模型文件会被 Server、TSF DLL、设置进程同时读,
// _SH_DENYNO 正是 _wopen 隐含的共享模式。
inline int _open(const char *path, int flags)
{
int fd = -1;
// pmode 只在 _O_CREAT 时被用到,这个重载的调用点不传 _O_CREAT。
if (::_wsopen_s(&fd, std::filesystem::u8path(path).c_str(), flags, _SH_DENYNO, 0) != 0)
{
return -1;
}
return fd;
}
inline int _open(const char *path, int flags, int pmode)
{
int fd = -1;
if (::_wsopen_s(&fd, std::filesystem::u8path(path).c_str(), flags, _SH_DENYNO, pmode) != 0)
{
return -1;
}
return fd;
}
} // namespace util
#endif