你不安装我们的运行时,你调用它。
你的应用用我们发放的密钥调用 TinkySpeak 接口。你无需持有我们的代码,无需分发模型,而符号、声音与界面完全属于你。
试点阶段,人工发放。
目前没有自助开通密钥的控制台。你告诉我们你在做什么,我们发放密钥,并与你一起推进部署。如果你更希望把引擎运行在自己的基础设施里,而不是调用我们的服务,来信时说明即可——那是一次关于条款的沟通,而不是一个下载链接。
六步,从头到尾。
| 步骤 | 你要做的 |
|---|---|
| 1 申请密钥 | 告诉我们你在做什么、为谁而做。我们会为试点发放密钥,并与你讨论部署方式——目前还不是自助开通的控制台。 |
| 2 把密钥留在服务端 | 存入 TINKYSPEAK_API_TOKEN,以 Authorization: Bearer … 发送。切勿把密钥打包进应用——任何人都能读出来。当你服务多位用户时,账号与会话归属由你的后端负责。 |
| 3 每场对话开一个会话 | 会话承载语言、沟通设置与记忆。在对话持续期间保留它的 id,结束时删除。 |
| 4 跑通这五步 | hear → 渲染 → select → speak → confirm。这就是对话的全部接口,无论使用者是用触摸、开关还是眼动来选择,流程都一样。 |
| 5 接上你自己的符号 | 运行时绝不获取或绘制素材。你把选项映射到自己的符号库并返回描述对象;未匹配的选项保留表情符号。 |
| 6 需要时再接上摄像头 | 从你自己的摄像头发送画面,同样的磁贴就会返回——关于使用者眼前的菜单、货架或物品。 |
它该放在哪里,不该放在哪里。
# Your server, not the device in someone's hands.
export TINKYSPEAK_API_TOKEN="the key we issue you"密钥标识的是你的应用,而不是某个人。来自浏览器的请求必须来自你登记的来源;非回环地址必须使用令牌。运行时不记录任何对话请求体。
每场对话一个。
POST /v1/sessions
Authorization: Bearer $TINKYSPEAK_API_TOKEN
Content-Type: application/json
{ "language": "en", "partnerLanguage": "en",
"profile": { "age": 7, "level": "sentence", "choices": 6 } }
→ { "id": "SESSION_ID", "choices": [], ... }五次调用,中间那一步由你的应用掌控。
// 1 — what the other person said
const state = await api.hear({ text: 'Would you like tea or coffee?' });
renderYourTiles(state.choices); // six complete sentences
// 2 — the person picks a tile in YOUR interface
const selected = await api.select({ choiceId: tappedTileId });
// 3 — turn the draft into a delivery request
const pending = await api.speak({ draftId: selected.draft.id });
// 4 — YOUR speech engine says it, in your voice, on your device
await yourSpeechEngine(pending.speech.text, pending.speech.language);
// 5 — tell the runtime what actually happened
await api.confirmSpeech({ speechId: pending.speech.id, outcome: 'spoken' });每个 id 只能使用一次,因此过期的点击无法送出昨天的句子。并发操作返回 409 session_busy。送出失败时用 failed 或 cancelled 回报——绝不要盲目重试。
词语由我们提出,图像由你决定。
一个选项包含词语与身份。它看起来是什么样,只有你的应用能决定,因为只有你的应用了解这个人、他的词汇,以及他早已认得的那套图像。
// Every choice arrives with an id, a label, a sentence and an emoji.
// You decide what it looks like.
function yourArtworkFor(choice) {
const hit = myLibrary.lookup(choice.label, choice.sentence);
if (!hit) return null; // null keeps the emoji fallback
return { kind: 'symbol', library: 'my-aac-library', id: hit.id, alt: hit.alt };
// or: { kind: 'image', uri: '/my-art/water.png', alt: 'My water cup' }
}返回 null 就保留表情符号。对整句生成内容做匹配并不是通用符号词典——请提供语言感知的查找,并让它诚实地失败,而不是显示错误的图像。更换素材绝不会改变被说出的词语。
需要时给它一双眼睛。
视觉与对话模型分开配置,因此你可以加入摄像头功能,而不改变词语的生成方式。
// A photo from YOUR camera or photo picker, as base64.
const state = await api.scan({
images: [{ mimeType: 'image/jpeg', data: base64Frame }],
mode: 'menu', // auto | object | menu | scene
});
renderYourTiles(state.choices); // tiles about what is in the picture
state.vision.categories; // the whole catalog, paged
state.vision.objects; // { name, box, bodyPart }每次扫描最多八张图,单张 5 MiB。检测框是图像的比例值,原点在左上角。价格只是展示数据,绝不构成购买。识别可能出错,因此警告与原始文本都会返回给你的复核界面;读取不完整时会失败,而不是编造菜单。
继续阅读全部命令