Shapeshift
一个能读懂你意图的输入框。 一个文本框,随着你的输入自动变形为合适的 UI——事件卡片、待办清单、计时器、取色器、账单分摊、投票、单位换算等等。
dinner with priya friday 8pm on zoom → Event card · Friday · 8 PM · Priya · Video call
buy milk, eggs, bread and coffee → Shopping checklist
split 2400 between 3 → ₹800 each
minecraft diamond → #4AEDD9
意图由 TypeSafe AI 的 Jev 模型进行分类:一次调用并行回答 14 个类型化问题(是哪种卡片,外加"是否视频通话?““是否紧急?“等信号)。其余一切——日期、金额、单位、数学——都是确定性代码。Jev 负责决策,代码负责计算。
它默认完全离线工作,内置关键词分类器,无需账号即可运行。
快速开始
需要 Bun 1.2+。
bun install
bun dev
打开 http://localhost:3000 开始输入。按 / 查看所有卡片类型。
使用在线 Jev 模型(可选)
cp .env.example .env.local
# 然后设置 TYPESAFE_API_KEY=...(在 https://console.typesafe.ai/keys 获取)
重启 bun dev。右下角的延迟读数会从 jev-offline 切换为 jev-1.13.0。密钥只在服务器端(/api/intent)读取,永远不会到达浏览器。如果 API 不可达或被限流,Shapeshift 会静默回退到离线模式。
| 变量 | 默认值 | 作用 |
|---|---|---|
TYPESAFE_API_KEY | (空) | 启用在线模型。留空或为占位值时保持离线。 |
JEV_MODEL | jev-1.13.0 | 固定的模型版本。 |
NEXT_PUBLIC_USE_MOCK | false | 设为 true 则即使有密钥也强制离线。 |
NEXT_PUBLIC_SITE_URL | http://localhost:3000 | 用于 Open Graph 元数据。 |
卡片类型
| 卡片 | 试试输入 |
|---|---|
| 事件 | lunch with rahul and anna tomorrow |
| 提醒 | remind me to pay rent tomorrow urgent |
| 清单 | buy milk, eggs, bread and coffee |
| 计时器 | 25 min focus |
| 习惯打卡 | gym 3x a week |
| 颜色 | #ff6b35、tiffany blue、minecraft diamond |
| 分摊 | split 2400 between 3 |
| 支出 | spent 450 on uber |
| 换算 | 5 miles in km、72f to c |
| 计算 | 18% of 3450 |
| 行程 | flight to goa next weekend |
| 投票 | pizza or burgers for friday? |
| 联系人 | rahul 98200 12345 rahul@mail.com |
| 书签 | https://vercel.com/blog check later |
| 倒计时 | days until christmas |
| 时区 | 3pm pst in ist、what time is it in tokyo |
| 随机 | roll 2d6、flip a coin、pick one: tacos, sushi or pizza |
| 目标 | read 12 books this year, 4 done |
| 笔记 | 其他任何内容 |
保存的卡片存放在你的浏览器(localStorage)中,直到你删除它们。点击卡片即可编辑。
键盘操作
| 按键 | 操作 |
|---|---|
| Enter | 保存卡片 |
| Esc | 清空(或取消编辑) |
| Tab | 保留淡淡的预览 |
| ← → | 在"你是想输入"候选间切换 |
| / | 打开所有卡片类型 |
URL 参数:?debug=1 显示所有概率;?demo=1&loop=1 播放脚本化演示。
工作原理
原始模型输出会随输入不断闪烁,因此一个小型状态机将置信度转化为平稳的 UI 状态。只有当挑战者连续两次胜出(或非常有把握)时,卡片才会切换,信号徽章则使用开/关滞回区间。
图表均为 Excalidraw 文件——在 excalidraw.com 打开任意 docs/diagrams/*.excalidraw 即可编辑。
| 路径 | 内容 |
|---|---|
src/components/intents/registry.ts | 扩展点。 每种卡片类型一个条目。 |
src/lib/jev/questions.ts | Jev 问题 schema |
src/lib/jev/mock.ts | 离线关键词分类器(输出结构相同) |
src/lib/parse/ | 每种卡片类型一个确定性解析器 |
src/lib/decide.ts、src/lib/signals.ts | 平稳 UI 状态机 |
src/components/shapeshift/ | 外壳、候选 chips、调色板、已保存列表、HUD |
添加一种卡片类型
- 在
src/lib/jev/types.ts的INTENT_KEYS中添加 key。 - 在
src/lib/jev/questions.ts的intent中添加互不重叠的判据。 - 在
src/lib/parse/中编写解析器,并在src/lib/parse/index.ts中注册。 - 在
src/components/intents/中编写卡片组件,并添加 registry 条目。 - 教会
src/lib/jev/mock.ts中的离线分类器,并添加测试。
TypeScript 会指出你遗漏的任何内容。
开发
bun run check # 类型检查 + lint + 测试
bun test # 解析器、决策、信号与分类器测试
bun run build
技术栈:Next.js (App Router) · React 19 · TypeScript (strict) · Tailwind CSS v4 · shadcn/ui · Motion · chrono-node · zod。
