Commit Graph
31 Commits
Author SHA1 Message Date
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
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
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
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 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
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 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
Jia Sui efdea2c14f fix(engine): 全拼合法键入被别名改写后 preedit 不再照搬改写串 2026-10-01 15:09:32 +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
Lu Fan(SonnyCalcr) 4375d80414 feat: 支持导入自定义辅助码,内置“加加”更名为“拼音加加” (#477)
* feat(engine): 支持 helpcodes/custom 下的自定义辅助码

custom 目录里的每个 .txt 都是一套方案,方案名为 custom/<文件名>。
文件开头的 "# name:" / "# name_en:" 注释给出中英文显示名,缺省用文件名;
兼容 BOM、CRLF 和全角冒号。方案名不能跳出 custom 目录。

* feat(engine): WebView 契约新增 openHelpcodeDirectory

设置页请求打开自定义辅助码目录,仅允许 settings 页发送。同步 ui-html/webview2/shared。

* feat(server): 设置页列出自定义辅助码并可打开其目录

配置快照带上 helpcode.custom_schemas 与 helpcode.custom_directory,每次都会重新扫描;
方案文件被删除或改名后回退到 lantian。两个设置宿主都会处理 openHelpcodeDirectory。

* feat(ui-html): 辅助码设置显示拼音加加与自定义方案

内置方案“加加”改名为“拼音加加”。自定义方案追加在内置方案之后;新增说明区,
提供“打开目录”和“刷新方案”两个按钮,刷新完成后弹出提示。

* feat(installer): 升级与迁移数据目录时保留自定义辅助码

升级清理时只清掉 helpcodes 里的内置表,保留 custom 子目录;更换数据目录时一并迁移;
安装时建出 helpcodes\custom。
2026-09-26 20:21:55 +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
Jia Sui 1cfba58eba feat(engine): 光标驱动的拼音前缀解码与候选重算
caret 从纯显示状态升级为查询管线输入:set_caret 量化到最后一个完整
音节单元边界(只消费 segment_raw_boundaries,#187 契约),前缀候选
独立解码、preedit 保持全串拼音风格;纯移动光标同样重算候选。
IInputScheme::set_raw_input 提升为接口方法以支持不动现场组合的
独立前缀查询。runtime_isolation 两处按 R3/R4 新语义改写(caret 在
音节中间 floor 到空前缀、候选为空是预期状态);新增 caret 前缀
会话单测(engine/tests + server CI 目标,隔离词库夹具,覆盖
全拼 floor、双拼贪心配对、五笔无单元模型、boundary=0 空候选)。
2026-09-22 14:56:22 +08:00
Jia Sui 566ff8b832 feat(engine): 新增加加辅助码(拼音加加),第六套辅助码方案
按笔顺拆前两个部件、各取读音首字母(妈 = 女 n + 马 m = nm),部件用加加俗称读音(亻=d、
扌=t、纟=j、忄=s、攵=f、夂=z、刂=l、彳=s);138 个独体/部首字取「本字声母 + 起笔」。码表
7968 条,覆盖《通用规范汉字表》7846 字,比小鹤少 422 个扩展区生僻字——缺码会让含这些字的
词组拿不到辅助码,是已知取舍。

编码对齐拼音加加 5.x 安装包内的 fzm.bin(双拼键位已换算为声母):6487 字取到两码,6349 字
逐字一致,138 字保留本表规则,覆盖外的 800 字按同一规则重建。来源与非官方性质写在 NOTICE.md
与随包的 THIRD_PARTY_NOTICES.txt。

- engine/contracts/assets 注册 helpcode_jiajia,assets.h 重新生成(5 → 6)
- 设置页两个下拉显示名「加加」,两份配置模板注释同步
- 两侧测试补支持列表;README / README.en.md / server/AGENTS.md 改「六套」

默认值不变(双拼 lantian、全拼 ziranma)。
2026-09-20 22:00:34 +08:00
fanlusky 01c5bca325 fix(engine): 选中的整句候选落成用户词组
词格(CandidateSource::Generated)和 Google 解码器(CandidateSource::Fallback)
猜出来的整句在词库里没有对应的行,而调频走的是
update_weight_by_pinyin_and_word——它只改 SQLite 里已经存在的行,找不到行就什么
也不做。于是用户选中这种整句多少次,下次输入同样的拼音,它仍然是猜出来的,仍然
排在词库里那条同音短语后面,看起来就是"永远提不上来"。

选中即落库才是对的处理:存成用户词组之后,下次它以 UserDatabase 候选出现,按
quanpin::generated_sentence_insert_position 的约定排在两条整句之前,之后再选还能
走正常调频。

落库不受 frequency_adjustment_ 约束(那是候选词频策略,不是造词),也不跳过
index == 0——首位整句同样没有落库,下次仍要靠猜。长度上限对标
quanpin::WordLatticeOptions::max_phrase_syllables,再长的整句只是这一次输入的
产物,落库除了撑大用户词库没有别的作用。
2026-09-19 13:48:17 +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 e64195731e feat(server): Backspace 删空剩余拼音后退选已选分词(#35)
已选分词是造词中间态:删空剩余拼音时不再整条 composition 丢弃,
而是退选最后一段并恢复其原始拼音与候选。

engine:
- SelectionTransition 暴露本次选择消费掉的原始输入(保留大小写与双拼按键)
engine/contracts:
- 新增回复类型 CompositionRestored=14 与能力位 CompositionRestore;
  MaxKnown 同步抬高,Server 按协商能力位门控发送,旧 DLL 不会收到未知帧
server:
- 造词中间态压 (consumed_raw, previous_creating_word) 快照,边界 Backspace 弹栈退选
- 任何清空 raw 的路径同时清 creating_word 与快照历史,避免跨 composition 泄漏
windows:
- _HandleCompositionBackspace 提示退选时读回包重建 keystroke buffer / word / 预编辑 / 光标
- NeedToCreateWord 与 CompositionRestored 共用载荷解析;旧 Server 与 UiLess 回退旧行为

Closes #35
2026-09-17 18:45:01 +08:00
Jia Sui 94abc08e7c feat(engine): ü 系拼写别名归一,非标准拼法候选带轻标记
nue/lue 是词库标准键 nve/lve 的混拼别名,此前按原样查库必然落空。
把别名归一收敛到 resolve_segments 唯一咽喉点(jqxy 系 jv→ju 既有行为
一并收敛),查询、调频、造词键全部落到标准拼法上;别名改写同步进
pinyin_segmentation_,mark_autocorrect_candidates 据此给非标准拼法的
候选写 corrected_from,前端以词尾 * 轻标记提示(对标搜狗纠错星标),
提交、调频、置顶、造词不受影响。

契约翻转:fold_autocorrect_letters 不再把 v 折叠成 u——旧契约
「别名永不标记」按产品决策废弃,别名即标记;nu/nv、lu/lv 是真实
不同音节,归一按段精确匹配 [nl]ue,绝不互串,nu'e 手动分隔符不受
影响。composition 层显示折叠保留(职责是分隔符重建的等价分类),
注释改写说明与字典侧标记契约的分工。
2026-09-13 15:56:29 +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