AI 回覆
使用者和 AI 機器人單聊時,機器人的回覆是一條 type 為 ai 的訊息,內容邊生成邊推送過來。小程式 SDK 的 im.ai 與 Web SDK 相同:按順序拼接實時內容、斷線後續傳、重新上線時補發,回覆結束後以訊息正文為準。介面、欄位和事件的完整說明見 Web SDK 的 AI 回覆,本頁說明在小程式頁面中如何顯示。機器人和回覆由你的服務端建立,見 AI 對話。
版本
AI 回覆從 @deeprespond/im-miniprogram@1.0.6 起提供,安裝見概述與安裝。
整理成檢視
小程式不能直接渲染 Markdown。SDK 的 render.aiView(message, live) 把一條 AI 訊息整理成模板可以直接使用的檢視,正文轉成 rich-text 的節點陣列(只生成節點,不生成 HTML 字串;連結只保留文字):
const { render } = require('@deeprespond/im-miniprogram');
const view = render.aiView(message); // 已结束:取消息正文
const live = render.aiView(message, im.ai.state(message.body.stream_id)); // 生成中:取实时内容| 欄位 | 說明 |
|---|---|
stream_id、status | 流 ID;streaming、completed、stopped、failed |
streaming、thinking、waiting | 生成中;只有思考過程、還沒有正文(顯示“思考中”);還沒有任何內容(顯示“正在回覆”) |
reasoning | 思考過程的文字 |
tools | 工具呼叫:id、title、state(running、done、failed,結束時仍在進行的為 canceled) |
blocks | 正文中的塊:kind 為 text(nodes 為 rich-text 節點,last 表示最後一塊,用於顯示游標)、image、file(name、size、ext) |
error | 生成中斷時要顯示的說明;其他狀態為空字串 |
text | 複製用的純文字 |
不是 AI 訊息時返回 null。
跟隨生成中的內容
訊息列表中的 AI 訊息是正文的快照,生成中的內容隨 ai.streamUpdated 變化。用頁面繫結按 stream_id 維護一份實時檢視,事件觸發時重新計算:
Page({
behaviors: [app.behavior],
onLoad({ key }) {
// 整理消息列表时附上正文的视图(结束后以它为准)
this.drMessageList('chat', key, { mapItem: (item) => ({ ...item, ai: render.aiView(item) }) });
this.drState('aiLive', (im) => {
const items = this.drListOf('chat')?.getSnapshot().items || [];
const live = {};
for (const m of items) {
if (m.type !== 'ai' || m.body?.status !== 'streaming') continue;
const state = im.ai.state(m.body.stream_id);
// 键加前缀:setData 的路径中纯数字的键会被当作数组下标
if (state) live['s' + m.body.stream_id] = render.aiView(m, state);
}
return live;
}, ['ai.streamStarted', 'ai.streamUpdated', 'ai.streamEnded'], { lists: ['chat'] });
},
stopAI(e) {
app.im.ai.stop(e.currentTarget.dataset.stream).catch((error) => app.report(error));
},
});只需要一條回覆時,也可以用 /bind 入口的 DR_STATES.aiStream(streamId) 繫結它的實時狀態(im.ai.state() 的結果,結束後為 null)。
訊息迴圈中優先使用實時檢視,結束後回到 mapItem 中由訊息正文整理出的檢視:
<template name="ai">
<view class="ai-msg" data-status="{{ai.status}}">
<view wx:if="{{ai.reasoning}}" class="ai-reasoning">{{ai.thinking ? '思考中…' : '已深度思考'}}</view>
<view wx:for="{{ai.tools}}" wx:for-item="tool" wx:key="id" class="ai-tool ai-tool-{{tool.state}}">{{tool.title}}</view>
<block wx:for="{{ai.blocks}}" wx:for-item="block" wx:key="index">
<view wx:if="{{block.kind === 'text'}}">
<rich-text nodes="{{block.nodes}}" user-select/><text wx:if="{{ai.streaming && block.last}}">▍</text>
</view>
<image wx:elif="{{block.kind === 'image'}}" src="{{block.url}}" mode="widthFix"/>
<view wx:elif="{{block.kind === 'file'}}">{{block.name}} {{block.size}}</view>
</block>
<view wx:if="{{ai.status === 'stopped'}}">已停止生成</view>
<view wx:if="{{ai.status === 'failed'}}">生成中断:{{ai.error}}</view>
<button wx:if="{{ai.streaming}}" size="mini" data-stream="{{ai.stream_id}}" catchtap="stopAI">停止生成</button>
</view>
</template>
<view wx:for="{{chat.items}}" wx:key="_key">
<template wx:if="{{item.type === 'ai'}}" is="ai" data="{{ai: aiLive['s' + item.body.stream_id] || item.ai}}"/>
</view>rich-text 節點帶有 ai-p、ai-h、ai-list、ai-li、ai-quote、ai-code、ai-inline-code、ai-strong、ai-em、ai-link、ai-table、ai-tr、ai-th、ai-td 等 class,可以在頁面樣式中設定。
- 停止生成:只有接收回復的使用者可以停止,已結束的回覆返回當前狀態,不報錯。
- 重新生成:再發一次被回覆的問題,機器人的服務端會開始一條新的回覆。
- 斷線、切到後臺再回來時,SDK 自動補齊正在生成的內容。
示例
示例小程式 的聊天頁已顯示 AI 回覆(pages/chat),包括思考過程、工具呼叫、Markdown 正文、檔案、停止生成、複製和生成中斷的提示,可以作為參考。
