Skip to main content
AI 客户端代码里全是重复的水管 —— 用 AbortController 取消生成、按 chunk 解码流式 响应、轮询长任务、分页历史记录。如果不抽象出来,每个 demo 或 feature 都会带上同样的 30 行模板代码。 vibestrap 在 @/ai/hooks 下提供 五个 React hook,把这些全封掉。你的组件专心写 UI。每个 hook 都纯客户端,服务端契约是普通的 JSON / text 端点,可以替换。

前置条件

  • 看过 providers 文档 —— 这些 hook 调的就是 manager 暴露出来的 后端。
  • API 路由挂在 /api/ai/chat/api/ai/history/api/credits/balance、 (默认值;每个 hook 都接受自定义 endpoint)。
  • 标准 UI 示例在 src/components/demos/{chat-demo,image-demo,document-demo}.tsx

API 参考

useGeneration(options?)

从一个吐 UTF-8 chunk 的服务端端点流式拉文本。 签名
适用场景:模型逐 token 输出的对话型流程。Hook 自己管 AbortController 和响应体解码。
参考实现:src/components/demos/chat-demo.tsx

useTask(options)

长任务:POST 启动 → 轮询到结束态。 签名
适用场景:图像生成、视频、文档处理 —— 一次 HTTP 装不下的任务。parse 把 hook 和 具体响应结构解耦。
参考实现:src/components/demos/image-demo.tsx

useCredits(endpoint?)

读当前登录用户的积分余额。 签名
适用场景:顶栏积分徽章、CTA 前的余额校验、付费回调后刷新。默认端点 /api/credits/balance
<CreditsBadge /> 已经包了这个 hook,大多数业务不直接用。

useHistory(endpoint?)

当前用户的 ai_call 历史,游标分页。 签名
AICallHistoryRow 包含 providermodeloperationstatusinputTokens(nullable —— 图像 / 视频 provider 不返回 token)、outputTokens(同)、 totalMscreatedAt。每页 20 条,游标是末行的 createdAt(ISO 字符串)。
参考实现:src/components/demos/document-demo.tsx

验证生效

  1. 起 dev server,登录。
  2. 打开 /playground/chat,输入。看 text 一字一字出来 —— 那就是 useGeneration 在流。
  3. 打开 /playground/image,提交 prompt。状态从 queued → running → succeeded — 那就是 useTask
  4. 打开 /dashboard/usage。列表刷新,Load more 能加更多行 —— 那就是 useHistory

常见坑

  • 流式端点返回 JSON 而不是 text。 useGeneration 是按 UTF-8 chunk 读 body 的。 如果路由 res.json(),你会一次拿到全文而不是流。请用 new Response(stream)text/plain content type。
  • 忘记 await generate() 它返回的是最终文本的 Promise,发完不管也行,但不 try/catch 就看不到错误。
  • useTask.parse 返回了错的状态字符串。 Hook 只在 'succeeded' | 'failed' | 'cancelled' 时停止轮询,其他都当「继续轮」。
  • useCredits 显示旧余额。 任何 AI 调用之后都要 refetch(),manager 是异步扣 积分的,徽章不会自己更新。

官方文档