视觉输入法 · API 调用说明 / Visual Input · API Guide
中文在前,English follows each section. 公开页面:https://chu.ac.nz/p/ime-api.html(由本文生成)。
1. 它是什么 / What it is
中文 视觉输入法(视觉检字法)不用拼音,也不用背字根:看字由哪些部分组成,笔画 → 构件(含变形)→ 构件的位置 → 候选字,一步步找到字。莱斯学院把它做成了公开接口和可嵌入组件,其他网站、App、教学平台不需要再自己开发。
English The visual input method finds a character by sight, not by pinyin or memorised codes: strokes → parts (variants included) → the part's position → candidate characters. It is available as a public API and an embeddable widget, so other sites, apps and learning platforms do not need to build it again.
三种用法,选一种 / Three ways to use it:
| 用法 / Way | 适合 / Best for | 工作量 / Effort |
|---|---|---|
A. iframe 组件 https://chu.ac.nz/embed/ime |
网页,想要现成的完整键盘 / web pages that want the ready-made keyboard | 几行代码 / a few lines |
B. REST 接口 https://chu.ac.nz/v1/ime/… |
自己做界面(网页、App、小程序、游戏) / building your own UI | 自己画界面 / you draw the UI |
C. 离线数据 GET /v1/ime/data + 本文算法 |
无网络环境、桌面/手机输入法 / offline, native IMEs | 自己实现算法(很短) / implement the short algorithm |
2. 通用规则 / Common rules
- 地址 Base URL:
https://chu.ac.nz - 不需要登录、不需要密钥 No login, no API key. 只读 GET / Read-only GET.
- 跨域 CORS:
/v1/ime*和/sdk/*允许任何网站调用(Access-Control-Allow-Origin: *),不带 Cookie / any origin may call them, no cookies. - 限速 Rate limit:每个 IP 每分钟 240 次,超过返回
429。建议客户端缓存(响应带Cache-Control: public, max-age=300);需要大量调用请用/v1/ime/data一次取回整套数据 / 240 requests per minute per IP, then429. Cache on the client, or fetch the whole dataset once with/v1/ime/data. - 商用或大流量请先写信到 support@chu.ac.nz / For commercial or high-volume use, write to support@chu.ac.nz first.
- 错误 Errors:JSON
{"error":"CODE","message":"…"},状态码400(参数错)、404(没有这个构件/字)、429(太快)/ status 400 bad parameter, 404 unknown part or character, 429 too fast. - 字符 Characters:URL 里的汉字要 UTF-8 百分号编码(
encodeURIComponent)/ percent-encode Chinese characters in URLs.
3. 概念 / Concepts
- 八个笔画 Eight strokes(代码 code → 键位 key):
h横一 1、s竖丨 2、p撇丿 3、n捺乀 4、d点丶 5、t提㇀ 6、g钩亅 7、z折㇕ 8。 - 构件 Part:汉字的组成部分,包括各种变形(如 阝 亻 氵 扌 刂)。编号就是字形本身,如
阝。共 835 个。/ A component of a character, variant forms included (阝 亻 氵 扌 刂 …). Its id is the glyph itself. 835 parts. - 位置 Position:构件在字里的位置,代码如
A02(左)、A04(右)、A05(上)、A07(下)、A01(整体),每个位置有一个 4×4 的mask(16 个字符0/1,从左到右、从上到下,1表示构件占这一格)。共 43 种。/ Where the part sits, e.g.A02left,A04right,A05top,A07bottom,A01whole;maskis a 4×4 grid as 16 chars. - 笔画串
strokes参数:按书写顺序,可写字母hspndtgz、数字1–8、笔画字形一丨丿乀丶㇀亅㇕或中文名横竖撇捺点提钩折,可混用。/ In writing order; letters, digits 1–8, stroke glyphs or Chinese names, mixable.
4. 接口 / Endpoints
GET /v1/ime
说明、八个笔画(含键位)、数量。/ Info, the eight strokes with their keys, counts.
{"name":"Clavis visual stroke input (视觉检字法)","version":2,"strokes":[{"key":1,"code":"h","glyph":"一","zh":"横","en":"horizontal"}, …],"counts":{"parts":835,"positions":43,"characters":1649}}
GET /v1/ime/components
笔画 → 构件。/ Strokes → parts.
| 参数 Param | 说明 Description |
|---|---|
strokes |
已点的笔画(可空:空则返回最常用的构件)/ strokes tapped so far (empty = most common parts) |
used |
已选过的构件,逗号分隔,不再返回 / parts already chosen, comma-separated, excluded |
limit / offset |
分页,limit 默认 60,最大 500 / paging, default 60, max 500 |
规则 Rule:构件的笔画里必须包含所点的笔画;和所点笔画完全一样的构件(match:"exact")排最前,其余按使用频率从高到低(freq,越大越常用)。match 为 exact、prefix(以所点笔画开头)、ordered(顺序包含)、loose(只是包含)。/ The part's strokes must contain the tapped strokes; an exact match comes first, the rest by usage frequency (freq, higher = more common).
GET /v1/ime/components?strokes=s&limit=3
{"strokes":["s"],"total":498,"items":[
{"glyph":"丨","strokes":"s","freq":2008,"match":"exact"},
{"glyph":"口","strokes":"s,z,h","freq":70954,"match":"prefix"},
{"glyph":"亻","strokes":"p,s","freq":70200,"match":"ordered"}]}
GET /v1/ime/positions
构件可能出现的位置。/ Where a part can appear.
| 参数 Param | 说明 |
|---|---|
part |
构件字形,必填 / the part glyph, required |
with |
已选的组合 构件@位置,…;有它时只统计还能剩下的字 / already chosen pairs part@pos,…; counts only the characters still possible |
GET /v1/ime/positions?part=阝
{"part":"阝","items":[{"code":"A02","name":"左","mask":"1100110011001100","count":22},{"code":"A04","name":"右","mask":"0011001100110011","count":4}]}
count 是这个位置下有几个字;最大的就是“最常见的位置”。/ count = characters at that position; the largest is the most common place.
GET /v1/ime/candidates
候选字。/ Candidate characters.
| 参数 | 说明 |
|---|---|
parts |
构件@位置,逗号分隔,最多 6 个;多个取交集,必填 / part@pos list (max 6), intersected, required |
limit |
默认 60,最大 300 / default 60, max 300 |
GET /v1/ime/candidates?parts=阝@A02&limit=3
{"total":22,"items":[{"glyph":"阶","freq":12535},{"glyph":"队","freq":11438},{"glyph":"际","freq":8249}]}
freq 是字频,大的在前。/ freq is character frequency; higher first.
GET /v1/ime/char/{字}
一个字拆成哪些(构件, 位置)。/ How a character decomposes.
GET /v1/ime/char/明
{"glyph":"明","freq":24518,"parts":[{"part":"月","pos":"A04","posName":"右"},{"part":"日","pos":"A02","posName":"左"}]}
GET /v1/ime/data
整套数据(带 ETag,支持 If-None-Match 返回 304,约 100 KB)。格式 / format:
{"strokes":[[code,glyph,pinyin]],
"comps":[[glyph,"z,s",freq]], // 构件:字形、笔画序列、使用频率
"pos":[[code,name,mask16]], // 位置
"rows":[[char,part,posCode,(1=推导)]], // 字 = 构件 + 位置(一个字有多行)
"freq":{char:n}} // 字频
5. 用法 A:iframe 组件 / Way A: the iframe widget
<textarea id="box"></textarea>
<iframe src="https://chu.ac.nz/embed/ime?lang=zh" style="width:100%;height:420px;border:0" title="视觉输入"></iframe>
<script>
const box = document.getElementById('box');
addEventListener('message', e => {
if (e.origin !== 'https://chu.ac.nz' || e.data?.source !== 'clavis-ime') return;
const m = e.data;
if (m.type === 'insert') { box.setRangeText(m.text, box.selectionStart, box.selectionEnd, 'end'); box.focus(); }
if (m.type === 'backspace') { /* 删前一个字符 / delete the previous character */ }
if (m.type === 'enter') { /* 换行或提交 / newline or submit */ }
if (m.type === 'height') document.querySelector('iframe').style.height = m.height + 'px';
});
</script>
lang:界面语言zh en ar es fr ja ko ms pt ru th vi。/ UI language.- 消息 Messages(iframe → 外层 host):
{source:'clavis-ime', type:'insert', text}、backspace、enter、ready、height。外层 → iframe:{source:'clavis-ime-host', type:'reset'}。 - 组件内含四种键盘:笔画(视觉输入)、ABC、123、中文标点。/ Four keyboards inside: visual, ABC, 123, Chinese punctuation.
- 实体键盘的数字键在 iframe 外面的页面里,组件收不到;要支持“按 1–8 打笔画”,请用用法 B。/ Physical keys are outside the iframe; for “press 1–8 for strokes” use Way B.
6. 用法 B:REST + 小封装 / Way B: REST and the tiny SDK
import { clavisIme } from 'https://chu.ac.nz/sdk/clavis-ime.mjs';
const ime = clavisIme();
const a = await ime.components('2'); // 点“竖” / tap vertical
const b = await ime.positions('阝'); // 阝 的位置 / positions of 阝
const c = await ime.candidates([['阝', 'A02']]); // 候选字 / candidates
curl 'https://chu.ac.nz/v1/ime/components?strokes=2&limit=5'
curl 'https://chu.ac.nz/v1/ime/candidates?parts=%E9%98%9D@A02'
推荐的界面流程 Recommended UI flow
1. 用户点笔画 → 调 components?strokes=…,列出构件(常用在前)。/ stroke tap → list parts.
2. 点构件 → 调 positions?part=…&with=…。只有一个位置就自动选;最大 count 的位置标“常见”并默认高亮。/ part tap → positions; auto-pick if only one; mark the biggest count as common.
3. 点位置 → 把 构件@位置 加进列表,调 candidates?parts=… 立刻显示候选字。/ position tap → candidates right away.
4. 想缩小范围 → 回到 1,把已选构件放进 used,再加一个构件。/ narrow: repeat with used.
5. 点候选字 → 输入。/ tap a character → insert.
6. 实体键盘:1–8 = 笔画,空格/回车选中,←→ 换选,退格退一步,Esc 清空。/ keyboard shortcuts.
7. 用法 C:离线实现 / Way C: offline
取 /v1/ime/data 缓存到本地,然后:/ Cache /v1/ime/data, then:
components(picked): 候选 = 构件中 笔画 ⊇ picked(多重集包含)
排序 = exact(笔画与 picked 完全相同)在前,其余按 freq 降序
positions(part): 统计 rows 中该构件各位置的字数,count 降序
candidates(pairs): 每个 (part,pos) 取 rows 里的字集合,求交集,按 freq[char] 降序
参考实现 / Reference implementation:https://chu.ac.nz/js/imecore.mjs(约 100 行,无依赖,浏览器和 Node 通用)。
8. 版本与变更 / Versioning
接口路径带 /v1/;新增字段不算破坏性变更,请忽略不认识的字段。若有破坏性变更会换成 /v2/ 并保留 /v1/ 一段时间。/ Paths are under /v1/. New fields are not breaking: ignore unknown ones. Breaking changes will ship under /v2/, with /v1/ kept for a while.