本文只记 Skill 用到的端点。契约以稳定版(www.*)为准;标注「最新版」的能力可能在稳定版上还是 404。
基址记为 {API},形如 https://www.wikipali.org/api。所有响应统一形如:
{ "ok": true, "data": <任意>, "message": "" }
ok: false 时 message 是原因,HTTP 状态码同时表达语义。HTTP 200 不等于全部成功——见文末「静默跳过」。
| Token | 从哪来 | 代表谁 | 用在哪 | 有效期 |
|---|---|---|---|---|
| userToken | POST /v2/sign-in |
人类操作者 | 查/建 ai-model、签 access token、列 channel | 365 天 |
| modelToken | GET /v2/ai-model-token/{uid} |
AI 模型身份 | 写句子时的 Authorization |
30 天,可撤销 |
| accessToken | POST /v2/access-token |
被委托的 channel 编辑权 | 写句子时的 body 字段 | 7 天 |
写句子时两者同时出现:Authorization: Bearer <modelToken>,句子对象里带 access_token: <accessToken>。用错会让 editor_uid 落成人类用户,署名与审计就废了。
POST {API}/v2/sign-in body { "username": "<用户名或邮箱>", "password": "<明文>" }
data 是 JWT 字符串本身(不是对象)。message 是 invalid token——措辞误导,实际含义是用户名或密码不对。GET {API}/v2/auth/current(Bearer = userToken)
data: { id, nickName, realName, avatar, token, roles }realName 就是后面 studio_name 参数要用的值,不是 nickName。GET {API}/v2/ai-model?view=studio&name={studio_name}&keyword={模型名}(Bearer = userToken)
data: { rows: [...], count };keyword 是 like %kw% 模糊匹配,客户端必须自己做 name 精确比对。view 只接受 all / studio / usable / chat。传别的值会 500(服务端 switch 缺 default 分支,已知缺陷)。key / system_prompt 只在请求者是 owner 本人时才返回。POST {API}/v2/ai-model(Bearer = userToken) body {name, studio_name, model?, url?, key?, privacy?, description?, system_prompt?}
name 重复 → 409,客户端据此判定「已存在」。name / studio_name 缺失 → 422。studio_name 就是操作者本人的 studio(个人 studio),group studio 一律 403。PUT {API}/v2/ai-model/{uid}(Bearer = userToken)
null 才会清空。GET {API}/v2/ai-model-token/{uid}(Bearer = userToken)→ data: { uid, name, token }
typ: "ai-model" 与 ver。DELETE {API}/v2/ai-model-token/{uid}(Bearer = userToken)→ data: { uid, name, token_version }
GET {API}/v2/channel?view=user-edit(Bearer = userToken)→ data: { rows: [...], count }
uid / name / summary / type / owner_uid / lang / status / updated_at / created_at / role / studio。order / dir / limit(默认 200)/ offset / search。GET {API}/v2/channel/{uid} 可用于回显单个 channel 的名字。
POST {API}/v2/access-token(Bearer = userToken)
{ "payload": [ { "res_type": "channel", "res_id": "<channel uid>", "power": "edit", "book": 0 } ] }
→ data: { rows: [ { payload, token } ], count }
count: 0 和空 rows,HTTP 仍是 200。必须判空,等同 403 处理,不可继续写入。payload 里含 nbf / exp,据此判断何时重签。book 必须是整数。服务端校验用 $jwt->book !== $book 严格比较,而 $book 已被转成 int,写成 "1" 会让 "1" !== 1 恒真而永远鉴权失败。0 表示不限 book。POST {API}/v2/sentence(Bearer = modelToken)
{
"sentences": [
{
"book_id": 1,
"paragraph": 10,
"word_start": 0,
"word_end": 12,
"channel_uid": "<channel uid>",
"content": "译文",
"content_type": "markdown",
"access_token": "<第 5 步签出的 JWT>"
}
]
}
→ data: { rows: [ ... ], count }
(book_id, paragraph, word_start, word_end, channel_uid) 做 firstOrNew——存在即覆盖,不存在则新建。天然幂等,但也意味着会静默覆盖别人写的同位置句子,写前必须向用户确认。sent_histories(可追溯)、清缓存、发进度消息。book(不是 book_id)、paragraph、word_start、word_end、channel.uid、editor。核对写入结果要按这套字段匹配。sentences 字段时返回 HTTP 200 且 message: "no date"——这是客户端 bug,不是成功。store() 对逐句鉴权失败是 continue 掉的,不报错。所以:
提交 N 条、HTTP 200、
count却小于 N,意味着有句子没写进去。
必须把返回的 rows 与提交的句子逐条比对,把差集报给用户。
| 现象 | 含义 | 处置 |
|---|---|---|
| 401 | token 失效/过期/被撤销 | 提示重新登录或重取模型 token,不要自动重试 |
| 403 | 无 channel 编辑权,或不是模型 owner | 指出缺哪一项权限 |
| 404(较新端点) | 站点跑的是旧版代码 | 提示切到最新版站点,别当成「资源不存在」 |
| 409 | 同 studio 内模型重名 | 当作「已存在」,回查列表取 uid |
| 422 | 参数校验失败 | 看 message |
access-token 返回 count: 0 |
对该 channel 无编辑权(静默跳过) | 当作 403,中止写入 |
sentence 的 count < 提交条数 |
部分句子鉴权失败被跳过 | 逐条比对并报告 |
message: "no date" + 200 |
请求缺 sentences |
客户端 bug |
四个线上地址共享同一个数据库和同一把 JWT 密钥,凭据完全通用,可随时切换:
| 地址 | 地区 | 代码版本 |
|---|---|---|
https://www.wikipali.org/api |
.org | 稳定版 |
https://www.wikipali.cc/api |
.cc | 稳定版 |
https://next.wikipali.org/api |
.org | 最新版 |
https://next.wikipali.cc/api |
.cc | 最新版 |
http://127.0.0.1:8000/api |
开发机 | 另一个库、另一把密钥 |
.org / .cc 是地区可达性;www / next 是代码版本,不是数据环境。