97 Commits
Author SHA1 Message Date
Lu Fan(SonnyCalcr) a60e2948db fix(engine): 整句联想按 P(读音|字) 压住多音字的生僻读音 (#1123)
tai'zhuan'qian'le 出「大赚钱了」:大 也读 tai,词库里这一行权重 4719,占 tai 的
0.47%,已有的 reading_prior(看 P(字|拼音),1% 免罚线)只扣 0.33,翻不过语言模型
对「大赚」约 1.6 的偏好。换个角度看,大 读 tai 只占它全部权重的 0.14%——这才是
「这个字几乎不这么读」,语言模型只认汉字,这一维要由读音补上。

词格跨度查询对单字行加一项 P(读音|字) 惩罚:占比低于 10% 的部分按 log10 扣分,
上限 2.5。长 chang、重 chong、行 hang 这类常见第二读音不扣;大 tai/dai、会 kuai、
都 du、给 ji 扣 1.5~2。只罚单字,词本身就是读音的证据(会计、成都、大夫)。多音字
各读音的权重和在第一次整句联想时扫一遍单字表载入,全拼与双拼(含直接辅助码)共用。

自建 111 句多音字评测从 79 提到 82,无回归;5% 档翻不过「大赚钱了」,20% 与 10%
结果相同,取保守的一边。test_engine_smoke 加固定权重的断言,句子评测集补两条。
2026-10-20 08:47:27 +08:00
Lu Fan(SonnyCalcr) 5de73de7a6 feat(engine,server,windows): 双拼末尾辅助码支持间接触发,句中辅助码单独成区 (#1068)
双拼辅助码新增「直接辅助码」开关(默认开,行为不变)。关掉后末尾辅助码改由引导键触发:
反引号、分号、大写字母可多选,触发键后接一到两个辅码(如 ulpb;xy、ulpbXy),一码重排、
两码筛选,只在输入末尾生效。触发键在 TSF 缓冲与 Server raw 里统一记成 |,与句中辅助码的
反引号段区分。

两组触发键互斥:一边勾上某个键会取消另一边的同一个键;手改配置两边都勾时归句中辅助码。
新增 Worker 消息 EndHelpcodeTriggersChanged(37),旧 DLL 忽略。

设置页把句中辅助码单独成区(仅双拼),其中间接(引导键)与直接(万象式)两种方式互斥。
新配置项同时写进出厂模板与开发配置。
2026-10-18 22:54:17 +08:00
Lu Fan(SonnyCalcr) d912a926b7 fix(engine): 修复谷歌整句解码器去重越界写导致双拼 zjle 时 Server 崩溃 (#1064)
zan'l 的末尾半音节让「赞了」经 zan'le / zan'liao 各出一次。get_lpis 多字分支
先跳过等于整句候选的第一份,再遇到分数更好的重复项时 remain_num 仍为 0,
写到 lma_buf[-1]。改为先丢掉所有等于整句候选的项再去重。

Fixes #1063
2026-10-18 21:34:56 +08:00
Lu Fan(SonnyCalcr) 23bfdd4d51 feat(engine,server): 符号混输放开拼音读音,emoji 混输改为整串精确匹配 (#1050)
- 符号混输不再挡读得成拼音的编码:混输本来就只认整串精确匹配,xi → ξ 也照样混入;单字母编码仍不混。
- 构建器读取 msime-dictionary 新增的 custom/symbols.txt(拼音<TAB>符号),把 dian → · 、、
  shuminghao → 《》 〈〉 等标点读音写进 symbol_code,书名号、引号、括号成对给出。
- emoji 混输改用新的 query_mixed_emoji,只认整串精确等于关键词,不再按前缀带出 emoji;双拼下只查
  展开后的全拼,并和符号一样只在光标位于末尾时查询。Shift+E 的 emoji 模式仍按前缀查。
- 同步更新设置页说明、出厂与开发配置注释和 README。
2026-10-18 11:23:26 +08:00
Lu Fan(SonnyCalcr) 3cd429b19d feat(server): 加入 S 模式符号输入与符号混输 (#1047)
符号数据改用 rime-wanxiang 的符号表与 typst/codex 符号名,源数据放在
msime-dictionary 的 sources/symbols/,替换原来的 piliapp 符号表。

- 建库:新增 symbols_db.py,生成表情面板用的 symbol_catalog(中文分类)和
  S 模式、符号混输用的 symbol_code;剔除 wanxiang-unrenderable.txt 列出的
  Windows 自带字体显示不了的符号,以及与 ① ❶ 看不出区别的 Dingbats 带圈数字
- 新增 scripts/check-symbol-rendering.py,用 Windows 字体生成上面的剔除清单
- Shift+S 进入符号模式,按万象分组码(xl、sx、szq)、数字读音(yi → 一 ① ⑴)
  或符号名(alpha、infinity)检索
- 符号混输:整串精确等于编码时混入,首个紧跟首选;读得成拼音的编码只混数字
  序号写法;双拼先按方案换算成全拼再查(小鹤 sj → san → ③)
- 表情面板符号页:中文分类,搜索把整词命中的符号列在「最佳匹配」
- 配置:utility.symbol_mode(默认开)、general.symbol_mixed_input(默认关)

Refs #795
2026-10-18 02:08:39 +08:00
古明四季andfanlusky 0bad4c1aaa fix(engine): 修复日语分段选词吞掉后续输入 (#1020)
* fix(engine): 修复日语分段选词吞掉后续输入

* fix(engine): 日语分段选词后重建混排候选并去掉剩余输入开头的分隔符

固定候选位打开时 candidates() 返回混排列表,分段选词后不重建就还是选词前整串的候选,
下一次选词会选到过期项。ka'ta 选「か」剩下 'ta,开头的分隔符转不出假名,剩余输入一个
候选都没有;现在和拼音路径一样去掉,去掉后为空就按整串上屏处理。
已转换部分的边界改用 segments,与整句候选同一来源。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-17 17:41:01 +08:00
Jia Suiandfanlusky 3b1206ea82 fix(windows,engine): 提交键回复等待不再因超时重置会话或丢字 (#1019)
* fix(windows,engine): 提交键回复等待不再因超时重置会话或丢字

服务端按键处理偶发数百毫秒尖峰时,提交键(空格顶首选 / 确定选词 / 标点顶高亮候选)
的回复等待会走到会话内那条 300ms 同步读;一超时就被判成 TransportUnavailable
→ DeliveryAmbiguous → Transport 完整重置(丢键 + 吞队列 + 清组合 + 轮换 epoch),
用户看到的是整段已输入内容消失。

- 删除 FANY_IME_COMMIT_REPLY_SESSION_WAIT_MS 那条破坏性兜底读。会话侧改为非阻塞探测,
  拿不到回复返回「未就绪」,由 session 自身在 DoEditSession 内交回,沿用同一个
  FANY_IME_COMMIT_REPLY_TIMEOUT_MS 分片轮询窗口,不重开窗口、不新造等待原语。
- 交回必须发生在 session 内部:RequestEditSession 用 TF_ES_ASYNCDONTCARE,TSF 异步授权
  时调用方读不到 session 的 HRESULT;若靠调用方读返回值,该键会既不丢也不提交,
  deferred 闸门再不打开(后续按键全部只入队)。也不能改用 TF_ES_SYNC(WinWord 上不成立)。
- 真失败(写失败 / 读失败 / 坏帧 / 字节数不符 / 无 request id / 无管道)仍判 Transport 重置。
- 预取覆盖面扩到 candidate 类 finalize(空格顶首选等),堵住原先只能靠那条 300ms
  兜底读的路径。
- 新增按键级延迟诊断 bench_key_latency_diag(build 里有同名 exe 但源码已不在树),
  以及两份对照测试:commit_reply_not_ready(回复三态与交回状态机)、
  candidate_consistency(同配置下候选集合/顺序/分页逐字一致,引擎侧护栏)。

实测(bench_key_latency_diag):稳态逐键 median 0.6~0.8ms / max 12.5ms,尖峰指向内存
压力下的页回收而非稳态算力。在「结果完全不变」的约束下,预热 / 缓存 / 投机预解码均无效
或反向,故本次不改引擎打分路径。

* fix(windows): 直接标点提交会话补齐未就绪交回,并写准窗口沿用边界

审查 `7aca5e5d` 发现的问题:

- `CPunctuationCommitEditSession` 在 `FANY_S_COMMIT_REPLY_NOT_READY` 时只抑制了 token
  结算(`applied` / `_FailDeferredKey` 都不走),**没有**像 `CKeyHandlerEditSession` 那样把
  请求交回 `_PollCommitReply`。一旦走到这条分支——`_HandleCompositionPunctuation` 的高亮候选
  分支要求 `_candidateMode != CANDIDATE_NONE`,而派发该会话的条件是
  `_candidateMode == CANDIDATE_NONE`,两者在 session 执行时才求值——deferred token 会永久留在
  飞行中,后续所有按键只入队不处理,正是本 PR 在别处修掉的失效模式。现在两处都交回,
  并把原因写进注释,避免下一个人再照半个写法抄一遍。
- `_HandOffUnreadyCommitReply` 的两处注释与实现不符或不够具体:交回沿用第一片已经开始的窗口;
  只有从未开窗的路径(标点处理函数在派发时高亮候选条件为假、session 执行时条件成立)才在此
  开窗,那种情况键一点没等过、`waitedMs` 为 0。另一支(无法保活 → `_FailUnansweredCommitKey`)
  只在请求不属于协作轮询时到达,实务上即 `commitReplyMessage == 0`:派发没能用消息窗,
  没有可交回的对象。

签名相应扩展:`_RequestDirectPunctuationEditSession` 新增 `commitReplyMessage` /
`commitReplyDeadlineTick`,`CPunctuationCommitEditSession` 携带它们。没有行为回退,两个新参数
默认 0 时与改动前一致(而那正是「无消息窗」的既有降级路径)。

验证:windows x64 Release 构建通过,`ctest` 17/17 通过,`clang-format 18.1.8 --dry-run
--Werror --style=file` 对本次涉及文件全过。

* fix(windows): 把 _HandOffUnreadyCommitReply 移到公共区,修 CI 编译失败

CI 的 Windows x64 与 Windows Win32 两条腿都挂在同一处编译错误:

  MetasequoiaIME_AsyncRequests.cpp: error C2248:
  “CMetasequoiaIME::_HandOffUnreadyCommitReply”: 无法访问 private 成员

上一提交给 CPunctuationCommitEditSession 补「未就绪交回」时调用了这个成员,但它在 private
区。CKeyHandlerEditSession 能调是因为它在 MetasequoiaIME.h 里被显式声明为 friend;而
CPunctuationCommitEditSession 定义在 MetasequoiaIME_AsyncRequests.cpp 的匿名命名空间里
(该文件 31-254 行),头文件里的 friend 声明指不到它,加 friend 也无效。

处置:把该声明移到公共区,与同样由 session 调用的 _FailDeferredKey、_CompleteDeferredKeyReplay、
_HandleCompositionPunctuation 并列,并在注释里写明「它必须公共」的原因,免得下次有人顺手挪回私区。
仅可见性与注释,行为零变化。

验证(triplet 与 CI 一致,且这次看退出码、不截断构建输出):
- x64-windows-static:cmake --build build --config Release --parallel 退出码 0;
  ctest --no-tests=error 17/17。
- x86-windows-static:cmake --build build32 --config Release --parallel 退出码 0;
  ctest --no-tests=error 17/17。
- clang-format 18.1.8 --dry-run --Werror --style=file 对本次改动文件通过。

另:上一轮「构建通过」是我误报——当时用 Select-String 过滤构建输出又加了 -Last 8,错误行被截掉,
且没有检查 $LASTEXITCODE;ctest 过的是测试目标,与 DLL 编译失败并不冲突。

* fix(windows): 提交回复交回后轮询不再停摆,同步兜底保留有界等待

- 轮询定时器按请求 id 判断是否仍在等待:session 交回时换了新 token,
  按旧 token 查会误判为已结算并 KillTimer,交回的请求从此无人再分发。
- 没有轮询可交回的 session(同步 _InvokeKeyHandler 路径)恢复
  FANY_IME_COMMIT_REPLY_SESSION_WAIT_MS 的单次有界等待,不再一读不到就丢键重置。
- 确定并输入在提交回复为传输失败时不再继续键入字符并返回 S_OK。
- session 交回占用新槽位时同样受 kMaxPendingAsyncKeys 约束。
- 修正注释:未就绪由 session 自己的完成钩子交回,不是消息处理函数。
- 测试:覆盖轮询分发、等待上限与满表交回;SAL 剥离按最长前缀匹配;
  引擎一致性用例③不再清缓存,否则测不到跨输入的缓存泄漏。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-17 16:19:26 +08:00
Jia Suiandfanlusky d270395816 fix(engine): 简拼尾组合路径放开静态邻键纠错并拒生成式远键 (#1009)
* fix(engine): 简拼尾组合路径放开静态邻键纠错并拒生成式远键

整串 k-best 解释不了时回退到「head 纠错 + 简拼尾组合」,该路径原本把邻键位整段屏蔽,导致邻键手误的 head 纠不回来(shabgz -> shang'z)。

改为三条规则:head 用完整掩码(静态邻键进来);head 最优切分带 has_generated 时拒(k-best 静态优先,等价无静态读法,挡 huanzg -> huang'g);存在自洽明文读法时跳过组合(挡最短尾拆 sh/zh 后静态邻键改写正确输入,xish -> xia'h 类 39 起,及 huanzh -> huang'h)。

* fix(engine): 纠错用例取词库路径改用 path_to_utf8,非 UTF-8 ACP 下不再抛异常

新增的 head+简拼尾用例用 (directory / msime.db).string() 取路径。MSVC 的 path::string() 走本机 ACP,而测试临时目录名含中文(metasequoia-session-词库-…),在 ACP 表示不了它的机器(CI runner 的英文版 ACP 1252)上会抛 ERROR_NO_UNICODE_TRANSLATION,也就是 CI 日志里的 No mapping for the Unicode character exists in the target multi-byte code page.,input_session 因此失败。文件其余取路径处一律走 metasequoia::path_to_utf8,改齐。

本地 ACP 936 能表示该中文,故本地未复现;本地沙箱另限制子进程建临时目录,端到端只能由 CI 验证。

* fix(engine): 简拼尾组合的 head 也过简拼形状门,挡住 xibd -> xin'd

规则 3 只认「完整音节 head + 简拼尾」,漏掉「完整音节 + 两个简拼声母」:
xibd(xi + b + d)在 0xe/0xf 下最短尾 d 留下 head xib,静态邻键 b->n 把它
读成 xin,组合出 xin'd 顶掉明文;tamd、zhemd 同理。这正是旧邻键掩码要挡的
那类噪声。

改为让 head 过整串同一道 looks_like_jianpin_spelling 门:整串不纠的
"shag"(sha + g),后面多接一个简拼尾也不该纠。shabgz、hauzh 等正例不受影响。
顺带合并两遍 tail 扫描,去掉恒等于 autocorrect_types 的 head_types。

xibd/tamd/zhemd 补进 test_input_session 回归表(改动前 xibd 实测为 xin'd),
test_pinyin 用 xibd 替换被删的 shng 负例。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-17 00:05:17 +08:00
Lu Fan(SonnyCalcr)andli shiyan c67814caf8 feat(server): 改进中文模式下英文补全词形和首页候选 (#1010)
* feat(server): expand mixed English completion choices

* fix(server): count fixed English in the first-page English budget

- Fixed-position English never takes the slot, regardless of
  first_page_count; fixed English on the first page counts toward the
  budget and the page room, and the first-page emoji is placed so that
  re-inserting fixed words returns it to the last slot.
- SlottedEnglishIndex returns the first unfixed English, so slot
  learning keeps working when the top-ranked English is fixed.
- Drop the protected-prefix lower bound on the completion target: it
  pushed the single default completion off the first page.
- Protect cloud/AI (and AI following English) from the extra English
  even with a learned slot.
- Keep the legacy five-row prefix query for the default single English
  candidate; only first_page_count > 1 uses the mixed distinct-word query.
- Let SetConfiguredEnglishMixedInputFirstPageCount own the range check.

---------

Co-authored-by: li shiyan <150001555+lsy9966303@users.noreply.github.com>
2026-10-16 23:00:06 +08:00
HowGeGeandfanlusky 1671c3a467 fix(engine): recognize complete umlaut aliases in quanpin (#994)
* fix(engine): recognize complete umlaut aliases in quanpin

* refactor(engine): 移除九键输入

九键会话只有引擎公共 Session 门面在用,Server 与 TSF 都没有接入。删掉
NineKeySession、Session 的九键入口与 SessionSnapshot::nine_key_spellings,
以及对应测试和注释。

* fix(engine,server): ü 别名共用一条归一规则,入库与纠错不再产出查不到的键

- 新增 quanpin::is_jqxy_v_alias / canonical_umlaut_spelling,替换 canonical_syllable
  与 to_google_spelling 里各自手抄的别名表,normalize_umlaut_aliases 也改用它。
- 纠错表生成器与运行时生成式空间不再从 jqxy+v 别名派生纠错键(nvan -> jvan 之类),
  手误只纠到 u 的标准写法;重新生成 autocorrect_table.h。
- 个人词库新写入的拼音词、设置页导入的全拼按词库写法入库(xvan -> xuan、lue -> lve),
  否则查询归一后永远查不到;被替换的旧词保留原键,旧行仍可删除。
- 双拼音节集统一排除 jqxy+v 别名,round-trip 检查不再特判。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-16 20:48:33 +08:00
Jia Suiandfanlusky 93f95d1245 fix(engine): emoji / 颜文字查询精确命中优先于前缀命中 (#989)
* fix(engine): emoji 查询精确命中优先于前缀命中 (#988)

* fix(engine): 颜文字查询同样精确命中优先于前缀命中 (#988)

* fix(engine): emoji / 颜文字精确提级只认全拼,并合并为单次排序查询

- 双拼下原始码只按目录顺序参与前缀命中,不再精确提级:小鹤 xl 精确命中简拼键时会压过展开后的 xiang。
- 颜文字只有全拼精确命中提级,简拼精确命中不提级:单音节条目的简拼只有一个字母,打 k 时会整批排到前面。
- 两级查询合并为每个查询码一条 SQL(精确行在 LIMIT 之前),语句只 prepare 一次,循环抽到 local_database 的 query_ranked_entries 共用。
- server 回归测试不再断言 ku 多个精确条目之间的目录顺序。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-16 20:17:01 +08:00
Jia Suiandfanlusky d414268b5f [Feat] U 模式重构为部件拆字反查 (#973)
* feat(engine,server,windows,ui-html,installer): U 模式重构为部件拆字反查 (#971)

把 U 模式从 Unicode 十六进制码位输入改成部件拆字反查:Shift+U 后输入各
组成部分的拼音连写(晶 = ririri)即可出字,候选上反显注音。

- 引擎:新增 local_modes/radical_query(前缀匹配、字频降序),数据表
  engine/radical/decomposition.txt 与生成脚本;LocalInputMode::Unicode
  改为 Radical;删除 unicode_query。
- Server:g_radical_mode_triggered + IsRadicalCompositionActive + 候选分发,
  用 cpp-pinyin 反显注音;删除 Unicode 码位路径。
- 前端 TSF:删除 U 模式的十六进制/数字特例与影子预判,按普通组合处理。
- 配置:utility.unicode_mode 改为 utility.radical_mode。
- 部署:assets 登记 radical_decomposition,安装器与 CI 拷表。

数据来源 mirtlecn/rime-radical-pinyin (GPL-3.0),授权见 engine/radical/NOTICE.md。

* feat(server): U 模式反显拼音改为带调风格(jīng)

* fix(server,installer): 修复 U 模式 CI(拆字表打包夹具与 clang-format)

* fix(engine,server): 修正 U 模式按键错位、重复候选与配置迁移

- Server 在 U 模式不再吞掉撇号、分号、斜杠、大写字母等键:TSF 已把它们记进按键缓冲,
  吞掉又不重同步会让两侧串和光标错位。照常插入,含非 a-z 的码查不出候选
- 拆字查询全码命中排在仅前缀命中之前,同一个字的几种拆法只出一次
- 升级合并把旧键 utility.unicode_mode 的值带到 utility.radical_mode,读取时也兜底旧键
- 生成脚本只收汉字,重建拆字表去掉 abc 码下的 51 行数字、字母与符号
- 开着 U 模式时在后台预热拆字表与 cpp-pinyin 词典,避开首个按键的冷加载
- Server 按会话的 RuntimePaths 查拆字表,删掉走全局数据目录的便捷重载
- cpp-pinyin 初始化合并到 utils/hanzi_pinyin,设置页导入注音共用;U 模式与快捷短语的收键分支合并

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-16 01:01:18 +08:00
Jia Suiandfanlusky 456b23ed94 feat(engine,server): 五笔支持 T 模式与 V 模式 (#942)
* feat(engine,server): 五笔支持 T 模式与 V 模式

五笔方案此前被排除在 Shift+T 日期时间模式与 V 模式之外。根因是方案层就把
raw 归一成小写 a–y、丢弃数字与运算符,Server 的形状判定读不到大写 T/V 前缀。

- 引擎 WubiScheme 新增 raw_input_with_cases_:保留大小写与 T/V 模式的非字母键
  (数字、运算符、: /),但按码字域丢掉越域字母(默认配置下 z)。查询码仍由
  normalize_wubi_code 派生,普通码下两者长度相等——Server 用原样串长度数四码。
- Server:T 触发新增独立谓词 date_time_scheme(chinese_scheme || Wubi),不并入
  chinese_scheme 本身;FormatVModeWorkerPayload 对五笔返回 UppercaseOnly。
- 自动上屏 / 顶字两个谓词新增 special_mode_active 前置:T 模式关键词归一后可能与
  合法四码重合(Tdate → tdat),不挡会在第四个字母上结束模式。
- 引擎与 Server 测试、README 与两份配置模板文案同步。

* fix(engine,server,ui-html): 五笔 T/V 模式由宿主标注字面输入

原实现让五笔原样串不再裁到码长,普通码下原样串可以比码长(混输关、z 通配时 wqazb 对 wqaz),
Server 读回后光标、退格和上屏都会错位;守卫也只认 T 模式的全小写主体,TdatE 仍会顶出 tdat。

- 引擎:InputSession::set_wubi_literal_input 随 pending 序列一起下发,只作用于同一次设置。
  普通码的原样串就是带大小写的码,与查询码逐位对应、一起截断;字面输入原样保留,
  不查码表与拼音,也不算完整四码。退格从原样串重新派生码,字母键两份视图取同一个字母。
- Server:ApplyCompositionEditKey 按 IsWubiLiteralComposition(T 模式触发标记或 V 模式形状)
  标注字面输入;两个五笔上屏策略恢复原签名,不再需要 special_mode_active。
- 设置页 T/V 模式说明补上五笔。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-15 02:08:36 +08:00
Jia Suiandfanlusky 1499027f04 fix(engine,server): 光标落在拼音首单元内部不再收起候选窗 (#940)
* fix(engine,server): 光标落在拼音首单元内部不再收起候选窗

quantized_prefix_end() 把光标 floor 到完整单元边界后,prefix_end==0 同时表示「真串首」与「首单元内部」。后者被 Server 的 IsCaretPrefixEmpty 当成串首,候选窗整窗收起(全拼 nihaoya 选你好后剩 ya 左移即消失)。

floor 结果为 0 且 caret>0(首单元内部)时改返回 raw.size(),落回整串解码;prefix_end()==0 当且仅当 caret==0,只有真串首才隐藏。segment_raw_boundaries() 与 #187「前缀只切完整单元」的契约不变。

* fix(engine,server): 首单元内部的光标向上取整到首单元末尾

上一提交让首单元内部的光标落回整串解码,prefix_end() 因此报告整串已解码,
与实际光标位置不符:Server 选词时 caret_prefix_selection 为假,不复位组合
光标,造词后剩余串带着旧光标位置;首单元与后续单元的取整方向也不一致。

改为向上取整到首单元末尾(只有一个单元时即整串)。prefix_end() == 0 仍当且
仅当 caret == 0,前缀选词走正常的光标复位路径。同步更新引擎与
input_key_policy.h 中描述旧规则的注释和相应测试。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-15 01:37:58 +08:00
Lu Fan(SonnyCalcr) 119c439d7a fix(engine,server): 日文候选不再写进拼音词库,升级回放跳过已残留的日文词 (#907)
日文 provider 出的候选没有设置 scheme,默认是 Quanpin。在日文模式下选非首选
候选时,Server 按拼音调频,用罗马音作键(pan、amarini)写进拼音日志。msime.db
里没有这些行,UPDATE 改不到任何东西,但 update_pinyin_weight 照样记了日志;
升级回放时 apply_pinyin 找不到行就插入,日文词于是出现在全拼候选里。

- 日文候选标上 SchemeType::JapaneseRomaji
- Server 的选词调频、置顶、造词与云候选落库跳过日文候选
- update_pinyin_weight 没改到行时不写日志
- 回放跳过、打开日志时清掉自动学习来的带假名拼音条目;手动加的词不动

Fixes #869
2026-10-13 12:54:29 +08:00
Jia Suiandfanlusky 60c2b26698 fix(engine,server): 全拼纠错收窄「多字」纠错并让开关真正关闭纠错 (#889)
* fix(engine,server): 全拼多字纠错收窄为仅 QWERTY 邻键插入

多字(插入)纠错只保留「误插 QWERTY 邻键」:生成器 insertion_variants 不再生成重复相邻键(双击),生成式空间不再生成任意字母插入(远键插入)。autocorrect_table.h 随生成器重新生成。

* fix(engine): 全拼纠错开关关闭时真正不再改写切分

纠错开关关掉后真正不纠错:把手误拼写别名层从常开改为跟掩码走(ü 归一 jv->ju / nue->nve 仍常开);两个早于掩码可知的切分入口 QuanpinScheme::build_request 与 QuanpinDictionary::get_or_compute_segments 显式带上掩码,切分缓存键随之隔离。

* fix(engine,server): 纠错开关关闭时辅助码、写回与排序上下文也按字面切分

关掉全拼纠错后,只有方案的 build_request 和查询自身切分不再跑手误别名层,
其余几条路径仍用默认(带别名)的切分,和查询落在不同的键上:

- 辅助码路径自己切底串作为显式切分交给词典,haoyonga 仍被切成 hao'yong'ga;
- 调频、造词、删词、建 SQL、校验去掉分隔符后重切,开关关掉时选中 hao'yong'a
  的词会去更新 hao'yong'ga,调频静默失败;
- 排序 / 固定位置的上下文 key(引擎与 server 两处)仍按别名切,laing 与 liang
  的固定位置互相串。

改动:
- cut_pinyin_by_mode 的 include_correction_aliases 改为必填,每个调用点显式决定;
  双拼词典、设置页词库校验和离线工具传 true,保持原行为。
- 新增 quanpin::correction_aliases_enabled,方案、词典、辅助码与排序 key 共用
  (只看换位、邻键两位),修正只带删除 / 插入位的掩码在方案与词典两层判断不一致。
- 词典按最近一次 query 的掩码记录别名开关,写回路径统一走 cut_for_write。
- 会话改为在换方案、改开关时 bind_quanpin_scheme 一次,不再每次 refresh 下发。
- 方案只存 bool;jv -> ju 放回纠错表,去掉合并表。
- 在 CI 实际执行的 test_input_session 中补回归用例(写回、辅助码、固定位置、
  方案掩码),每条都确认回退修复后会失败。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-12 20:41:23 +08:00
Jia Suiandfanlusky fc90cb1f2c fix(engine): 纯简拼读法否决权,纠错不再劫持 nbn 等简拼候选 (#881)
* fix(engine): 纯简拼读法否决权,纠错不再劫持 nbn 等简拼候选

纯简拼形输入(切分全是单字母声母)若词库 jp 列有该输入读法,纠错不得接管:
nbn 是「能不能」、nqn 是「女青年」、bqng 是「并且能够」,纠错却把它们改写成
字母更近的错串候选(难/帮),顶掉真实命中的简拼词。

输入形状分不干净——sahng 也全是合法声母却必须保留乱序纠错;唯一分得开的是
词库有没有这个简拼读法,故判定落在同时持有 DB 与纠错掩码的查询层。

- 新增 quanpin::has_pure_jianpin_reading(jp 列 LIMIT 1 查询)
- QuanpinDictionary::effective_autocorrect_types 统一 query_exact 与
  insert_word_to_series_cache 的有效掩码,避免 series 缓存键分歧
- 非纯简拼(shng=[sh,n,g]、shbng、sahng/shangg/sjhang)纠错不变

* fix(engine): 纯简拼整词改为排在纠错前面,不再整个关掉纠错

原方案在词库有纯简拼读法时把纠错掩码置 0,漏了元音的真手误(bng 想打 bang)
也随之纠不了,而且只有词库层知道纠错被关,预编辑与选词消耗仍按原掩码判断。

改为不动掩码:纠错照常进行,纠错分支里字面结果中的纯简拼整词
(literal_jianpin_pinyin_match:两个及以上单字母声母盖住整串,逐个是正读首字母,
a/e/o 不算)和混合简拼一样放进领衔组。纠错读法排在后面,仍可选、仍带纠错标记。
判定直接看已查回的字面结果,不新增 SQL;掩码不变,缓存键也不变,
因此删掉 has_pure_jianpin_reading 与 effective_autocorrect_types。

测试补上预编辑(n'b'n)、选前缀单字只消耗自己的声母、bng 仍保留「帮」。

---------

Co-authored-by: fanlusky <1730976608@qq.com>
2026-10-12 17:23:30 +08:00
Jia Sui d495ea2ad0 fix(engine,server,installer): octagram 加成收敛为单一注入,校正量纲与参数,修复〔万象〕同音乱码 2026-10-12 13:12:21 +08:00
fanlusky b434240489 feat(engine): 模糊读音按词频与原读音混排,整句词格收模糊读音
开模糊音时模糊读音的候选不再整组垫在末尾:同组内按「权重 × 0.2」与敲出读音的词库行
归并,min 出「民 明 名 命 敏…」而不是先翻完 min 的生僻字。词格的跨度查询同时收模糊变体,
每个模糊音节扣 1.0(log10),lin'yi'bian 解出「另一边」;整句 canonical 记真实读音,
造词不写错音。切分与纠错的裁决打分不带模糊读音,避免字面读法借模糊分压过纠错。
双拼同步。eval_quanpin_sentence 新增 fuzzy=<规则位> 参数。
2026-10-12 03:44:25 +08:00
fanlusky cf07b77df6 feat(engine): 等音节数字面切分按整句打分裁决,预编辑跟随首选
最少音节切分平局时固定取较短首音节,切分又在查词之前定死,yibananzhao 只会切成
yi'ba'nan'zhao 出「一把难找」,「一般按照」「这个方案很好」这类 n/ng 边界歧义的整句没有机会。

- arbitrate_literal_segmentations:合法输入的等音节数字面切分各解一遍词格,路径分最高的领衔,
  同分仍取原切分;输方分差在 3.0 以内时它的整句占第 2 位,更远不出。任一切分在词库里有整词时
  不介入(单词级仍按词频),整句来源全关时与原来一致,用户调过频的读音不让出领衔
- 合法输入纠错的原读法改为领衔的字面切分:纠错胜出时第 2 位是得分最高的字面读法
- 首选是另一种等音节数字面切分时预编辑跟着它分(yi'ban'an'zhao、fang'an)
- 胜出切分的前缀词替换原切分前缀区间扫出的同名行,选「一般」按 yi'ban 消耗
- 词格跨度查询与最佳路径加缓存,随 reset_cache 清空;普通输入每键 p90 也随之下降
- 新增 eval_quanpin_sentence 与句子级评测集 tests/data/quanpin_sentence_cases.tsv
2026-10-12 03:05:44 +08:00
fanlusky 7ed4f2e0fd fix(engine): 回溯切分判定合法全拼,合法输入选词不再按纠错切分消耗
is_complete_pinyin_input 用贪心最长匹配判定合法性:zaijinuta 取了 jin 就剩下切不动的
uta,合法的 zai'ji'nu'ta 被当成手误。查询侧用回溯切分认它合法,预编辑和选词却去走纠错:
预编辑显示成 zai'ji'nut'a,选「再」按 zaij -> zai 的纠错切分吞掉 j,只剩 inuta。

- is_complete_pinyin_part 与 looks_like_jianpin_spelling 改用回溯切分,与查询侧同一个算法
- corrected_reading_raw_length:读音是原始字母前缀、整串合法(可带一个末尾声母)时按读音长度消耗
2026-10-12 03:01:57 +08:00
沐雪清泽andmushiyuki 93c7b8121d fix(engine): consume Japanese nn as a single nasal (#669)
Co-authored-by: mushiyuki <248113054+muxueqingze@users.noreply.github.com>
2026-10-11 20:39:55 +09:00
Lu Fan(SonnyCalcr) 649747f8cd feat(server): 神经网络整句效果优先模型改为按需下载 (#838)
效果优先模型(sentence-model-desktop.safetensors,约 25 MB)不再随安装包分发,
改为和八股文模型一样在设置页下载后才能使用。

- engine:SentenceAssociationOptions 新增 neural_desktop_model 路径,留空即模型缺席、
  静默不重排;词典不再从资源目录固定加载效果档。load_file 按 UTF-8 打开路径,
  数据目录在非 ASCII 用户目录下也能读到模型
- server:新增 settings/neural_model,下载到 <数据目录>\models\neural-desktop\,
  下载与导入都按 neural-model/lock.json 的字节数和 SHA256 校验后原子落位;
  会话层只在开关打开时解析模型路径
- ui-html:设置页增加下载 / 导入 / 删除 / 浏览器下载,模型未就绪时开关置灰
- installer:不再打包效果档模型;旧版装进数据目录根下的那份在覆盖安装与卸载时清掉

原有配置项 sentence_neural_desktop 保持不变,用户的开关状态升级后保留。
2026-10-11 18:08:33 +08:00
chr331 be66c8c128 test(engine): 补全混拼边界与双拼回归 2026-10-11 14:59:31 +08:00
chr331 36ab259c43 fix(engine): 保留原样混拼候选优先级 2026-10-11 13:56:14 +08:00
Ouchihao 777fb2aef4 fix(engine): protect repeated-initial jianpin 2026-10-10 17:05:09 +08:00
Ouchihao 29c8917e8c fix(engine): preserve leading-initial mixed jianpin 2026-10-10 14:46:13 +08:00
normaltank c2bd59d448 fix(server): 翻页扩展时保留混输候选并同步 Emoji 末尾排序 2026-10-08 22:10:13 +08:00
fanlusky 9a08042586 fix(engine): 日语预测紧跟整读音转换,不再被前缀片段压后
完整读音时的候选顺序改为:最佳整句路径与整读音精确词条在前,前缀预测随后,
其余整句结果(次优路径、假名兜底、只覆盖前缀的词条)殿后。预测只取读音严格
长于输入的词条,不再重复扫描精确词条;预测权重不高于其上方的转换,避免按权
重重排时把顺序翻回去。测试补齐头文件、清理目录不再抛异常,并新增前缀片段回归。
2026-10-08 16:48:39 +08:00
mushiyuki 4234f6deb2 fix(engine): prefer Japanese conversions over prefix predictions 2026-10-08 11:45:44 +08:00
Lu Fan(SonnyCalcr) 53ee180ec3 feat(engine): 直接辅助码句中四码可用第二位辅码大写结束 (#630)
直接辅助码的四码在句中原来只能补 / 结束(uiab/),现在也可以把第二位辅码敲成大写(uiaB)。
设置页「直接辅助码句中四码标记」两个勾选框可多选、至少留一个,默认只勾 /。

- 引擎:拼写图新增 Aux2Upper(非缩写)。开着大写标记时大写字母只能当第二位辅码,
  走不通再退回不分大小写的旧规则,第一位辅码敲大写(uiAuiQ)照常可用。/ 的收键受勾选控制。
- 协议:DirectHelpcodeChanged 载荷改为 "0"/"1"/"2"(2 = 开着但 / 不是编码键),
  TSF 据此决定吃不吃 /。
- 配置:新增 helpcode.shuangpin_direct_helpcode_slash / _uppercase,同步写入出厂模板、
  工作配置和两个设置宿主的读写映射。
2026-10-05 20:43:02 +08:00
Lu Fan(SonnyCalcr) 3c79876205 Merge pull request #629 from fanlusky/feat/v-mode
feat: 新增 V 模式,数字转中文与算式计算
2026-10-05 17:51:21 +08:00
Lu Fan(SonnyCalcr) 1da1c1bcd6 fix(engine): 辅助码串上的 Ctrl+方向与 Ctrl+Backspace 按单元编辑 (#627)
双拼串里带句中辅助码(反引号段 / 大写段)或开着直接辅助码时,segment_raw_boundaries
直接返回空,Server 只能退回逐字符移动和删除。

现在按请求带着的辅助码段布局切单元:每个音节和挂在它后面的辅码段各算一个单元,
Ctrl+Backspace 可以只删辅码,Ctrl+方向也能停在音节与辅码之间。布局对不上原串时仍
不给边界、退回逐字符。直接辅助码没解析出辅码时请求原样放行,沿用普通双拼切分。

光标前缀重算与按段编辑共用同一套边界,带辅助码的串也随之按光标前缀出候选。
2026-10-05 04:19:23 +08:00
Lu Fan(SonnyCalcr) b391fd616b feat: T 模式支持输入指定的日期和时间 (#626)
Shift+T 后面除了 rq / sj / xq 唤醒词,还可以直接写数字:

- YYYYMMDD、YYYY/M/D、M/D(年份取今年)出那一天的日期格式,星期按那一天算
- YYYY/M 出年月格式(新增 date:ym_* 五种)
- h:mm、h:mm:ss 出时间格式,写了秒才给带秒的格式
- YYYYMMDDhh[:mm[:ss]] 出日期加时间的格式

指定的日期时间沿用唤醒词的格式 ID,学到的顺序、置顶、固定位置跟着走。

输入形状放在 engine/contracts/date_time_input.h,TSF、Server、引擎共用:
数字、/ 和 : 只在还能接成某种形状时才进输入串,接不上的数字仍是选词键,
/ 和 : 仍是标点,Shift+数字始终选词。小键盘数字同样可以输入。

Refs #531
2026-10-05 03:42:12 +08:00
Lu Fan(SonnyCalcr) 8a524aa498 feat(engine): 全拼纠错扩展到多字/漏字,贵档读法按整句分领衔 (#623)
* feat(engine): 合法输入纠错扩展到多字、漏字,纠错读音按原始区间消耗字母

jiuzheeyang 切成 jiu'zhe'e'yang 全合法,多打的 e 原本纠不回「就这样」;多字纠错的
读音又与原始字母不等长,buuhui 选「不会」后会剩下一个 i。

- legal_input_correction_cuts(原 legal_input_transposition_cuts)认换位、多字、漏字
  三类静态表读法,不认邻键与生成式空间;末尾音节按漏字读出的(nia -> nian)视为
  还没打完,跳过;k-best 先取 9 条再过滤,长句里纠正不被别处的读法挤掉
- 改变字母数的纠正代价 3.0(换位 2.0);字面切分本身是真词时不认改变字母数的读法,
  少一个音节的句子在语言模型里天然分高(邪恶 -> 些、答案 -> 但)
- 新增 correction_cut_for_reading / corrected_reading_raw_length:选词按纠错切分
  记录的原始区间消耗字母,预编辑也按它分隔(jiu'zhee'yang)
- AutocorrectCut 恢复 has_generated,供合法输入路径排除生成式读法

* fix(engine): 被裁掉的合法输入纠错读法不再误标原读法的候选

合法输入上的纠错读法登记进了全局纠错标记表,即使裁决时被丢掉也照样参与按读音字母
的标记匹配:xiee 按多一个 e 读成 xie 被丢掉后,邪恶后面的前缀单字 写/些/血 读音
也是 xie,全被标成纠错。

改为不登记,只在 arbitrate_legal_corrections 里给真正用上的那条纠错读法的整读音
候选打标,标记随结果进缓存。

* feat(engine): 结构性贵档纠错读法可按整句分领衔

shiideya 的换位读法 shi + ide->die(权重 10,是爹呀)比多字读法 shii->shi(权重 12,
是的呀)便宜一档。#592 只在同档内做上下文消解,贵档读法一律排在最后,「是的呀」
连首页都进不了。

- 上下文消解把前 2 条贵档读法也解码,不要求词库有整词;总分 = 路径分 - 手误代价,
  代价按纠错表权重换算(权重 x 0.2:换位 2.0、漏字 2.2、多字 2.4)
- 只收由结构性手误(换位、漏字、多字)构成的贵档读法:邻键只比漏字贵 0.4 分,
  常用词的语言模型优势会把 zhowei 的「周围」挤成「作为」
- AutocorrectCutSegment 记录每段的纠正权重,用来区分纠正类型
- 预编辑跟随领衔读法分隔也覆盖切不成合法音节的输入(shii'de'ya)
- eval_quanpin_autocorrect 新增 --word-lattice,量产品默认开词格时的排序

评测(--word-lattice,300 样本,seed 42)各档 R@1/R@3 不低于改动前:mixed R@1
79.7/76.7/78.3/70.3 -> 82.3/81.7/81.3/78.0,insertion 83.3/74.7/72.7/52.0 ->
91.3/89.3/90.0/83.7,deletion 持平或上升,ambiguous 持平。

* fix(engine): 纠错上下文消解在任一整句来源开启时生效

上下文消解只认 word_lattice 开关。只开万象重排、不显示 Trigram 整句时(词格在内部
照样解码),整段被跳过,shiideya 退回静态排序,「是爹呀」又领衔。

- 新增 SentenceAssociationOptions::any_sentence_source,门控改看它;全关时仍是纯
  静态排序,#592 的「关联关闭 = 静态路径」不变
- 贵档胜者没有整词也没有整句行时(重排模型未载入),由它的最长前缀词领衔,不让
  主切的行顶回首位
2026-10-05 01:41:37 +08:00
Lu Fan(SonnyCalcr) adde5c188c feat(engine): 合法输入的换位手误按整句打分纠错 (#622)
ziazheliya、jioa、liazheli、nia 能整串切成合法音节(zi'a'zhe'li'ya、ji'o'a),
纠错入口按「切不成合法音节」设闸,原本完全不进纠错。

- legal_input_transposition_cuts 列出合法输入上的换位读法:纠正段须盖住字面
  切分里被挤出的非首位零声母音节(排除 dao'lu 读成「大楼」这类跨边界重切),
  另有罕见音节小表(lia->lai、dia->dai),只用于多音节输入
- arbitrate_legal_corrections 按噪声信道整句打分:词格最佳路径分 + 每处换位
  -2.0,不看整句候选显示开关;纠错领衔时原读法固定第 2 位,原读法领衔时纠错
  在 3.0 分差内占第 2 位,否则不出
- 字面整词保住首位:候选里有读音字母与输入相同的词库词时,改写字母的读法
  (换位纠错,以及已有的辅音复制别名 yongan -> 勇敢)最多排第 2
- 纠错领衔时预编辑按领衔读法分隔(zia'zhe'li'ya)
2026-10-04 23:54:18 +08:00
Lu Fan(SonnyCalcr) 5208753ce8 feat: 句中辅助码新增大写字母触发方式 (#620)
* feat(engine): add uppercase trigger for shuangpin mid-sentence helpcode

With the uppercase trigger on, an uppercase letter right after a complete
two-key syllable opens a mid-sentence helpcode block by itself, as if the
backtick had been typed before it: ulpbXihfa is ulpb`xihfa, and a following
uppercase letter is still the second code (ulpbXYih is ulpb`xYih). The raw
input keeps the typed letters; the block rules live in
contracts/mid_sentence_helpcode.h so TSF, Server and engine parse alike,
including the semicolon final, which no longer counts uppercase blocks.

The scheme now hands the parsed layout (source index and decorations) to the
request, so selection advance and preedit no longer re-parse the raw input.
Adds the MidSentenceHelpcodeUppercaseChanged worker opcode (31).

* feat(windows): count uppercase helpcode blocks before backtick and semicolon

With MidSentenceHelpcodeUppercaseChanged on, TSF uses the shared block rules
when deciding whether '`' opens a block and whether ';' is the ing final, in
both the synchronous and the deferred key classification.

* feat(server): wire the mid-sentence helpcode uppercase trigger

New helpcode.shuangpin_mid_sentence_helpcode_uppercase (default off) in both
config templates, both settings hosts and the settings page as a third
trigger checkbox. It takes effect only with mid-sentence helpcode on and
direct helpcode off; the Server applies it to the semicolon final rule and
broadcasts MidSentenceHelpcodeUppercaseChanged to TSF.
2026-10-04 21:00:41 +08:00
Lu Fan(SonnyCalcr) 22fb1e2569 Merge pull request #619 from fanlusky/feat/shuangpin-direct-helpcode
feat: 双拼直接辅助码(万象式,无需引导键)
2026-10-04 19:32:10 +08:00
fanlusky a219e499f6 fix(engine): 全拼纠错上下文接管让位于用户在主切读音上的选择
加载 sc.lm 时词格路径分里的词库权重只剩 dictionary_tiebreak(≤0.07)和
reading_prior,调频改的权重翻不过 1.0 的接管边际:banzhng 的用户每次都选
班长,办证系照样每次领衔,调频在这组词上被架空。

接管前加一道判据:主切键在用户日志里有 upsert,且主切整键首位权重不低于
胜出切分首位(即用户已把主切读音选到前面),就不接管、走按权重排序的静态
合并。出货词频本身仍交给上下文裁决;日志只在边际达标后查一次。

测试用手写 ARPA 作 sc.lm,让 LM 稳定偏向办证,覆盖无用户记录照常接管、
用户选过班长不再接管、用户记录未越过胜者照常接管三种情形。
2026-10-04 14:35:50 +08:00
Jia Sui 7e1ae10da2 docs(engine): 更正生成式空间可达性论断,删除对用户不可见的错误结论 2026-10-04 05:21:45 +08:00
Jia Sui 3a0d95e143 test(engine,server): 对齐生成式纠错空间的类型位可达性断言 2026-10-04 04:25:25 +08:00
Jia Sui bbebd34d22 docs(engine): 补上下文重排切分与用例打分的前提说明
R2 的分层判据是 canonical_pinyin == winner_key。原注释只说明了「整句与词格行
同键」,没解释为什么整键档**必然**是 winner_key。而 query_single_cut_keyed 在精确
键查空时会退到前缀区间扫描,那类行的 canonical 是别的读音(gun'qi 捞出 gun'qiu),
放宽判据就会静默把同档整词沉到末尾——正是本任务在修的那类回归。补上这条不变量:
decode_pool 由 query_exact_segmentations_keyed_flat 只收精确键构造,词库里没有整词的
切分进不了池,这条路在胜出切分上不可达。

测试侧补上「fixture 无 sc.lm ⇒ 启发式打分 ⇒ 用例确定」这个前提(同组 ranking fixture
已有,新用例依赖同一前提却没写)。
2026-10-04 03:45:53 +08:00
Jia Sui e1331ff1dc fix(engine): 恢复上下文重排的「整键在前、前缀在后」分层
胜出切分接管后用 query_series(raw_input, winner_key, winner_segments) 取它的结果,
但该函数的 count 从整键递减到 1,返回的不只是整键行,还有首音节的全部单字;而
rest(班长、搬账这些同键位整词)在这之后才append。

结果是办证/辩证/整句/班/办/半/般…/班长——胜出切分的单字插到同键位整词之前,把它们
整组挤出首页,PR 描述里「同键位纠错读法整组下移」并不成立。

按 canonical_pinyin == winner_key 把前缀行摘出来,恢复 merge_alternative_segmentations
的既有分层(merged_full 在前、前缀作为 remaining 追加):整键块、rest、前缀块。分类
键选 canonical_pinyin 而非 pinyin——后者承载用户键入码(可能是简拼);整句与词格行
同样落在整键块内,因为 append_ime_fallback 用完整 segmentation、词格 select_distinct
用 path->key 填 canonical_pinyin。

补判别性用例:原 fixture 缺 tbl_1_b,前缀这条路根本没被走到。已实测——撤掉本修复
时该用例失败(Same-tier whole words must not be pushed behind the winner cut's
single-character prefixes.),装回后通过。
2026-10-04 03:45:53 +08:00
Jia Sui fc3564e4d9 feat(engine): 生成式纠错空间兜静态表长尾
静态纠错表四类形状(相邻换位/漏字/QWERTY 邻键替换/限重复邻键插入)均为
穷举式生成,表外单编辑手误(非相邻键替换、任意字母插入)结构性无人管——
这是覆盖反馈的机制根源。新增生成式索引:对全部合法音节枚举表外形状
(48,216 对,首次纠错查询时一次性构建),并入纠错索引,k-best/贵档垫底/
上下文消解全链路复用;换位/漏字静态已穷尽,不枚举。

表内零回归为结构性保证:含生成边的切分在 k-best 排序中整体垫底
(has_generated 先序键),最优切分为纯静态时全部生成切分被丢弃——丢弃
规则在 autocorrect_cut_kbest 单点实现,主解析与 head+简拼尾组合路径同享;
生成读法只在静态空间完全无法解释输入时出场。混表加权仲裁依赖训练权重,
留给方向阶段 3。

评测:eval 新增 outside 注错档(表外形状,与静态表构造性不相交),覆盖
增益量化 R@1 47.7/44.3/36.3/22.7(四率;静态-only 恒为 0);表内四档
R@1/R@3 与基线逐位一致;种子聚合不回归。fixture 四用例含 head 组合路径
判别(shatngzh)。README 补 outside 档与资源目录说明。
2026-10-04 01:27:15 +08:00
Jia Sui 49be145bdf feat(engine): 全拼纠错同档歧义按词格上下文消解
同档纠错读法(zhng→{zhang,zheng} 这类 k-best 等权目标)此前只按静态词频
消解、不读上下文,是纠错误报的主要来源。现在整句词格开启时直接解出主切与
同档备选的最佳路径分,边际达标(打分器自身对数单位 1.0)时胜出切分接管
领衔候选,静态词频降级为解码前置过滤;词格不可用或边际不足时与现状逐位
一致(关联关闭、单音节、纠错开关关三条降级路径)。

七项护栏全部保留:贵档绝对垫底、精确键领先位、每来源至多一行、合并池去重、
纠错标记边界、输入门未动,1/100 门槛升格为解码前置过滤。单音节纠错无词格
可搭,维持静态路径(已知限制,fixture 测试钉住)。

评测:eval 新增 --seeds-file 固定精度套件(15 条,豁免逐键一致契约),
四档注错模型 R@1/R@3 与重采基线逐位一致,种子聚合 R@1 73.3%、R@3 80.0%;
机制生效由 test_input_session 隔离 fixture 端到端断言(lattice-on 序列
[办证,辩证,班长,搬账])。README 补资源目录要求与种子表维护纪律。
2026-10-04 01:27:15 +08:00
luo jiyin 9a22905fb7 perf(engine): add blocked AVX2 int8 linear kernel (#608)
Reuse each widened weight chunk across up to four activation rows.

Use a scalar path when the CPU lacks AVX2 or FMA.
The blocked kernel reduces scoring time for both locked models.
Keep a focused test for row blocks, input tails, and optional bias.
2026-10-04 00:06:38 +08:00
luo jiyin 136d440517 Merge branch 'develop' into perf/neural-skip-padding 2026-10-03 17:05:48 +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