“Kime” 已经是韩国输入法引擎的名称,为了避免与已有项目冲突,将名称改为 Xime。
Xime 输入法 1.0 只是解决了输入法能用的问题,相对于商业输入法,至少对我来说,其实还差点意思。
1.0 时代,更多是为了快速实现一个可用的 MVP 版本,用于快速验证可行性。事件证明,Xime 真的很不错。
至少,我已经可以 100% 掌控输入法的 DIY 细节了,哪里不用得不舒服,我就可以改哪里,这是商业输入法完全不可能做到的事。
2.0 的目标是从能用做到好用。
全新的名字
Kime 刚好和韩国输入法引擎存在重名。因此,改为 Xime 输入法。目前 Xime 输入法应用名已经显示为 “曦码输入法”。
全新的UI设计
1.0 时代,Xime 输入法 的 UI 界面相对来说比较简陋,没有设计的痕迹。对于产品来说,1.0 的 UI 更接近于原型设计。因此 2.0 专门对 UI 进行了重构。
| 1.0 | 2.0 |
|---|---|
![]() | ![]() |
键盘调节
本质上讲,输入法其实是可覆盖在其他应用界面上的一个窗口。键盘调节就是在控制键盘的窗口大小与位置。
┌─────────────────────────────────────┐
│ CandidateBar (候选栏) │
├─────────────────────────────────────┤
│ 键盘区 │
│ (QWERTY/数字/符号/语音等) │
├─────────────────────────────────────┤
│ Spacer (底部间距) │
├─────────────────────────────────────┤
│ 底部按钮区 [收起] [切换] │
└─────────────────────────────────────┘
键盘调节支持2个功能:
- 上下移动键盘的高度: 指的是底部按钮区不变,候选栏和键盘区整体可以上下移动。
- 拉伸键盘的高度: 指的是底部按钮区不变,候选栏和键盘区整体可以上下拉伸。
可以看到,上面的 Spacer 区域是为了上下移动键盘的高度时的点位留的。
至于键盘调节层,则完全和键盘区域分离,通过共享状态来达到键盘调节效果。

语音转文本
我一直有一个观点,语音转文本的门槛在于 ASR 模型,而 ASR 参数量决定了语音转文本的质量。在这一点上,个人玩家是无论如何优化,都打不过商业公司的 ASR 模型的。因为商业输入法的语音转文本功能,完全可以不用部署在手机上,而是通过云端服务来获得最佳的效果。
但是我的个人使用场景里,还是会偶尔有使用语音转文本的需求,因此这个功能有必要添加。
我这里实现了2种:
- 在线 ASR: 通过云端服务获得结果,这里接入的是阿里百炼的语音转文本服务。这个成本非常低,按我的使用习惯,充5块估计能用2年。
- 本地 ASR: 我这里使用的是 sherpa-onnx 模型。
经过实际的测试,本地 ASR 模型的效果确实比较一般,只能说是能用,好处是它真的是纯本地的,没有任何网络访问,也不会有任何人收集隐私。

一个小问题: 标点符号怎么办?
在线 ASR 模型一般是自带标点符号(punctuation)预测的,毕竟是商用服务。比如:
“我的名字是张三我来自杭州你呢”
在线 ASR 模型可以自动得到:
“我的名字是张三。我来自杭州,你呢?”
但是本地 ASR 模型怎么办?
看了一下 sherpa-onnx 模型提供的标点预测模型 sherpa-onnx-punct-ct-transformer-zh-en-vocab272727-2024-04-12-int8
total 155776
-rw-r--r-- 1 fangjun staff 1.5K Jun 18 10:34 README.md
-rwxr-xr-x 1 fangjun staff 1.6K Apr 12 2024 add-model-metadata.py
-rw-r--r-- 1 fangjun staff 810B Apr 12 2024 config.yaml
-rw-r--r-- 1 fangjun staff 72M Jun 18 10:33 model.int8.onnx
-rwxr-xr-x 1 fangjun staff 745B Apr 12 2024 show-model-input-output.py
-rwxr-xr-x 1 fangjun staff 4.6K Apr 12 2024 test.py
-rw-r--r-- 1 fangjun staff 4.0M Apr 12 2024 tokens.json
int8 的模型大小竟然也有 72M !
这对于我来说,绝对是无法接受的!因为我的智能联想的模型才不到20mb。
但是认真思考一下,手机使用的标点预测模型真的这么大吗?
答案是否定的。
我们日常使用输入法,很少会用来办公等严肃场景,一般就是用来聊天对话。因此,我们不必预测所有的标点符号,也不必预测英文标点。甚至,因为一般也只用于聊天场景,对标点预测的精度也不需要那么高。
那这个需求很简单,我可以自己设计一个非常非常小的模型,只预测中文标点符号。而且可以直接使用用于智能联想的模型的数据集来训练它。
这个模型的项目名为: srf-punctuation。 它的结构如下:
PunctuationPredictor(
(encoder): SmallTransformer(
(embedding): Embedding(8000, 64, padding_idx=0)
(pos_encoding): PositionalEncoding(
(dropout): Dropout(p=0.1, inplace=False)
)
(transformer): TransformerEncoder(
(layers): ModuleList(
(0-1): 2 x TransformerEncoderLayer(
(self_attn): MultiheadAttention(
(out_proj): NonDynamicallyQuantizableLinear(in_features=64, out_features=64, bias=True)
)
(linear1): Linear(in_features=64, out_features=128, bias=True)
(dropout): Dropout(p=0.1, inplace=False)
(linear2): Linear(in_features=128, out_features=64, bias=True)
(norm1): LayerNorm((64,), eps=1e-05, elementwise_affine=True)
(norm2): LayerNorm((64,), eps=1e-05, elementwise_affine=True)
(dropout1): Dropout(p=0.1, inplace=False)
(dropout2): Dropout(p=0.1, inplace=False)
)
)
)
)
(classifier): Sequential(
(0): Linear(in_features=64, out_features=64, bias=True)
(1): GELU(approximate='none')
(2): Dropout(p=0.1, inplace=False)
(3): Linear(in_features=64, out_features=5, bias=True)
)
)
量化后为 int8 后实际大小为2.24mb,这直接比 sherpa-onnx 提供的模型小了 96.89%。
同时,srf-punctuation 也有一定的标点纠正能力。
不过,如上面模型结构看到的,它只支持4个标点符号(第1位是正常字符位),对于日常聊天是够用了,但是不适合用在其他场景。
智能联想
事实上,我并不太了解其他输入法(无论是商业的还是开源的)的智能联想功能是怎么实现的。N-Gram 或者大模型? 1.0 版本的智能联想功能,我采用的方案是 transformer 模型 + N-Gram 融合实现。transformer 模型负责固定的预测,N-Gram 负责用户过往的输入预测。
但是如果你有在用我的输入法,你会发现,这个智能联想功能,好像不是很智能,至少预测的词都有一点点的奇怪。
根本原因在于,由于我要快速验证 MVP 原型,这个 transformer 模型我当初并没有训练到一个非常好的效果,还有就是数据集方面也不够丰富。
另外一个原因是,手机的资源是有限的,而模型推理,是一个高能耗的任务。因此这个 transformer 模型的上限就被限制死了,参数量一定要足够的小,才能不造成过多地消耗手机的资源。
词表也要做一定的精简,在日常的生活中,我们常用字其实只有4000个左右,再加上一些常用的词组,因此我的设计词表大小目标是 8000。一半用于常用字,一半用于常用的词组。
生成办法是,使用常见汉字表label.txt + 频率分析做剪枝。
- 训练标准 BPE tokenizer(12000 词表)
- 采样 30% 语料统计每个 token 频次
- 分类:
- 单字在
label.txt中 → 保留 - 单字不在
label.txt中 → 丢弃(覆盖率 < 0.2%) - 多字组合 → 按频率排序保留 top-N
- 单字在
- 输出
vocab.json(~8000 词表)+train.bin+val.bin。
常见汉字表
label.txt来源于 CASIA-HWDB 1.0 数据集。
通过一些融合实验,终于有一些不错的效果:
联想预测示例:
"今天天气" -> 晴 | 怎么样 | 预 | 炎 | 太 | 很 | 真 | 非常 | 如何 | 确实
"我们一起去" -> 看 | 看看 | 公园 | 找 | 。 | 吧 | 探索 | 体验 | 做 | 吃
"我觉得" -> 自己 | 这个 | 这 | 你 | 我 | 这是 | 很 | 你的 | 我们 | 他
"明天早上" -> 点 | 起来 | 上 | 起 | 去 | 时 | 要 | 就 | 来 | 睡
"我在上海的" -> 路 | 房 | 街 | 妈妈 | 地铁 | 东 | 火车 | 夜 | 那个 | 交通
"正在吃饭" -> 。 | 的 | 时 | 的时候 | 和 | 了 | ? | 前 | 的人 | 吃
"无论如何" -> 选择 | 选 | 是 | 处理 | 使用 | 坚持 | 如何 | 成立 | 计算 | 做
"你" -> 好 | 提到 | 现在 | 怎么 | 听 | 是一 | 愿意 | 说 | 已经 | 看
"我真的是受" -> 不 | 过 | 了 | 伤 | 着 | 人 | 骗 | 我 | 惊 | 歧视
"好" -> 像 | 奇 | ! | 多 | 玩 | 了 | 处 | 象 | 好 | 事
"是我" -> 不 | 刚 | 爸 | 现在 | 自己 | 看 | 最 | 朋友 | 喜欢 | 说
"不想出" -> 去 | 什么 | 来 | 一 | 话 | 国 | 门 | 问题 | 事 | 差
最后
这个输入法主要还是为我自己服务,经过之前的一些 breaking 的乱改,目前应该终于稳定下来了。
如果你觉得适合你的话: https://github.com/ximeiorg/Xime/releases

