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)
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
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
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
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
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
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
Jia Sui
01c45c8d90
fix(server,ui-html,engine): octagram 激活中的模型包也可删除,引擎映射支持动态释放
2026-10-02 20:15:41 +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
fanlusky
31241d22ed
fix(engine,server,windows): 句中辅助码支持光标在句中插入,上屏按不带约束的排序调频
...
光标用箭头或 Ctrl+箭头移回句中后敲反引号,TSF、Server、引擎三处都要求光标在串尾,
反引号被当成标点,光标前的预编辑连同「·」一起上屏。改为只看光标前的部分:光标前是
完整的两键音节就收,落在音节中间或已有段的前面不收。形状规则新增
FanyImeMidSentenceHelpcode::AcceptsMarkerAt,三处共用;引擎的光标插入路径同时接受
句中的第一码和大写第二码。
句中辅助码筛过的列表里,要的词往往已经排第一,选第一个不调频,调了也是在筛过的列表
里排位,下次不敲辅助码时排序不变。现在带句中辅助码上屏词库候选时,改用去掉约束后的
候选作排位参照,选的是第一个也照样调;空格、数字键、鼠标点选都走 ProcessSelectionKey,
引擎自己的上屏路径同样处理。
2026-10-02 12:43:16 +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
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
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
1e372c9c48
fix(engine): 读词库的连接等写锁而不是直接失败
...
msime.db 的三条读连接(全拼词典、双拼词典、quanpin_query 的 SqliteDb)都没设
busy timeout。设置页或学习写入提交的那几毫秒里,落在这段时间的查询直接拿到
SQLITE_BUSY,这一页候选就是空的。统一设 250 ms(与 english.db 读连接一致):
写锁只占一次提交,这点等待足够;大批量导入时最多卡一下,而不是出空页。
这也是把学习写入挪出按键线程的前提:之后读写会真正并发。
2026-09-27 16:09:28 +08:00
fanlusky
fc6f6469f7
perf(engine): 上屏不再清空候选缓存,按键不再重复重建混合候选
...
- set_rescoring_context:每次选词都会换上文并清空 cache_、series_cache_ 和
segmentation_cache_,下一个词的前几键因此都是冷查询。上文只经神经重排
进入候选,没有生效的神经模型时与缓存无关,此时不清;之后打开神经重排
会经 set_sentence_association 清缓存。全拼、双拼同改。
- set_quanpin_autocorrect_types:Server 每键重新应用配置,值没变也会调用
update_mixed_candidates 复制整份候选列表。值不变时直接返回;构造时已把
初值同步给引擎。
2026-09-27 15:03:17 +08:00
fanlusky
57dd0fc2f3
fix(engine,server): 整句来源标签只挂在整句联想候选上
...
候选窗按 CandidateSource 挂〔Trigram〕/〔Unigram〕,但 Generated/Fallback 同时被
原样上屏兜底、英文模式原文、日期、Unicode、假名、译文义项等合成候选借用,导致
输入 E 等特殊模式前缀时原样候选被误标为〔Unigram〕。
WordItem 新增 sentence_association 标记,只由 Google 解码器整句(全拼、双拼)与
kenlm 词格整句置位;Server 挂标签时同时要求来源与标记。source 本身不变,落库与
学习策略不受影响。
2026-09-27 08:25:51 +08:00
fanlusky
e7f7addd4f
feat(engine): 神经网络整句联想与词格 n-best 重排
...
- 新增 engine/neural:移植 chinese-ime-lm 的字符级 Transformer 推理,在词格解出的最多 12 条
n-best 里重排挑选整句,desktop / keyboard 两档模型各出一条首选,后台 worker 异步打分
- 词格支持 n-best 输出与重排(quanpin/lattice_rerank),全拼、双拼共用
- 新增 SentenceAssociationOptions,经 QueryRequest 传给各 provider;四个来源默认全关
- 资源契约登记两个 safetensors 与 NOTICE;模型二进制不进仓库,由
scripts/fetch-neural-model.ps1 按 neural-model/lock.json 下载并校验 SHA256
- 新增 neural_sentence 测试
2026-09-24 14:03:39 +08:00
fanlusky
ccbaa3a631
fix(engine): 送进 Google 解码器前把 ü 换成 nue/lue/ju 写法
...
小鹤双拼 ntdddswu 出的是「女蛾黛动物」而不是「虐待动物」:nt 转成全拼后
是 nve(shuangpin_pinyin_set 把 nue 抹掉了,词库与词格那一侧统一用 v 形),
而本地 googlepinyinime-rev 的拼写表和 inputtools 云输入都不认 nve/lve/jv,
只有 nue/lue/ju/jue,也不做 v→ü 的转写。带分隔符的串照样送过去了,解码器
却把 nve 重新切成 nv + e,于是有了「女蛾」。
加一个 quanpin::to_google_spelling,按音节整体改写 nve→nue、lve→lue、
jv→ju 这一类拼写,只在两个 Google 解码器的边界上用:云输入的 query_text、
双拼与全拼的整句回退。词库查询和词格用的仍然是 canonical_syllable 那一侧的
v 形写法,没有动。nv'er、lv'se 这些 Google 也认的写法原样通过。
2026-09-19 12:29:01 +08:00
fanlusky
e2a5f5f988
fix(engine): 词格整句只用精确读音,并补上多音字读音先验
...
长句联想此前会把读音对不上的词拿去造句,也分不清多音字的常见读音与生僻读音。
词格的跨度查询改用批量精确键查询。原先走的 query_segments_keyed_flat 带降级:
精确键查不到就退到前缀区间扫描(key >= "gun'qi" AND key < …),gun'qi 因此捞出
gun'qiu 的「滚球」,简拼那两级同理。联想出来的每个词,读音都必须精确对上用户
敲的那段拼音。顺带省掉了白扫的前缀区间,也不再需要 QuerySource——区分全拼与
双拼的只有简拼那几级。
新增读音先验:每一行按「自己的权重 / 该拼音跨度的权重和」算读音占比,占比低于
免罚线的部分按 log10 扣分。语言模型只看汉字,分不出「卷」读 gun、「而」读 neng
这种词库里权重为 0 的多音字读音,于是 gun'qi 出「卷七」、neng'fa'sheng 出
「而发生」。不能整体按 log10 P(词|拼音) 扣,那等于把字频算两遍(语言模型已经
算过一次),「跑得很快」会被「跑的很快」压掉——得/地 各占 de 的 7%~9%,本来就是
常见读音;真正的生僻读音占比是 1e-5 量级,离免罚线还差好几个数量级。
ü 的两种拼法归一化到词库存的那一种。intact_pinyin_list() 两种都认,词库只存
一种(j/q/x/y 后写 u,l/n 后写 v),切出来的 jv、lue 这类音节因此一行都查不到。
改精确键查询之后这会让整张词格断在那里——wo'men'lue'de 解不出任何路径,长句
联想整个消失。lue 和 lve 本来就是同一个读音的两种拼写,归一化之后仍是精确匹配。
新增两条回归用例:生僻读音不得赢下词格;421 个合法音节每个都必须在词库里至少
查得到一行,切分器与词库哪边漂了都先在这里炸。
2026-09-19 10:08:39 +08:00
fanlusky
03a5b4fe26
feat(engine): 整句候选把词格排到 Google 解码器之前
...
词格换成 kenlm 三元模型打分之后,它出的整句整体比 Google 解码器那条准,
所以由它占首位。
merge_lattice_candidates 的插入点本来就在 Fallback 之前,word_lattice.h
里也是这么写的不变量;真正把次序翻过来的是词典层在合并之后的一个后置
步骤——它把 Fallback 重新提回表头。全拼和双拼各有一份,这次都删掉。
这一步此前没有任何测试盯着:test_pinyin 里的用例断的是
merge_lattice_candidates 自身,词典层怎么再排它看不见。补一个查询层的
回归用例,断相对位置而不是具体句子——词格出什么取决于 msime.db 和
sc.lm,钉死了会随词库更新而碎;两条来源凑不齐时按既有风格优雅跳过。
顺带修掉 ScopedLocalAppDataOverride 上一条已经过期的注释:dict_pinyin.dat
现在随安装包发布了,不发布的只有 role=user 的 user_dict.dat。
2026-09-19 10:08:39 +08:00
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
Lu Fan(SonnyCalcr)
e1d53dd8f0
Merge pull request #426 from ouchihao/codex/fix-299-double-helpcode-cache
...
fix(engine): isolate ordered double-helpcode query caches
2026-09-18 21:34:50 +08:00
Ouchihao
0925937bfe
fix(engine): isolate ordered double-helpcode query caches
2026-09-18 20:43:17 +08:00
Ouchihao
5e641fb5a0
fix(engine): accept yo as a complete shuangpin syllable
2026-09-18 20:35:14 +08:00
Jia Sui
b1ec3ab1e0
feat(server): Ctrl+Backspace 按分词删除前置拼音(#187)
...
组词中 Ctrl+Backspace 删除光标前的一个分词单元:剩余拼音非空时删
最后一个字的拼音(音节段),剩余拼音为空时删除最后一段已选分词。
engine:
- InputSession::segment_raw_boundaries() 作为按段删除/移动的唯一分段来源:
全拼把纠错显示串的分隔符映回 raw 下标,双拼与 pinyin_segmentation 共用贪心谓词,
2 字辅助码自成一段;非拼音方案与本地模式返回空表示无单位模型
server:
- IsSegmentBackspaceKey(Ctrl-only)、整段丢弃 / 边界截断 / 单字符回退三分支,
截断点残留分隔符清理
- 复用 CompositionRestored 回包(含 caret),仅协商能力位且非 UiLess 时发送;
新出现「只剩已选汉字、无拼音」的中间态
windows:
- 两处 Ctrl 闸门对组词中的 Ctrl+VK_BACK 放行,新增 FUNCTION_BACKSPACE_SEGMENT
与 _HandleCompositionBackspaceSegment(读回包重建,失败回退单字符)
- 空 raw 状态渲染、终态清理 word_for_creating_word,延迟投影失效处理
Closes #187
2026-09-17 23:01:31 +08:00
Jia Sui
6673155c7b
fix(engine): 双拼置顶权重静默失效——直切完整拼读检查并去除二次归一化
...
update_weight_by_pinyin_and_word 判定输入已是 canonical 全拼只看切分拼回
原串,而 correction 模式的 greedy 后备能把 qbtmuo 切成 q'b't'mu'o 这类恰好
拼回原串的碎片,归一化被跳过后 resize 截出错误 key;build_quanpin_sql_for_
updating_word 又对调用方已归一化的键再过一次双拼归一化,qin'tian'shuo 被
重切成 qi'n'ti'an'sang'shuo。两层叠加使三音节置顶 UPDATE 匹配 0 行仍返回
OK。直切增加完整拼读检查(与 delete 路径语义一致),SQL 构建器信任调用方
传入的 canonical 键。钉住用例 ThreeSyllables 已在前一提交启用。
2026-09-13 11:04:34 +08:00
fanlusky
cbd95f74e3
fix(engine): 消除 /W4 下的编译警告
...
一方代码在 /W4 下已零警告。剩余警告全部来自上游副本
(googlepinyinime-rev/、vendor/opencc/ 及其捆绑的 marisa),
按 AGENTS.md 保留上游原格式,有意不改。
- data_path.h、test_pinyin.cpp: _wgetenv 改 _wdupenv_s,返回值
用 optional 包一层,由 unique_ptr 负责 free
- quanpin_dictionary.cpp: 去掉条件表达式内的赋值。外层查询原本
只用其真假,reset_cache_if_database_changed() 可能使其失效,
故保留重取
- build_sql_for_checking_word: 删掉从未使用的 jp 形参
- 未使用的 catch 形参、int/size_type 符号不匹配
- wav_writer.h: 形参 sample_rate 遮蔽同名命名空间常量,改名
requested_sample_rate;默认值改为直接引用该常量,去掉魔数
- pinyin_file_io.h: _wfopen/_wopen 改 _wfsopen/_wsopen_s
最后一项没有用微软推荐的 _wfopen_s: 它打开的文件不可共享,而这是
词库文件,Server、TSF DLL 和设置进程会并发读同一份。_SH_DENYNO
正是被弃用调用原本的共享语义,因此只消除警告,不改变行为。
_wsopen_s 的 pmode 传 0,唯一调用方 userdict.cpp 用的是 O_WRONLY,
不带 _O_CREAT。
2026-09-13 02:22:53 +08:00
fanlusky
e835e09c20
fix(engine): give whole-sentence fallback candidates a canonical pinyin
...
The Google-pinyin whole-sentence candidate is inserted at index 0 in both
quanpin and shuangpin, so it is what Space commits. All four construction
sites built it without a canonical quanpin reading, so when it finished a
word-creation session update_creating_word_progress() had no reading to
join and can_store stayed false: the prefix plus the sentence went to the
host app but were never learned.
Carry the converted quanpin segmentation on those candidates, and extract
the early-return storage condition into a testable predicate.
2026-09-12 15:53:54 +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