Commit Graph
17 Commits
Author SHA1 Message Date
fanlusky c280634c2a fix(engine,server): 词库切到 WAL,避免调频写入阻塞按键线程
选词后的调频写入在词库写线程上提交 msime_user.db / msime.db。两个库都是
默认的 rollback-journal 模式,提交时持独占锁并 fsync,按键线程此时读同一个
库(引擎查询、apply_fixed_positions)就得等完整个提交。磁盘忙或杀软扫描
-journal 时单键可达 0.7~1.1 s,后续按键排队;排队期间按空格/数字会超过 TSF
300 ms 的上屏回复等待,组合被当作传输失败丢掉,表现为输入消失。

- 用户日志库每次建连接时切到 WAL;msime.db 在每次创建输入会话时切到 WAL
  (安装升级会换上非 WAL 的新文件)。WAL 下读取看到最近一次提交的快照,
  不再等写锁。安装器已保留 msime_user.db-wal/-shm、替换词库前删除旧的
  msime.db-wal/-shm。
- ensure_schema 的 PRAGMA user_version=3 本身是写操作,版本已一致时跳过,
  建连接不再被其他写者阻塞。
- 新增回归测试:两个库都被写事务锁住时,读取须在 1 s 内返回提交前的内容。

本地用真实词库加锁测量:被锁时首键 769 ms -> 0.5 ms,
apply_fixed_positions 810 ms -> 0.4 ms。
2026-10-02 14:57:31 +08:00
fanlusky e32eeadec9 fix(engine): 调频比较集跨键合并,按权重而非显示顺序取基准
打 jian 时列表里混着另一种切分 ji'an 的词。吉安 在出货词库里权重是 1,压在同组的
积案(9420)/几案(5999) 底下,而 adjust_candidate_ranking 按音节数圈比较集,于是
吉安 只跟 ji'an 这一组比,可学权重封顶一万出头,永远追不上 见 的 3460998——用户
选多少次,这个候选都纹丝不动。

音节数这个尺度是 #400 加的,为的是挡住另一个 bug:显示列表里备选切分词会被保护位
顶到最前面,中点数学却假定列表按权重降序,于是拿 西鄂(w=6) 当基准把 写 写成 506。
根子在「显示顺序 != 权重顺序」,按音节数滤掉跨表行只是绕开了症状,代价是把每个候选
关进自己的组里。

改成在比较集上直接按权重降序排一次,不变式在源头恢复:任何行都不可能坐在高于自身
权重的位置上充当基准,西鄂 那条路被堵死;同时比较集不再按音节数切开,吉安 的基准
取到整个列表最重的 见,置顶一次即越过,promote 模式连选五次一路走到首位。写入仍只
落在 entry_key 的行上,#36 的护栏不变。

test_user_dictionary_journal 新增两条回归(跨键置顶、连续 promote 收敛到首位),
#400 的两条断言原样保留并仍然通过。
2026-09-19 22:14:57 +08:00
Jia Sui 9bbd86b633 fix(engine): 调频权重基准限定同音节尺度
置顶/提升把一个候选的权重算成「显示列表首位权重 + 500」。显示列表会混入
备选切分词和不同切分的候选,它们的权重是另一套尺度(单字表是语料计数、
多字表是词组词权),于是基准取错就把候选写成垃圾值:用户机器上 xi'e 的西鄂
(w=6) 坐在 xie 列表首位时,置顶写会写出 506(= 6+500),低于些/血/谢,反而
被埋到三十名开外;将也以同样方式被写成 24240(= 激昂 23740+500)。

- 候选的 rank 与权重基准改在同音节尺度内计算:同音节数的表互相可比(九宫格
  数字上下混多个单字表、简拼上下文混多个 key 都保留原语义),跨音节数不再
  互相充当中点基准。选中词已是同尺度首位时不再写权重,避免被跨尺度反降。
- 写入仍按 entry_key 走,rebalance 不会落到别的 key 的行上(#36 的护栏不变)。

test_user_dictionary_journal 增加回归:混表列表里置顶写必须以些为基准,
且不再把些本身写成 506。
2026-09-14 20:14:28 +08:00
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
fanlusky ac8394291b fix(tests): keep the shared test header free of engine dependencies
The portable test target builds on a bare Linux runner with no vcpkg tree, so
the UTF-8 path helper cannot live in test_framework.h -- including the engine's
data_path.h there broke the sanitizer build. Move it to test_utf8_path.h, which
only the Windows tests that need it include.
2026-09-09 04:48:56 +08:00
fanlusky 55605973d8 fix: build filesystem paths as UTF-8, not through the ANSI code page
Narrow strings in this repo are UTF-8, but std::filesystem converts narrow
strings through the system ANSI code page. The two agree only on ASCII, so any
path crossing that boundary breaks for users whose profile directory is not
ASCII -- and on a code page that cannot represent the characters at all,
path::string() throws rather than mangling.

The user dictionary replay tool hit exactly that. It handed the journal API
paths converted with path::string(); on a Chinese user name the conversion
threw, the exception escaped main(), and MSVC fastfailed the process with
0xC0000409. The installer treats any non-zero exit from replay as fatal, by
design, so those users could not upgrade at all. Build the paths from the wide
form via path_from_utf8/path_to_utf8 instead, and wrap main() so an unexpected
failure reports a diagnosable message and exit 1 rather than a fastfail code.

The skin catalog had the same defect: toml::parse_file(manifest.string())
routed the manifest path through the ANSI code page, and skins live under the
user profile. The throw escaped past the toml handlers around it. Read the file
through the wide path and parse the text instead.

Also drop FanyUtils::GetIMEDataDirPath, which built a path from the ANSI
environment block and dereferenced getenv without a null check. It had no
callers.

Tests cover the three layers this spans: the conversion contract itself, the
journal API in-process, the replay tool as the installer actually launches it,
and the skin catalog. Each non-ASCII case is paired with an ASCII control so a
failure says whether the path encoding or the data caused it. The replay and
skin tests were both confirmed to fail with their fix reverted.

Test fixtures pass paths through the new test::Utf8 helper rather than
path::string(), since the temp directory sits inside the user profile too.
2026-09-09 04:35:34 +08:00
Evan 42238a2af6 style: 用 .clang-format 重排 server / windows / ui / log
一次性重排,无任何行为改动。四个目录各自的 .clang-format 放在仓库里已久,但全组织只有
MSIME-Linux 在 CI 里执行 clang-format 检查,这边 149 个文件里有 149 个不符合自己声明的风格。

已逐文件核对语义等价:去掉空白、注释与相邻字符串字面量拆分之后,全部 149 个文件与重排前逐字节
相同。差异只有三类——缩进与换行、clang-format 补的 } // namespace 结尾注释、以及长字符串被拆成
相邻字面量(C++ 保证自动拼接)。

这个提交会写进 .git-blame-ignore-revs。
2026-09-06 12:13:47 +09:00
fanlusky 7c0461fe3a Fix adjust word frequency issue. 2026-08-29 23:56:50 +08:00
fanlusky 27a7143050 Fix the issue where English words created by Enter cannot be replayed during new version installation. 2026-08-25 22:50:06 +08:00
fanlusky 38fe99be62 Add a function that commits the raw string when the Enter key is pressed and records the string into the dictionary. 2026-08-25 19:05:25 +08:00
fanlusky e08feaa713 Add regression tests for the issue where promoting xianwang candidates hid 先 from later xian queries.
Fixes metasequoiaime/MetasequoiaImeTsf#36
2026-08-20 14:01:00 +08:00
fanlusky 23d78f161a Fix the issue where some database entries fail to replay during installation. 2026-08-04 23:25:21 +08:00
fanlusky f70d210465 In auxiliary code mode, AI prediction should not send requests, just like cloud prediction. 2026-07-31 16:12:03 +08:00
fanlusky 21fb3a9e2e feat(settings): add user dictionary export support
- export Pinyin, Wubi, English, and quick-phrase dictionaries
- export unknown-source multiword Pinyin entries
- filter single-character Pinyin entries
- generate UTF-8 text files with dictionary-specific formats
- add coverage for insertion tracking and bounded ranking
2026-07-29 01:17:18 +08:00
fanlusky 025f966a90 perf: reuse persistent database connections for fixed candidates 2026-07-27 20:46:49 +08:00
fanlusky e8736d66b9 feat: integrate candidate ranking, pinning, and cache refresh 2026-07-27 20:25:27 +08:00
fanlusky d5523dd44d feat: preserve user dictionary changes across updates 2026-07-27 16:32:34 +08:00