更新记录
1.0.2(2026-05-23) 下载此版本
1.0.1(2026-05-23)
- 新增图片/视频消息发送能力,支持
sendSupportlyMedia。 - 新增附件鉴权访问 URL 生成能力,支持
getSupportlyAttachmentUrl。 - 支持远端图片展示和
uni.previewImage大图预览。 - 支持视频消息展示,可配合
<video controls>播放。 - 优化断线重连后的历史消息补拉说明。
- 完善插件
readme.md,补充初始化、消息结构、媒体消息、平台配置和常见问题。
1.0.0(2026-05-08) 下载此版本
- 首次发布 Supportly UniApp AI 客服 SDK
- 支持基于 Cloudflare 的免费自部署客服方案
- 支持 RAG 知识库智能问答
- 支持 HTTP 消息发送、WebSocket 实时接收、历史同步和断线重连
平台兼容性
uni-app(5.07)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
supportly-ai-chat
Supportly AI Chat 是一个用于 uni-app 的 Headless 客服聊天 SDK。插件只负责会话、消息、WebSocket、历史同步和图片/视频上传,不绑定任何 UI 框架;聊天页面、气泡样式和业务按钮由接入项目自己实现。
在线演示
后台 Demo:
https://supportly.comarket.dev/
默认账号:
邮箱:admin@example.com
密码:admin123
Web Chat Widget Demo:
https://supportly.comarket.dev/demo
Server API:
https://api.supportly.comarket.dev
功能
HTTP 初始化访客会话
HTTP 发送文本消息
HTTP 上传图片 / 视频消息
WebSocket 实时接收新消息
断线重连
重连后按 lastMessageId 补拉历史
本地 visitorId / session 持久化
message.id 去重
连接状态回调
消息回调
附件鉴权访问 URL 生成
依赖的后端接口
插件对接 Supportly Server API 的 Widget 接口:
POST /api/widget/conversations
POST /api/widget/conversations/:conversationId/messages
POST /api/widget/conversations/:conversationId/messages/media
GET /api/widget/conversations/:conversationId/messages
GET /api/widget/conversations/:conversationId/messages/:messageId/attachments/:index
GET /api/widget/ws
媒体文件由 Server API 写入 Cloudflare R2,客户端读取附件时通过 visitor token 鉴权。
快速使用
import {
initSupportly,
connectSupportly,
closeSupportly,
sendSupportlyText,
sendSupportlyMedia,
getSupportlyAttachmentUrl,
loadSupportlyMessages,
onSupportlyMessage,
onSupportlyStatus,
} from "@/uni_modules/supportly-ai-chat";
const removeMessageListener = onSupportlyMessage((message) => {
console.log("message", message);
});
const removeStatusListener = onSupportlyStatus((status) => {
console.log("status", status);
});
await initSupportly({
apiBaseUrl: "https://api.example.com",
wsBaseUrl: "wss://api.example.com",
channelAccountId: "ch_xxx",
visitorId: "user_123",
pageUrl: "app://support",
pageTitle: "在线客服",
});
connectSupportly();
await sendSupportlyText({
content: "你好",
clientMessageId: "local_001",
});
const messages = await loadSupportlyMessages(null);
console.log(messages);
closeSupportly();
removeMessageListener();
removeStatusListener();
初始化
await initSupportly({
apiBaseUrl: "https://api.example.com",
wsBaseUrl: "wss://api.example.com",
channelAccountId: "ch_xxx",
visitorId: "user_123",
pageUrl: "app://support",
pageTitle: "在线客服",
});
参数说明:
| 参数 | 必填 | 说明 |
|---|---|---|
apiBaseUrl |
是 | Server API HTTP 地址,例如 https://api.example.com |
wsBaseUrl |
是 | Server API WebSocket 地址,例如 wss://api.example.com |
channelAccountId |
是 | Supportly 后台创建的 Web Chat 渠道 ID |
visitorId |
否 | 业务侧用户 ID。未传时 SDK 自动生成匿名 visitorId |
pageUrl |
否 | 当前页面 URL 或业务场景标识 |
pageTitle |
否 | 当前页面标题 |
initSupportly 会创建或恢复访客会话,并把 visitorId 和 session 写入 uni storage。
连接状态
const unsubscribe = onSupportlyStatus((status) => {
console.log(status);
});
状态值:
idle
initializing
connecting
connected
reconnecting
disconnected
error
建议 UI 显示:
function formatStatus(status) {
if (status === "connected") return "在线";
if (status === "connecting") return "连接中";
if (status === "reconnecting") return "重连中";
if (status === "initializing") return "初始化";
if (status === "disconnected") return "离线";
if (status === "error") return "异常";
return "待连接";
}
接收消息
const unsubscribe = onSupportlyMessage((message) => {
messages.value.push(message);
});
SDK 内部会按 message.id 去重。WebSocket 断开重连后,会自动调用 loadSupportlyMessages(lastMessageId) 补拉断线期间的新消息。
消息结构:
{
id: "msg_xxx",
conversationId: "conv_xxx",
direction: "inbound", // inbound | outbound | internal | system
senderType: "customer", // customer | agent | ai | system
messageType: "text", // text | image | video | file | audio | event
content: "你好",
attachments: [],
status: "received", // received | sending | sent | failed
createdAt: "2026-05-23T10:00:00.000Z"
}
附件结构:
{
type: "image", // image | video | file | audio
url: "本地临时 URL 或远端 URL",
r2Key: "media/conv_xxx/msg_xxx/att_xxx/photo.jpg",
fileName: "photo.jpg",
mimeType: "image/jpeg",
size: 123456
}
发送文本
await sendSupportlyText({
content: "你好",
clientMessageId: "local_001",
});
参数说明:
| 参数 | 必填 | 说明 |
|---|---|---|
content |
是 | 文本内容,SDK 会 trim |
clientMessageId |
否 | 客户端消息 ID,用于幂等和替换本地乐观消息 |
返回值是服务端创建的 inbound message。
发送图片
uni.chooseImage({
count: 1,
sizeType: ["compressed"],
sourceType: ["album", "camera"],
success: async (result) => {
const filePath = result.tempFilePaths[0];
const message = await sendSupportlyMedia({
filePath,
content: "图片说明",
clientMessageId: `local_${Date.now()}`,
mimeType: "image/jpeg",
});
console.log(message);
},
});
发送视频
uni.chooseVideo({
sourceType: ["album", "camera"],
compressed: true,
success: async (result) => {
const message = await sendSupportlyMedia({
filePath: result.tempFilePath,
content: "视频说明",
clientMessageId: `local_${Date.now()}`,
mimeType: "video/mp4",
});
console.log(message);
},
});
sendSupportlyMedia 参数说明:
| 参数 | 必填 | 说明 |
|---|---|---|
filePath |
是 | uni-app 临时文件路径 |
content |
否 | 图片/视频说明 |
clientMessageId |
否 | 客户端消息 ID |
fileName |
否 | 文件名;未传时 SDK 从 filePath 推断 |
mimeType |
否 | MIME;未传时 SDK 从扩展名推断 |
后端当前支持:
图片:image/jpeg, image/png, image/gif, image/webp,最大 10 MB
视频:video/mp4, video/webm, video/quicktime,最大 50 MB
附件展示
服务端返回的附件可能没有公开 URL。展示远端附件时,用 getSupportlyAttachmentUrl(message, index) 生成带 visitor token 的鉴权 URL。
图片:
<image
v-if="message.messageType === 'image'"
:src="getSupportlyAttachmentUrl(message, 0)"
mode="aspectFit"
@click="previewImage(message, 0)"
/>
视频:
<video
v-if="message.messageType === 'video'"
:src="getSupportlyAttachmentUrl(message, 0)"
controls
/>
点击图片查看大图:
function previewImage(message, index) {
const url = getSupportlyAttachmentUrl(message, index);
uni.previewImage({
current: url,
urls: [url],
});
}
乐观消息建议
发送前可以先把本地消息插入列表:
const clientMessageId = `local_${Date.now()}`;
messages.value.push({
id: clientMessageId,
direction: "inbound",
senderType: "customer",
messageType: "text",
content,
attachments: [],
status: "sending",
createdAt: new Date().toISOString(),
});
try {
const remoteMessage = await sendSupportlyText({ content, clientMessageId });
replaceLocalMessage(clientMessageId, remoteMessage);
} catch (error) {
markMessageFailed(clientMessageId);
}
图片/视频乐观消息的 attachments[0].url 可以使用本地 filePath,上传成功后用服务端消息替换。
API
initSupportly(config): Promise<session>
connectSupportly(): void
closeSupportly(): void
sendSupportlyText({ content, clientMessageId }): Promise<message>
sendSupportlyMedia({ filePath, content, clientMessageId, fileName, mimeType }): Promise<message>
loadSupportlyMessages(afterMessageId): Promise<message[]>
getSupportlyAttachmentUrl(message, attachmentIndex): string
onSupportlyMessage(callback): () => void
onSupportlyStatus(callback): () => void
平台配置
H5:
生产环境使用 https:// 和 wss://。
如果浏览器跨域访问 API,Server API 需要允许对应 Origin。
App:
使用 uni.request / uni.uploadFile / uni.connectSocket / uni storage。
图片视频选择由业务页面调用 uni.chooseImage / uni.chooseVideo。
小程序:
需要在小程序后台配置合法 request 域名、uploadFile 域名和 socket 域名。
apiBaseUrl 对应 request/uploadFile 域名。
wsBaseUrl 对应 socket 域名。
生命周期建议
页面加载:
await initSupportly(config);
connectSupportly();
页面卸载:
closeSupportly();
unsubscribeMessage();
unsubscribeStatus();
常见问题
为什么提示 Supportly is not initialized?
在调用 sendSupportlyText、sendSupportlyMedia、loadSupportlyMessages、connectSupportly 前,必须先调用并等待 initSupportly(config) 成功。
为什么 WebSocket 连不上?
检查:
wsBaseUrl 是否是 wss://
小程序 socket 域名是否合法
Server API /api/widget/ws 是否可访问
conversationId 和 visitorToken 是否有效
为什么图片或视频上传失败?
检查:
apiBaseUrl 是否正确
小程序 uploadFile 域名是否合法
filePath 是否存在
mimeType 是否在后端允许列表中
图片是否超过 10 MB
视频是否超过 50 MB
Server API 是否配置 MEDIA_BUCKET
为什么附件图片打不开?
远端附件需要 visitor token 鉴权,请使用:
getSupportlyAttachmentUrl(message, 0)
不要直接拼 R2 地址,R2 bucket 默认应保持私有。
为什么消息重复?
SDK 会按远端 message.id 去重。业务侧如果做乐观消息,需要在发送成功后用服务端返回的消息替换本地 clientMessageId 消息。
AI 为什么没有回复图片/视频?
当前图片/视频消息不会触发 AI 自动回复。AI 回复只处理文本内容。
交流反馈
QQ 交流群:1081883123

收藏人数:
https://github.com/unicornB/Supportly-Ai
下载插件并导入HBuilderX
下载插件ZIP
赞赏(0)
下载 400
赞赏 0
下载 12301152
赞赏 1923
赞赏
京公网安备:11010802035340号