Commit Graph
108 Commits
Author SHA1 Message Date
luo jiyin 136d440517 Merge branch 'develop' into perf/neural-skip-padding 2026-10-03 17:05:48 +08:00
luojiyin 1b5e7a71e4 refactor(engine): name compact logit slots
Use slot for compact logits and row for Transformer positions.
2026-10-03 16:40:00 +08:00
luojiyin 1acc3d6745 perf(engine): skip unused neural scoring positions
Skip vocabulary projection for positions without targets.

Remove the final unused Transformer position from each candidate row.

Add coverage for empty candidates in mixed batches. Refs #593.
2026-10-03 16:40:00 +08:00
fanlusky b8ceeef7f9 fix(engine): 重查时不再重复排正在打分的同一批候选
回调触发的重查会问到刚被后台取走、还没算完的那一批:结果表里没有,待办位也空着,
于是同一批又排了一份。用户连续打字时每个回调都可能白算一次;benchmark 里这份重复
任务会在 clear() 之后写回结果,让下一轮误报 neural_already_visible 或把等待计入
async_ms。

按模型记下正在算的键,同键请求直接返回并丢掉该模型更旧的待办。
2026-10-03 16:35:48 +08:00
luojiyin a7087a0cdf fix(engine): label benchmark session caches precisely 2026-10-03 10:23:53 +08:00
luojiyin 68b791c771 perf(neural): add async rerank end-to-end benchmark 2026-10-03 10:09:08 +08:00
fanlusky 233ac9ef33 feat(engine,server,windows,ui-html,installer): 句中辅助码触发键可多选,新增分号
设置页「句中辅助码触发键」可勾选反引号和分号,至少保留一个。

- 分号只在 AcceptsMarkerAt 成立(这一节是偶数键)时才当触发键;微软/搜狗/紫光双拼的
  ing 韵母只跟在奇数键之后,两者不抢同一个位置,判断时分号先让给 ing 韵母
- 无论按哪个键,TSF 按键缓冲、Server raw 与引擎输入串里都记成反引号,引擎解析不变
- 新配置项 helpcode.shuangpin_mid_sentence_helpcode_backtick / _semicolon 同步写入出厂
  模板、工作配置与两个设置宿主
- opcode 28 保持「反引号是否触发」、载荷单个 "0"/"1"(TSF 会丢弃更长的帧);分号走新增
  的 opcode 29,旧 DLL 忽略它
2026-10-02 23:55:46 +08:00
Jia Sui 72c1d7ddb0 fix(engine): darts-clone 登记为 vendored 副本,脱离格式门禁
0976c307 随octagram 读取端入库的 darts-clone 0.32h 不在 format.sh 的排除名单里,
而它整份文件都不符合仓里的 .clang-format,本分支一旦推上去 CI 的
Check formatting 就会报 1826 处违规。

按精确路径排除 darts.h,不按目录:同目录的 octagram_gram.{h,cpp} 是我们自己的
代码,必须继续受门禁管,目录级排除会连带把它们一起豁免掉。

与上游 v0.32h(87b71afd)比对后确认这份副本并非原样入库,而是带 6 处本地改动
——open() 删掉 256 单元头部校验与两段式读、save() 删掉 offset 参数、
commonLongestPrefixSearch 整体删除、DoubleArrayBuilder 三个常量改为
static const std::size_t、一处注释拼写。这些此前没有任何地方记录,是它掉出
名单却一直没被发现的原因;逐条写进 UPSTREAM.md,升级 darts-clone 时才能重放。
前两条与 mmap 装载自洽(octagram_gram 走 set_array,不经过 open/save)。

两份 AGENTS.md 里硬编码的「那三个上游副本」清单同步为四个。
2026-10-02 22:00:36 +08:00
Jia Sui 01c45c8d90 fix(server,ui-html,engine): octagram 激活中的模型包也可删除,引擎映射支持动态释放 2026-10-02 20:15:41 +08:00
Jia Sui 03c0a4246d feat(server,ui-html,engine,installer): 接入社区多 octagram 模型,分模型下载与单选激活 2026-10-02 20:15:40 +08:00
Jia Sui 8089841e78 fix(engine): octagram 头按外部头暴露,darts.h 收窄告警不再刷屏 2026-10-02 20:15:40 +08:00
Jia Sui e1a664a194 fix(server): 万象下载器改用格式锁,撤下无依据的评测宣称
锁定值与上游实际资产不符(字节数 409719852 vs 409412652,摘要 ae43724a… vs 873cbbb3…),下载在字节锁处失败。上游 LTS 会被原地重传且无不可变资产 URL,摘要硬锁意味着每次重训都要改代码发签名安装包,否则全用户下载失败,这个成本消不掉。

改为锁格式:删字节数常量,总长取响应 Content-Length 并在收完后比对一次(截断检测);新增 ValidateFormat 让引擎读取端自己开一次(魔数 + 双数组边界,不按文件自带长度做堆分配)。摘要不再参与放行,只判断 reviewed 并写入旁挂 .sha256(状态查询要频繁调用,不能每次重算 400MB 哈希)。真实上游字节按 open() 判据复核精确贴边通过:array_size=102353152,收尾正好在 409412652。

kReviewedSha256 保留旧值,摘要不符即 reviewed=false,设置页明示「上游已更新,未经评测」,NOTICE 记录实际摘要与字节数并附差异说明。契约无需重生成:sentence_collocation_model_status 是两个宿主各自拼的 ad-hoc JSON,不在 schema.json 内。

撤下无法验证的宣称:设置页删掉「评测 top1 +6 个百分点」(仓里没有评测工具、没有 docs/research,该数字无法复现),改为描述机制;清掉两处对从未进仓的文档与工具的引用(docs/research、tests/src/gram_reader、eval_lm_compare);修正 octagram_gram.h 里被本次改动失效的「摘要校验在下载侧做」。配置只改注释、未增删键,五件套映射不适用。
2026-10-02 20:15:39 +08:00
Jia Sui 2925fabf4a feat(contracts,ui-html): 设置页新增万象模型下载与开关
- 契约新增客户端消息 collocationModelDownload / collocationModelStatusRequest
  (bindings 经 generate.py + sync-contracts.py 再生)
- 设置页整句区新增:模型状态卡片(未下载/下载中 x%/就绪/失败原因)、下载按钮、
  「万象搭配加成整句」「万象搭配重排整句」两个开关
- 下载中页面每 2 秒发 collocationModelStatusRequest 拉新快照,进度与按钮态随
  configSnapshot 的 association.sentence_collocation_model_status 应用
2026-10-02 20:15:39 +08:00
Jia Sui cc738f19ca feat(engine): 词格接入万象搭配加成与 n-best 重排
SentenceAssociationOptions 新增四个字段(模型路径、加性权重、重排开关、重排权重),
随 QueryRequest 下发到全拼与双拼词典:

- 加性(接入点 A):collocation_scorer 在 Viterbi 逐边叠加字级搭配分,与三元模型
  同域竞争,离线评测 top1 89.4% -> 95.6%(w=0.25)
- 重排(接入点 B):make_octagram_reranker 在解出的 n-best 上按整句搭配分重排,
  以独立来源 CandidateSource::Collocation 出行(徽标〔万象〕),落库/学习判定与
  神经整句同类
- 模型路径由宿主按模型包解析后传入,UTF-8 经 path_from_utf8 显式转换;模型缺席
  时词格静默降级,与其余整句来源同范式

同时修正 test_pinyin 里一处 9 月底起与实现矛盾的断言:重排器同意词格排序时,
行保持词格来源(Generated)而非记到重排名下——以 word_lattice.h 的单重排器契约
与 merge 实现为准。原断言所在的 imetest 不进 CI,因此一直没被发现。
2026-10-02 20:15:39 +08:00
Jia Sui 0976c3072c engine(ngram): 万象语法模型(octagram .gram)读取端转为产品件
从评测工具的移植版升级为引擎库成员:装载从整文件 ReadFile 换成 Win32 mmap(RSS
只随命中页增长),新增进程内按路径共享的 shared_gram_db(照
ngram::shared_language_model 范式,查询全只读、多会话并发安全)。eval_lm_compare
改用同一份实现,评测与产品不再有两套读取器;darts.h(BSD)随目录入库。
2026-10-02 20:15:39 +08:00
Jia Sui c87684272b engine(quanpin): 词格加可选的字级搭配打分接缝
WordLatticeOptions 新增 collocation_scorer/collocation_weight(默认关闭,产品路径
零行为变化):为 octagram(.gram)这类与词表零耦合的字级搭配语法模型预留加性
打分入口。假设额外携带路径尾部文本(至多 8 个码点),句尾词以 is_rear 标记,
供 .gram 的「词+\$」rear 项参与打分。
2026-10-02 20:15:39 +08:00
fanlusky 45c473158a feat(engine,server,windows,ui-html): 双拼预编辑可显示转换后的全拼
外观里行内预编辑与候选窗预编辑各加一个「双拼显示转换后的全拼」开关,默认关闭。
开启后在双拼方案下:行内原始按键显示不带分词符号的全拼,拼音分词显示带分词符号的
全拼;候选窗显示带分词符号的全拼。

- 引擎新增 get_shuangpin_preedit_forms,同时给出原串切分与全拼切分,不受
  shuangpin_preedit_mode 影响。
- 原始按键样式下 TSF 不等 Server 回包,开关开启且为双拼时 Server 下发的实际样式
  改为 pinyin,回包里再按用户样式去掉分词符号;换方案时重新下发。
- 转换后字母数与按键不再对应,Server 在预编辑末尾附光标映射表
  (engine/contracts/preedit_caret_map.h),DLL 用它定位光标和处理方向键,
  无表或长度不符时回落到原有字母映射。
2026-10-02 16:14:50 +08:00
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 31241d22ed fix(engine,server,windows): 句中辅助码支持光标在句中插入,上屏按不带约束的排序调频
光标用箭头或 Ctrl+箭头移回句中后敲反引号,TSF、Server、引擎三处都要求光标在串尾,
反引号被当成标点,光标前的预编辑连同「·」一起上屏。改为只看光标前的部分:光标前是
完整的两键音节就收,落在音节中间或已有段的前面不收。形状规则新增
FanyImeMidSentenceHelpcode::AcceptsMarkerAt,三处共用;引擎的光标插入路径同时接受
句中的第一码和大写第二码。

句中辅助码筛过的列表里,要的词往往已经排第一,选第一个不调频,调了也是在筛过的列表
里排位,下次不敲辅助码时排序不变。现在带句中辅助码上屏词库候选时,改用去掉约束后的
候选作排位参照,选的是第一个也照样调;空格、数字键、鼠标点选都走 ProcessSelectionKey,
引擎自己的上屏路径同样处理。
2026-10-02 12:43:16 +08:00
fanlusky cec3118324 feat(engine): 新增日期时间混输候选来源
CandidateSource 末尾追加 DateTime,标记全拼 / 双拼里由 rq / sj / xq 等唤醒词混进普通候选的
日期、时间、星期;Shift+T 模式里的同一批文本仍记 Generated。快捷短语槽位计数不把它算作普通候选。
2026-10-02 03:39:13 +08:00
fanlusky fae80660c1 feat(engine,server,windows,ui-html): 双拼句中辅助码
在完整音节后敲反引号,接着的字母筛这个音节上的字:第一码大小写均可,
紧跟的大写字母是第二码,之后可以接着打,一个输入里可以有多段。开关
helpcode.shuangpin_mid_sentence_helpcode 默认关闭。

约束在整句解码时生效,而不是解完再筛:
- Google 解码器在 add_char_qwerty 里送 extend_mtrx_nd 之前按约束过滤词条,
  锁住的字带着上下文重新整句解码;约束变化时整段重解,不污染增量搜索。
- kenlm 词格建图时按约束筛边,受约束的跨度不截断地查词库;神经重排只在
  词格 n-best 里挑,自动满足约束。
- 普通词条、云和 AI 候选按同一规则收尾校验;满足不了就不出整句。

反引号段在请求里换成手动分隔符,原串留给宿主回读与预编辑显示;选词推进
时剩余音节上的约束随原串保留。输入形状规则放在 contracts/mid_sentence_helpcode.h,
TSF、Server、引擎共用,新增 Worker opcode MidSentenceHelpcodeChanged = 28。
googlepinyinime-rev 已与上游解绑,AGENTS 与 UPSTREAM.md 同步说明。
2026-10-02 02:20:37 +08:00
fanlusky 8004bc9250 fix(engine): imetest 直接链接正式引擎库,修正与实现不符的重排来源用例
engine/tests 手抄了一份引擎源文件清单,2c3546f8 新增 local_database.cpp
时只登记到 engine/CMakeLists.txt,imetest 自此链接失败;清单还漏了
shuangpin_custom_profile.cpp,也没有正式构建给 googlepinyinime 加的
/FI pinyin_file_io.h 与 /utf-8。改为 add_subdirectory 引擎根目录、链接
MetasequoiaIme::Engine,引擎源只在一处登记;vcpkg 依赖对齐根清单,
删掉无人引用的 includes/main.h。

test_pinyin.cpp 的「重排器同意」用例期望来源记为 NeuralDesktop,但
e7f7addd 引入的实现(word_lattice.h 的契约)是把被认可的三元首选提前、
来源仍为 Generated。以实现为准改测试。imetest 现在完整通过。
2026-10-02 00:52:12 +08:00
fanlusky e502201fd9 fix(engine): 全拼别名改写后的 preedit 保留合法切分与手动分隔符
#565 让合法键入在被别名改写后退回无分隔的原始字母,多打一个字母就会丢掉
已显示的全部分隔符(hao'yong -> haoyonga)。现在按键入字母自身的合法读音
重新切分(hao'yong'a、dong'an)。BFS 无法解释时的退路改为原样显示键入,
不再吞掉用户手打的分隔符(haoyonga' 不再显示为 haoyonga)。

测试拆成两组:走简拼守卫的合法拼写,与走退路的输入。dongua、zhonguo 不经
过守卫,归入退路组,此前它们在修复前也能通过,不构成守卫分支的回归用例。
2026-10-01 22:57:51 +08:00
Lu Fan(SonnyCalcr) 9529ac2d10 Merge pull request #565 from metasequoiaime/fix/quanpin-alias-preedit
fix(engine): 全拼合法键入被别名改写后 preedit 不再照搬改写串
2026-10-01 22:48:46 +08:00
Jia Sui efdea2c14f fix(engine): 全拼合法键入被别名改写后 preedit 不再照搬改写串 2026-10-01 15:09:32 +08:00
Jia Sui 1da7b06682 fix(engine): kenlm 字符流不再解引用 end 迭代器,MSVC Debug 测试可正常运行 2026-10-01 15:06:46 +08:00
fanlusky 3f430cd68e fix(server): 双拼辅助码开启时快捷短语奇数长编码不再被拦掉
双拼开着辅助码时,「完整音节 + 一个字母」的编码(如 dia = di + a)会被认成带辅助码,
快捷短语混排见到辅助码就直接退出,这类编码的短语永远进不了候选。整串精确等于用户编码时
按短语处理,Server 的 PlaceQuickPhrases 与引擎的 quick_phrase_code 一并去掉辅助码判断,
并补双拼 dia 的回归用例。
2026-10-01 02:35:55 +08:00
fanlusky c99fb8d585 fix(engine): 英文调频不再以中文权重为基准,并按输入记英文槽位
混输列表里英文调频把「全表最高权重 + 1000」写成新权重,中文候选也算在内。
在 zai 下选一次 zaire,它的权重就变成 19,196,987,超过「在」,并且对所有能查出它的输入永久生效。

- adjust_english_candidate_ranking 只用英文候选的权重当基准
- 新增 english_slots 表和 english_slot / set_english_slot /
  learn_english_slot_selection / learn_english_slot_bypass:按输入记录首个英文候选在列表中的位置,
  选中时按调频名次前移(可以升到首位),越过它时后退一位,最多到首页末位
- 新增 InputSession::reads_as_pinyin:整串能否读成拼音(允许简拼声母和打到一半的音节)
2026-09-30 22:49:27 +08:00
Lu Fan(SonnyCalcr) 5a74ee7a17 Merge pull request #557 from metasequoiaime/fix/rescore-worker-terminate
fix(engine): 别让重排后台线程的异常把输入法带走
2026-09-30 22:41:34 +08:00
fanlusky 0bc2ec1f19 test(engine): 重排回调在锁内 notify,避免碰到已析构的条件变量
等待方一拿到锁就可能离开作用域、析构栈上的 mutex 和条件变量,锁外 notify_all 会落在已析构的对象上。三个后台线程用例都改成在锁内 notify。
2026-09-30 22:34:05 +08:00
Jia Sui 5d8487a490 fix(engine): 别让重排后台线程的异常把输入法带走
Signed-off-by: Jia Sui <jsfaint@gmail.com>
2026-09-30 22:08:23 +08:00
Jia Sui 4fde941291 fix(engine): 测试的 main 再补一层 catch (...)
只接 std::exception 的话,第三方库或跨 FFI 边界抛出来的东西照样会逃出 main 走 abort,
和上一个 commit 修掉的是同一类故障:ctest 看不到原因,栈也不展开。引擎内现有的抛出确实
都是 std::exception 派生,但这一层缺的是「无论什么异常都到不了 terminate」的保证,补上它
才让 main 的边界真正闭合。

只加 catch 分支,输出通道沿用各文件原来那一个(fprintf / cerr / fmt::println),
不改任何断言。
2026-09-30 21:34:12 +08:00
Jia Sui 74e0a16776 fix(engine): 让测试的 main 接住逃逸的异常
这些测试用 throw 报告断言失败,但 13 个测试的 main 没有顶层 try,异常一路逃出去就会
走 std::terminate -> abort。abort 不做栈展开,ScopedDataDirectoryCleanup 的析构不执行,
测试建的临时目录和用户词库句柄留在原地;失败原因也不会打到 stderr,ctest 只能看到一段
崩溃,排查时得先猜是哪个断言。

按仓里已有的写法把函数体挪进 run_test(),main 变成一层薄包装,catch 里打 what() 再返回 1。
fuzzy_pinyin 的 create_directories 原本落在 try 之前,一并挪进去。

只是给失败换一条能读到的出口,没有改任何断言或阈值。
2026-09-30 21:32:07 +08:00
fanlusky e365a8d1b5 perf(engine): 大模型改为只读映射并按需载入,缩短每键查询路径
- sc.lm 改用 kenlm 的 LAZY 载入:Windows 上默认的 POPULATE_OR_READ 会退成 READ,
  把 33 MB 整份拷进私有堆且永不释放;现在是 MapViewOfFile 只读映射,可被系统回收
- dict_japanese.dat 在 Windows 上同样改为只读映射,与 POSIX 分支一致
- 神经整句模型改为开关首次生效时才载入(LazySentenceModel),默认关闭的桌面模型
  不再占用约 24 MB
- 新增 reset_sentence_cache():重排结果与上文只影响词格整句,只清 series 一层,
  逐前缀查库与切分缓存保持热;set_rescoring_context 也改用它
- CircularBuffer 新增 find():命中时返回指针而不复制整份候选列表,并改为真正的 LRU;
  全拼、双拼每键的命中路径改用它
- Google 解码器去掉每次调用前的 im_reset_search,沿用上游的公共前缀增量搜索
- 测试:出货 sc.lm 能映射载入并正常打分;增量搜索与从头搜结果逐步一致
2026-09-30 19:58:18 +08:00
fanlusky 9f5572c525 fix(build): 所有 MSVC 目标显式按 UTF-8 编译源文件
#548 修了 ngram,同类问题还有几处:源文件或头文件是无 BOM 的 UTF-8,
目标却没有 /utf-8,在代码页 936 的系统上注释会吞掉换行。

- ui:Controls.h 让 msimeui 与各 demo 单独构建失败,/utf-8 设为 PUBLIC
- server/tests/portable:input_key_policy.h 让 MSVC 构建失败
- engine test_windows_ipc_contract、tests/pipe-probe、windows/tests:C4819
- windows DLL:此前只靠 fmt 的 INTERFACE 选项带来 /utf-8,改为显式设置,
  否则 L"“" 等宽字符标点会在去掉 fmt 后静默变成乱码
2026-09-30 15:37:13 +08:00
Lu Fan(SonnyCalcr) 68742373e3 Merge pull request #548 from ouchihao/codex/fix-436-ngram-utf8
fix(engine): compile ngram sources as UTF-8 on MSVC
2026-09-30 15:36:12 +08:00
fanlusky 375e1bcd48 feat(engine): 新增候选框翻页箭头消息 candidatePage
候选页点击翻页箭头时发出 candidatePage,数据限定为 previous / next。
同步重新生成 TypeScript / C++ 绑定与 ui-html/webview2/shared 副本,并补充契约用例。
2026-09-30 12:42:14 +08:00
Ouchihao 9b867175d7 fix(engine): compile ngram sources as UTF-8 on MSVC 2026-09-30 03:02:12 +08:00
fanlusky 42fbb9541c feat(engine): 快捷短语混入全拼 / 双拼候选并参与调频
Shift+K 快捷短语模式保留,仍按编码前缀查询(query_quick_phrases)。另外全拼 / 双拼下
编码精确匹配(query_quick_phrases_by_code)的快捷短语作为一组插在固定位置候选之后,由
LocalModeOptions::quick_phrase_candidates 单独开关;五笔不混。

用户日志新增 quick_phrase_slots 表记录快捷短语组前的普通候选数:选中短语让组前移,
越过组选普通候选让组后移,后移上限为页长减一。quick_phrase_frequency 关掉时组固定在
首位。与普通候选同文本时保留快捷短语那份。
2026-09-29 14:31:51 +08:00
fanlusky c9b86e0026 feat(engine): 支持用户自定义双拼方案
用户在数据目录 shuangpin\custom\ 下放 TOML 文件,在设置页以 custom/<文件名>
选用。零声母规则从 o、a、first_letter、full_pinyin 四种里选,声母和韵母
映射由文件指定,可用 [zero_initials] 覆盖个别零声母音节。

- 引擎:新增 CustomShuangpinLayout 与 BuildCustomShuangpinProfile,校验缺键、
  声母撞键,并对全部音节做往返解码,冲突时给出可读的错误信息;新增运行时
  方案注册表,按需加载。
- Server:扫描并解析自定义方案,配置快照带上方案列表与目录;文件缺失或无效
  时回退到小鹤。
- 设置页:仿照自定义辅助码,新增打开目录和刷新按钮;无效方案列出但禁用,
  悬停时显示错误。
- 安装器:覆盖安装与迁移数据目录时保留 shuangpin 目录。
- 文档:docs/custom-shuangpin.example.toml 提供带详细注释的示例。
2026-09-29 11:33:23 +08:00
fanlusky f56551c34b feat(engine): 内置搜狗、紫光、智能ABC、国标和拼音加加双拼方案
新增五套双拼方案表,零声母规则:
- 搜狗、紫光、智能ABC:o + 韵母所在键
- 国标:a + 韵母所在键
- 拼音加加:韵母第一个字母 + 韵母所在键

搜狗和紫光与微软一样把 ing 放在分号上。分号作韵母键原先按方案名写死为
microsoft,现改为 ShuangpinProfileUsesSemicolonFinal 按方案表判断,
引擎、Server 按键处理和下发给 TSF 的开关一并生效。

智能ABC 键位图把 ve 也标在 V 上,但这样 lv/nv 会同时解成 lü 与 lüe,
这里按标准智能ABC 把 ve 放在 M(与 ue 同键)。

Server 配置校验改为按方案解析结果判断;设置页下拉框、配置模板注释和
README 同步更新;新增各方案键位、零声母、分号及全方案逐音节往返测试。
2026-09-29 03:52:19 +08:00
fanlusky 738435b002 fix(engine): 全拼长句不再为更短的前缀补 Google 整句
前缀查不到词时 query_single_path 会补一条 Google 整句,长句候选后面于是缀上一串越来越短的〔Unigram〕子串。整句联想只对完整输入出一句,前缀只取词库里的词,查不到就交给更短的前缀。
2026-09-29 02:22:57 +08:00
fanlusky d0feee74cc fix(engine): 修正五笔混输的候选方案标记、通配排序与固定位置去重
- 首字母展开与固定位置补入的拼音候选不经过 query(),此前保留默认 Quanpin,
  双拼会话里调频/删除会落到全拼引擎;现在按查询方案打标。
- 混输与 z 通配同时开启时,含 z 的编码拼音候选排在通配结果之前,避免通配
  整页码行把 zi/zu 这类拼写的正解挤到后几页。
- 固定位置分区合并时,拼音分区 include_missing 补回的词若五笔分区已列出则去掉,
  保持同词只留五笔一份。
2026-09-29 00:12:46 +08:00
Jia Sui e9c824266f test(engine): 恢复被拒第五键不改候选的断言 2026-09-28 18:31:18 +08:00
Jia Sui a9920cb40f perf(engine): 五笔设置未变化时不再重建候选 2026-09-28 18:29:50 +08:00
Jia Sui a50232f06c fix(engine): set_wubi_mixed_pinyin 不再复位 z 通配开关 2026-09-28 18:28:42 +08:00
Jia Sui 456fdb819c feat(engine,server,ui-html,installer): 五笔拼音混输改为同时混排并拆出独立开关
Signed-off-by: Jia Sui <jsfaint@gmail.com>
2026-09-28 17:55:36 +08:00
fanlusky 69ee4fb49b test(engine): 新增逐键耗时基准 bench_input_session
在真实词库上逐字母输入几串典型拼音(单词、短语、整句),每串前清空候选缓存,
按整句联想的几档设置统计每个键在引擎里的耗时(中位数 / p90 / 最大)。只构建、
不注册 ctest,也不选词、不写用户日志;用 METASEQUOIA_IME_DATA_DIR 指向数据目录
的副本运行。

本机一次结果(ms/键,冷缓存,5 轮):

  设置                中位数   p90    最大
  全关                 0.10    0.19   1.04
  词格                 0.39    2.12   3.97
  词格+Google          0.34    1.93   4.43
  全开(含两档神经)   0.44    2.72   5.61

引擎查询本身不是打字卡顿的来源,性能工作应放在绘制、IPC 与 UI 线程等待上。
2026-09-27 17:02:04 +08:00
fanlusky 2c3546f823 perf(engine): 简拼、快捷短语、表情、颜文字查询复用词库连接
这四种模式每个键都新开一次 SQLite 连接,第一次 prepare 还要解析整个 schema
——msime.db 有两百多张分表。新增 local_modes/local_database,四个查询统一经它
打开只读连接:路径正是当前数据目录下的 msime.db 或 others.db 时共享一条连接,
其余路径(测试、工具)照旧每次独立打开、用完即关。

只共享这两个随安装包发布的库:msime.db 本来就被引擎整个会话持有,others.db 只在
Server 停止时由安装程序替换;保持其它文件常开会让删除它们的工具或测试在 Windows
上失败。close_default_user_database() 同时释放这些连接,调用方原本就用它在删除
或替换数据目录前放开文件。

引擎测试(本地单独构建,CI 不跑)23/23 通过;不加释放钩子时 input_session、
mixed_expressive_input_session、jianpin_input_session 会因目录删不掉而失败。
2026-09-27 16:10:01 +08:00
fanlusky 8f2c81dd0f perf(server,engine): 选词学习的写库挪出按键线程
权重调整(AdjustCandidateRanking)和输入过的英文词(LearnEnteredEnglishWord)
原本和按键排在同一个 worker 队列里:每次选非首位候选都要在下一个键之前付一次
用户日志的提交和 fsync,触发阈值时还有 msime.db 的一次提交。磁盘忙或杀软扫描
时,这就是肉眼可见的卡顿。

- server/src/utils/serial_task_runner:单线程、按提交顺序执行、低优先级,Stop()
  先执行完队列再退出,选词不会在退出时丢失。附单元测试。
- 两类写入改为投递给这个执行器。它们只调用 user_dictionary,不碰输入会话;唯一
  的会话副作用——权重变化后清引擎候选缓存——经 EnqueueResetInputSessionCacheTask
  回到 worker。删除对应的 TaskType 和 Task 字段。main 在 worker join 之后调用
  ShutdownDictionaryWriter()。
- user_dictionary:默认日志连接改为每线程一条。FULLMUTEX 只保证单次调用安全,
  保证不了事务:连接只有一个事务状态,写线程的 BEGIN IMMEDIATE..COMMIT 会把
  worker 的读卷进来,worker 侧 UserDatabase 析构时还会把它回滚。
  close_default_user_database() 递增代号,各线程下次访问时关闭旧连接。
- WorkerThread 取任务改为 move,不再每次复制整个 Task。

行为变化:选词后如果写入还没完成就立刻再打同一串,会短暂看到旧顺序;写完后
worker 清缓存,下一次查询即是新顺序。此前的“下一个键之前一定写完”换成了不阻塞
按键。
2026-09-27 16:09:51 +08:00