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)
c0a9d371f0
feat(server,windows,engine): 横排候选时左右方向键移动高亮 ( #1080 )
...
- 快捷键页「翻页方式」新增「左 / 右(横排时移动候选项)」,与「上 / 下」各自独立,默认关闭,
只在候选窗为横排时生效。配置项 general.candidate_horizontal_arrow_navigation 已写入出厂模板。
- 光标在拼音串尾时右键移动高亮(到页末翻页),左键往回移高亮,高亮回到第一个候选后再按才移动光标;
光标在串中间时右键先把光标移回串尾,再按才移动高亮。Ctrl+左/右与 UILess 宿主不变。
- 新增 worker 消息 HorizontalArrowSelectionChanged(39)和按键标记 FanyImePipeFlags::HorizontalArrowSelection:
开关生效时 TSF 把候选态下的左右键交给 Server 决定,移光标时 Server 用 CompositionRestored 回光标,
移高亮时回 MoveSelection*,TSF 不再自己预测光标。旧 DLL 忽略新消息,保持原行为。
Closes #779
Closes #895
2026-10-19 02:11:25 +08:00
Lu Fan(SonnyCalcr)
6e15526e75
perf(server,ui,engine): 降低 Server 常驻内存并加快候选去重 ( #1078 )
...
- ui: 同一线程上的窗口共用一个 D3D11 设备。候选窗、悬浮工具栏、托盘菜单原先各建一个,
每多一个硬件设备约多占 10 MB 私有内存;设备被移除时下一次取用会换新的。
- engine: U 模式拆字表改为单块文本池加 16 字节定长条目,常驻内存从约 12.6 MB 降到约 3.9 MB,
查询结果不变。
- server: 未开启语音输入时,提示音播放器推迟到第一次播放才打开 miniaudio 引擎,
不再常驻 WASAPI 播放设备和音频线程;开启时行为不变。
- engine: append_unique_words 由逐条线性比对改为哈希集合去重,顺序与结果不变。
2026-10-19 00:55:46 +08:00
Lu Fan(SonnyCalcr)
75d8c710a9
feat(server,windows,engine): 新增顿号自定义,翻页方式移到快捷键页 ( #1071 )
...
- 设置「输入」页在智能标点上方新增「顿号自定义」:\ 和 / 各一个勾,至少保留一个,
未勾选的键按原样输出。新装默认两个都开;升级用户的配置里没有 / 这一项,
模板合并时补成关,保持原来只有 \ 出顿号。
- 新增 worker 消息 EnumerationCommaKeysChanged(38),载荷见
engine/contracts/enumeration_comma.h;旧 DLL 忽略它,保持只用 \。
- 选候选时按 / 改为按配置上屏「候选 + 、」;未作顿号的 \ 或 / 跟在候选后原样上屏。
小键盘 / 与小键盘 . 一样始终输出原字符。
- 「翻页方式」从「输入」页移到「快捷键」页。
- AtLeastOneChecks 从辅助码页移到公共绑定,两页共用。
2026-10-18 23:49:41 +08:00
Lu Fan(SonnyCalcr)
58a27f3edb
fix(engine,server): 候选末页满页且无法再展开时置灰下一页箭头 ( #1070 )
...
下一页箭头原先在当前页满时一律可点,为首字母候选分批展开留口子;
但只有单个首字母且首字母候选恰好截在 24 条时才能展开,其余情况
末页满页的右箭头点了没反应也不会变灰。
引擎新增只判断不查库的 can_expand_initial_candidates,与实际展开
共用前置条件;Server 发布候选页快照时,满页只有在还能展开时才算
有下一页。
Refs #1069
2026-10-18 23:11:22 +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)
692bed7d7c
fix(engine): 出厂词库换过时,回放不再用旧量级的调频权重压住新词频 ( #1049 )
...
用户词库日志存的是调频写下的绝对权重。词库升级换了权重量级后(msime-dictionary
把拼音词频对齐万象,「了 le」从 348 万变成 5200 万),安装时的回放仍把旧词库上
调出来的 650 万写回去,打 l 时「了」排到「来」「里」后面。
回放现在用数据目录里 dictionary-manifest.json 记的 msime.db SHA-256 认出厂词库,
并在日志新增的 dictionary_state 表记下回放到哪份。同一份词库照旧原样写回;换了
词库(或日志还没有记录)时,自动调频的行只在高过新出厂权重时写回,否则保留新
权重并把日志改记成新权重。用户手动加的词和删除不变。
设置页改权重改走新的 record_weight_edit,记在新增的 weight_edited 列里,换词库时
照写不让位;之后的自动调频覆盖同一行时清掉这个标记。
2026-10-18 10:40:59 +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
古明四季 and fanlusky
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 Sui and fanlusky
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
Lu Fan(SonnyCalcr)
1b875267db
refactor: 移除 WebView2,界面只保留 Direct2D ( #1013 )
...
* refactor(engine): 语音独立工具改用原生托盘菜单,移除 WebView2
托盘菜单改用 Win32 弹出菜单,设置项改为用关联编辑器打开 config.toml,关于页改为消息框。删除 window_webview2 与两份 HTML 资源,windows-app 特性不再依赖 webview2 端口。
* refactor(server): 移除 WebView2,候选窗、工具栏、托盘菜单与设置窗口只保留 Direct2D
删除 src/webview2 与 webview_utils,小窗口的置顶、皮肤重载和工具栏状态缓存移到 window/small_windows,presenter 成为唯一路径,D2D 下的置顶时序与 cloak 行为保持不变。设置进程去掉 WebView2 宿主、鼠标转发与启动图,只构建原生窗口;旧快捷方式传入的 --d2d / --webview2 被忽略。删除 appearance.ui_backend 与 appearance.settings_ui_backend(读取、写入、设置页下拉框与两份配置模板),升级时由模板合并丢弃旧值。设置窗口的图片资源移到 server/assets/settings,安装到数据目录的 assets\settings。不再链接 WebView2Loader,vcpkg 去掉 webview2 端口。
* build(installer): 打包与 CI 不再处理 WebView2 页面和运行时
Prepare-PackageFiles 去掉 -UiHtmlDirectory 与 html 暂存,改为暂存 server/assets/settings;安装器不再检查 WebView2 Runtime、不再创建 ProgramData 下的 WebView2 用户数据目录,升级和卸载时清理旧版留下的 webview2 / webview2-settings 与数据目录里的 html。CI 删除设置页构建、契约同步检查和候选窗 DOM 测试,release 的打包任务不再依赖网页产物;dependabot 去掉 npm。第三方声明去掉 WebView2Loader。
* refactor(ui-html): 删除 WebView2 页面与设置页前端工程
候选窗、工具栏、托盘菜单、设置页、主题和契约副本都已没有使用者;设置窗口用到的图片资源已移到 server/assets/settings。sync-contracts.py 与 pnpm/Vite/TypeScript 工程一并删除,契约仍以 engine/contracts/webview 为唯一来源。
* docs(server): 文档改为只描述 Direct2D 界面
仓库地图去掉 ui-html,组件边界、uiAccess 与置顶时序、设置窗口和配置读写的说明改写为 Direct2D 唯一界面;安装说明去掉 WebView2 Runtime 检查,打包命令去掉 -UiHtmlDirectory;engine/contracts/webview 的说明改为设置窗口是唯一使用者,名字是历史遗留。
* docs(skins): 皮肤说明不再区分 WebView2 与 D2D 渲染器
v2 字段去掉「仅 WebView2」,改为说明由 Direct2D 原生渲染、部分字段仍在补全;颜色必须带 # 改为清单格式约定。随包的 skins/niya-demo/skin.toml 不改,免得用户机器上的同名皮肤在升级时被当成已修改而改名备份。
* docs(ui): demo 说明文字不再提 WebView2
2026-10-17 02:48:02 +08:00
Jia Sui and fanlusky
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) and li 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
6072ae7784
fix(windows): 修复临时日语 R 模式无法输入长音符 ( #1000 )
...
* fix(windows): 修复临时日语 R 模式无法输入长音符
* fix(server,windows): 临时日语策略每键只算一次,并去掉多余的帧
- Server 在 HandleImeKey 开头按本次按键所属客户端算一次策略,不再每个谓词都查活动客户端、加锁、构造 payload 再解析回来。
- 普通激活只补发 TemporaryJapanesePolicyChanged;整套输入模式状态(含语言栏刷新)仍只在 FocusRestored 时发送。
- 配置重载时输入方案变了由 ApplyConfiguredInputScheme 统一广播,不再重复广播策略。
- TSF 的 WaitForProtocolReady 不再清零策略:worker 管道先于 Main 注册,可能已收到本次连接的策略;断开时已有清零路径。
---------
Co-authored-by: ranly <ran618ly210805@qq.com >
Co-authored-by: fanlusky <1730976608@qq.com >
2026-10-16 22:30:28 +08:00
26e6896c5f
fix(voice): dismissible overlay, silent no-speech handling, reasoning strip + provider registry with mainstream presets ( #996 )
...
* fix(server): keep vendor chat fields off foreign endpoints and strip reasoning from responses
* fix(engine): strip inline reasoning from polished text and assistant responses
* fix(server): never block the voice control loop with modal dialogs
* feat(server): provider registry for AI assistant with mainstream provider presets
* feat(ui-html): settings pages for the provider registry, model fetch everywhere and new ASR providers
* test(server): vendor detection, reasoning strip, provider store and expanded provider defaults
* fix(server): keep the voice overlay dismissible at all times
* fix(server,ui-html,installer): 服务商注册表与语音收尾的评审修正
- 加载配置时先读 ai_providers.json 再校验当前服务商,用户添加的服务商不再被重置为 deepseek
- Token 不再明文写进 ai_providers.json,统一存为 config.toml 的 token_<id>(DPAPI 加密、升级时按凭证保留);旧文件里的明文 token 读取时清掉
- 配置重载同时检查 ai_providers.json 的修改时间,只改注册表也能同步到 Server
- 删除当前服务商时按切换服务商的流程更新 token、地址和模型
- 内置服务商列表收敛到 ProviderStore::BuiltinProviderIds 一处,新增的六个预置服务商同样以 config.toml 为准;去掉未使用的 MakeProviderId,前端生成 id 时避开内置 id
- 出厂模板和开发配置补上六个新预置服务商的 token_/endpoint_/model_ 键
- 录音回调失败时走完整的取消收尾,恢复系统静音并关闭豆包连接;删除不可达的第二段 Esc 处理
- 语音转写地址查询模型时正确推出 /models
- 设置页补上语音识别和润色的 Custom 选项、新预置服务商的显示名,修正添加服务商的地址提示
---------
Co-authored-by: alayahbridge319-boop <246594988+alayahbridge319-boop@users.noreply.github.com >
Co-authored-by: fanlusky <1730976608@qq.com >
2026-10-16 21:46:41 +08:00
HowGeGe and fanlusky
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 Sui and fanlusky
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
chr331 and fanlusky
1c3bd7cb83
feat(server,ui-html,windows): 支持自定义“输入状态切换”中的快捷键 ( #985 )
...
* fix(windows): 支持标点切换快捷键改绑与取消绑定
* fix(shortcut): 对齐虚拟键并处理语音与窗口快捷键冲突
* fix(ui-html): 绑定标点快捷键前提示应用快捷键占用
* fix(ui-html): 仅对已知快捷键冲突提示确认
* feat(shortcuts): 支持自定义输入状态切换快捷键
* fix: keep shortcut editor buttons on one row
* fix(shortcuts): 限定输入状态快捷键为 Ctrl 组合
* fix: clarify shortcut override and punctuation lock behavior
* perf(server,windows): 提前筛选输入状态快捷键
* fix(windows,server,ui-html): 修正输入状态快捷键的兼容与保存问题
- windows: 未协商 InputStateShortcuts 时回退到旧的 Ctrl+Shift+E KeyEvent,
新 DLL 配旧 Server 时英文候选快捷键不再失效
- windows: 全角快捷键与标点快捷键一样可在待处理按键后排队,不再漏给应用
- windows: Server 不可用时排队的英文候选切换按 FUNCTION_CANCEL 离线回放,
不再丢弃其后的按键
- server: 非字符串配置值不再以 "!invalid" 作为 binding 发给设置页
- server: 仅三个输入状态快捷键路径强制回传配置快照;去掉 worker 中与
reader 重复的协商检查;抽出 InputStateShortcutViews 去除重复转换
- ui-html: 保存后 5 秒未收到快照则恢复编辑器并提示重试
---------
Co-authored-by: fanlusky <1730976608@qq.com >
2026-10-16 03:31:19 +08:00
Jia Sui and fanlusky
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 Sui and fanlusky
2f7335be3e
统计增加首词命中率 ( #963 )
...
* feat(engine): webview 契约给统计概览增加首词命中率字段并支持 null 分支
* feat(server,ui-html): 统计新增首词命中率(决策点记录、stats v2 迁移与设置页展示)
* fix(server): 首词命中计数补日语标点排除与并发迁移复查
* fix(ui-html): 统计卡片改用自适应列宽,避免长数字被省略号截断
* fix(server,installer): 修复首词命中率随附测试在 CI 的失败
三条 server 用例是首词命中率改动新加、但从未跑绿:RawDb 在迁移用例里对尚不存在的库开只读写连接,补上 SQLITE_OPEN_CREATE;09-19 写了一次次选,按契约它是一次真实测量(0%),断言却要求 nullopt,改为断言 0.0,并把 nullopt 覆盖移到迁移用例(total==0 的那天)。安装器 preserve-user-data 从 stats_pipe.cpp 取库名,而 EnsureStatsStoreOpen 连同 stats.db 字面量已挪到 stats_candidate_capture.cpp,改到新位置。
* fix(server,ui-html): 首词命中率写库移出按键路径,修正迁移与统计口径
- 选词计数改由后台 SerialTaskRunner 写库,标点收尾与选词路径不再同步等 SQLite 锁
- 迁移以表结构为准,不再被版本号挡住;缺列时在 IMMEDIATE 事务里逐列补齐
- 标点在日期入口上收尾时按实际上屏的首条候选计数
- 五笔四码唯一自动上屏不计入;多段造词任一段非首位即不算命中
- 只有选词计数的日线不算打字日,不影响天数、日均与连续天数
- 卡片复用 formatFirstWordRatio 并展示累计命中率,概览复用 DailyRow::FirstWordRatio
---------
Co-authored-by: fanlusky <1730976608@qq.com >
2026-10-15 22:09:50 +08:00
Jia Sui and fanlusky
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 Sui and fanlusky
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)
e46294308d
fix: CS2 / Dota 2 / 三角洲行动等游戏里的输入法兼容(加载、候选、翻页、独占全屏、启动崩溃) ( #925 )
...
* fix(installer): TSF DLL 改装到系统目录,CS2 等 Trusted Mode 游戏里可以切出输入法
CS2 的 Trusted Mode 只放行位于系统目录且有代码签名的第三方 in-proc DLL,
装在 Program Files 下的 DLL 会被拒绝加载,游戏里切不出输入法。
x64 DLL 改装到 System32\IME\MetasequoiaIME\msime_v*,x86 装到 SysWOW64 下同名目录,
语言配置图标随之放到两处根目录;升级时清掉旧版留在 Program Files 的版本目录。
* fix(windows): CS2、Dota 2 不理会 UI-less 声明,照常显示候选窗
起源 2 引擎的 Valve 游戏以 UI-less 激活 TSF,但只替白名单里的输入法绘制候选。
我们据声明收起了自己的候选窗,游戏又不画,结果只剩左上角的系统默认 IME 小框,只能盲打。
对 cs2.exe、dota2.exe 忽略 UI-less,照常由 Server 绘制候选窗。
* fix(server): 前台为 D3D 独占全屏时不弹候选窗与光标状态提示
独占全屏下别的进程的窗口画不上去,弹出去反而可能把游戏踢出独占模式(闪黑、切分辨率、卡死)。
在 UI 线程真正显示前用 SHQueryUserNotificationState 判一次(300ms 缓存),独占全屏就收起候选窗,
并清掉已渲染可见标记,数字键与空格选词不再等待不会到来的绘制。
* fix(engine,server,windows): 游戏自绘候选时后台改动的候选列表实时同步给宿主
英雄联盟等 UI-less 宿主自己画候选。云候选、AI 候选、模型重排、英文混排在按键回复之后才改
候选列表,却从不通知 DLL,游戏还画着上一键读到的旧列表,数字键和空格却按新列表上屏,
于是「选的和上屏的不一样」。
- 契约新增 Worker opcode 35 UiLessCandidatesChanged,载荷与 UiLessComposition 同形,
由 uiless_page.h 统一格式化与解析,并附候选页代号;旧 DLL 读选中位时在第三个制表符处停下,兼容。
- Server 在上述后台改动之后把新页推给候选归属的客户端。
- DLL 收到后回到 TSF 线程核对焦点与组合纪元,更新候选 UI 元素并通知宿主重读。推送与按键回复
走不同管道,按代号只接受不旧于当前的页,避免旧页盖掉新页。
- 从共享内存重读到不同的页时高亮回到第一项,与 Server 每次重建都选中首项一致,
不再保留旧高亮造成「高亮这个、空格上屏那个」。
* feat(windows,server,ui-html,installer): 游戏兼容开关,CS2 / Dota 2 独占全屏打字不再黑屏
CS2、Dota 2 只替内置白名单(按输入法登记名称全等比对)里的输入法处理输入法消息。不在名单里时
组合落到 Windows 默认组合窗 CiceroUIWndFrame,左上角弹出编码小框;独占全屏下这个窗口一出现
游戏就被踢出全屏,表现为一打字就黑屏。清风输入法未开兼容时同样如此。
- 设置页帮助页新增「游戏兼容(CS2 / Dota 2)」:开启后把水杉在系统里登记的名称换成白名单里的
名字(默认「拼音输入法」),游戏会自己画候选。需要管理员权限:设置进程以
--apply-game-compat-name 提权重启自身,写 HKLM 记录值并改语言配置的 Description。
- TSF DLL 注册时以记录值为准,安装/升级重新注册不再把用户选的名称冲掉;卸载时删除记录值。
- 开启时不再对 cs2.exe / dota2.exe 忽略「宿主自己画候选」的声明,避免两个候选框。
- Server 的独占全屏判断覆盖进出独占模式时的 QUNS_BUSY 间隙,不在切换途中弹候选窗。
- TSF 诊断日志在组合开始/结束与 BeginUIElement 时记录宿主窗口状态(只有窗口与标志,没有文本)。
* fix(windows): 后台刷新回调持有加载器引用,宿主卸载 TSF DLL 后不再崩溃
当前输入法是水杉时,CS2 启动途中会加载再卸载 TSF DLL。诊断日志的线程池回调
FlushTsfDiagnosticLogs 正在 Sleep(250),只靠 DllAddRef 撑着:那只回答 DllCanUnloadNow,
挡不住宿主直接卸载。DLL 卸载后 SDL3 映射进同一段地址,回调醒来跑进 SDL3 的代码,
游戏崩溃(0xc0000005,崩溃转储里卸载模块的地址范围与崩溃地址吻合)。
- 诊断日志与统计上报的线程池回调改为用 GetModuleHandleEx 取加载器引用,
回调里 FreeLibraryWhenCallbackReturns,函数完全返回后才放手。
- 析构函数把 DllRelease 挪到最后,不在等待 IPC 线程退出之前就让 DLL 可卸载。
* fix(windows): 游戏自绘候选时不再把 Server 的 HTML 候选页当成候选交给游戏
CS2 开了游戏兼容后打一个码,游戏里的候选只有一项且是乱码。宿主要等 BeginUIElement 才说
自己画候选,而那时组合首键已经不带 UI-less 标记发给了 Server;Server 往共享内存写的是给
自己候选窗用的 HTML 页(辅助码、译文 span),DLL 的候选元素从共享内存回读后整串交给了游戏。
- 开了游戏兼容名称的 cs2.exe / dota2.exe 在 ActivateEx 就认定由游戏画候选,每个按键都带标记。
- 候选会话里收到过 Server 的 UI-less 页之后才从共享内存回读,之前一律不读。
* fix(windows): 游戏自绘候选时翻页能刷新,部分上屏后不再出现乱码候选
三角洲行动(虚幻引擎,以 TF_TMF_UIELEMENTENABLEDONLY 激活)里按 = / - / PageUp / PageDown
翻页,Server 已翻到第 N 页,游戏却还画着第一页;接着按空格上屏的是第 N 页的首项(多为单字),
剩下的拼音继续组合时候选框里出现乱码。
- 翻页、移高亮等键走异步的 WM_AsyncServerCandidateKey,以前把回复当作「只是确认」丢掉;
UI-less 下这份回复就是新的候选页,现在应用并通知宿主重读。
- UI-less 的 _SetText 拿不到 Server 的候选页时不再退回本地引擎的占位列表——那不是候选,
宿主会画成一条乱码。部分上屏后从共享内存回读 Server 写好的新页;_ClearList 同时清掉上次
的页记录,页文本相同也会重新载入。
2026-10-13 21:58:15 +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 Sui and fanlusky
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 Sui and fanlusky
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
時崎 ギャラクシー and fanlusky
add122fcc6
feat: 候选词翻译新增 AI 辅助提供方,收敛为单一 translation.provider ( #876 )
...
* feat(engine): 翻译凭据测试新增 translation.ai 服务类型
* feat(server): 候选词翻译新增 AI 辅助提供方,收敛为单一 translation.provider
* feat(ui-html): 候选词翻译新增 AI 辅助提供方并跟随单一 provider
* fix(server): 将 ai_translation 加入编译目标与测试套件
* fix(server): 在 AiTranslation 命名空间导出 ParseTranslations 供测试调用
* fix(server): 解析模型返回时剥除 Markdown 代码块标记
* fix(server): AI 候选词翻译校验占位 Token、收紧解析,翻译配置改读快照
- AI 翻译的 Token 改用 IsUsableSecret 校验,出厂模板的占位符不再被当成可用凭据
- 解析模型回复时,合法 JSON 但键不对、数组长度不符或残缺 JSON 一律作废,不再把原文当译文显示和写进释义库
- 从旧布尔推导出腾讯云时保留 tencent_tmt.enabled 门禁;在设置页明确选择时才打开,升级不会替用户向腾讯云发送候选词
- 候选词翻译读取的 provider 与各服务配置合成一份加锁快照,配置重载时整份替换,候选线程和翻译 worker 不再直接读会被改写的全局字符串;每个任务只解析当前服务的配置
- provider 与三个旧布尔一次原子写入;旧的 niutrans/custom enabled 开关改为切换 provider
- AI 联想与 AI 翻译共用 ChatCompletions 传输层,翻译超时与 AI 联想一致改为 8 秒
- 设置页凭据测试与运行时共用 AiTranslation::FromConfiguredTranslation,provider 白名单只保留 IsValidTranslationProvider 一处
* fix(ui-html): 候选词翻译的 AI 配置提示随 AI 辅助页实时更新
AI 辅助页改服务商、地址、Token 或模型后,翻译区的提示和摘要立刻刷新,不用重开设置窗口;可用性判断与服务端一致,占位 Token 不算已配置。
---------
Co-authored-by: fanlusky <1730976608@qq.com >
2026-10-12 16:47:04 +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
Lu Fan(SonnyCalcr)
035b2ad779
chore(engine): 辅助码表补充「瑠」「弔」 ( #856 )
2026-10-12 01:07:15 +08:00
Lu Fan(SonnyCalcr)
715028e1b9
feat(server): AI 联想上下文跳过密码框、换应用清空、过滤类凭证串 ( #845 )
...
AI 联想会把最近的上屏文本作为上下文发到云端,以前不区分输入框,也跨应用累积。
- 密码 / PIN 输入框:TSF 在一段输入的首键上读 InputScope(IS_PASSWORD、IS_NUMERIC_PIN 等),
按键包带上 FanyImePipeFlags::SensitiveField;Server 收到后不发 AI 请求,上屏也不进上下文
- 只在 AI 联想开启时才检测:Server 通过新的 worker opcode AiContextUploadChanged(34)
告诉 TSF 开关状态,关着时按键路径只多一次 atomic load
- 上下文按焦点会话归属:client_id 或 activation_epoch 变了就清空,不再把 A 应用里打的字带进
B 应用的请求
- 发送前去掉像凭证的 ASCII 串:不含空白、长度 >= 8 且混了字母 / 数字 / 符号中两类以上
2026-10-11 21:58:34 +08:00
沐雪清泽 and mushiyuki
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
Lu Fan(SonnyCalcr)
85edddc988
feat(server): 设置页支持把水杉设为默认输入法 ( #802 )
...
帮助页新增「默认输入法」卡片:显示当前是否为默认,提供「设为默认」和
「系统设置」两个按钮。设置走 input.dll 的 InstallLayoutOrTip /
SetDefaultLayoutOrTip,完成后按 HKCU International\User Profile 复核;
EnumEnabledLayoutOrTip 在 Windows 10/11 上对 TSF 输入法返回空列表,
因此状态直接读注册表。只在用户点击时执行,不在启动或升级时改写。
新增 defaultImeRequest / defaultImeResponse WebView 契约并同步 ui-html。
同时在帮助页加入 Wiki 与 FAQ 链接,在关于页加入官网 msime.app。
2026-10-11 02:22:01 +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
AkaneIwasa and fanlusky
568d07f513
feat(windows): 添加中日英三语轮换 ( #717 )
...
* feat(windows): 添加中日英三语轮换
* fix(windows): 三语轮换改为快捷键开关并修复两端状态不同步
- 开关移到「快捷键 → 中英文切换」下的「允许中日英循环切换」,配置键改为
[keybindings] trilingual_cycle;输入模式恢复为中文/日文,二者互不影响
- 循环请求带显式标记位和请求方自身的中英/日文状态,Server 据此计算目标语言;
普通 VK_SHIFT 仍是中英切换,不再被误当成循环
- Server 开关在请求途中被关闭时仍回复,按中英切换处理,TSF 只丢弃后续排队按键,
不再超时重连
- 已发出的循环回复未被应用(含 Superseded)时走完整重连,避免日文状态两端不一致
- 循环切换补上光标处状态提示和标点同步
- 切换语言时复用暂存的另一语言会话,不在按键路径上重建引擎和打开 msime.db
- 配置读取的语言与开关改为原子量;TrilingualCycleChanged 的能力过滤移到发送方
- 中日切换不再重发 TrilingualCycleChanged;结束组合被拒绝时不计入统计
---------
Co-authored-by: fanlusky <1730976608@qq.com >
2026-10-09 15:44:41 +08:00
時崎 ギャラクシー
aa5c632ea9
Merge pull request #711 from Tokisaki-Galaxy/feat/llm-model-fetch
...
feat: AI 辅助新增获取模型、测试连接与 Custom 提供商
2026-10-08 23:13:01 +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
luojiyin
ecbc932009
perf(engine): reuse int8 weights across eight rows
2026-10-06 09:24:24 +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