@lingshuai/chat-uniapp
v1.1.3
Published
UniApp chat SDK for AI-powered platform
Maintainers
Readme
@lingshuai/chat-uniapp
UniApp 聊天 SDK,支持流式对话、会话管理、离线存储,兼容 Vue 2 和 Vue 3。
平台支持
| 平台 | 流式传输 | 说明 |
|------|---------|------|
| 微信小程序 | ✅ 支持 | 使用 enableChunked + onChunkReceived |
| H5 | ✅ 支持 | 使用浏览器原生 fetch + ReadableStream |
| App (iOS/Android) | ✅ 支持 | 优先使用 RenderJS 真流式,降级为 plus.net 模拟流式 |
| 支付宝/百度/抖音小程序 | ⚠️ 降级 | 自动降级为非流式传输 |
安装
npm install @lingshuai/chat-uniapp
# 或
pnpm add @lingshuai/chat-uniappVue 2 项目额外依赖:
npm install @vue/composition-api快速开始
Vue 3 项目
<template>
<view class="chat-container">
<scroll-view class="messages" scroll-y>
<view v-for="msg in messages" :key="msg.id" class="message">
<text class="role">{{ msg.role }}:</text>
<text class="content">{{ msg.content }}</text>
</view>
</scroll-view>
<view class="input-area">
<input v-model="input" placeholder="输入消息..." />
<button @click="send" :disabled="loading">
{{ loading ? '发送中...' : '发送' }}
</button>
<button @click="reset">新对话</button>
</view>
<view v-if="error" class="error">{{ error }}</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { useChat } from '@lingshuai/chat-uniapp';
const input = ref('');
const { messages, loading, error, sendMessage, resetConversation } = useChat({
apiKey: 'sk_live_xxx',
appId: 'your-project-id',
baseUrl: 'https://pinyou.xin/api' // 可选
});
const send = () => {
if (input.value.trim()) {
sendMessage(input.value);
input.value = '';
}
};
const reset = () => {
resetConversation();
};
</script>
<style>
.chat-container {
display: flex;
flex-direction: column;
height: 100vh;
}
.messages {
flex: 1;
padding: 20rpx;
}
.message {
margin-bottom: 20rpx;
}
.role {
font-weight: bold;
margin-right: 10rpx;
}
.input-area {
display: flex;
padding: 20rpx;
border-top: 1px solid #eee;
}
.error {
color: red;
padding: 20rpx;
}
</style>Vue 2 项目
<template>
<view class="chat-container">
<scroll-view class="messages" scroll-y>
<view v-for="msg in messages" :key="msg.id" class="message">
<text class="role">{{ msg.role }}:</text>
<text class="content">{{ msg.content }}</text>
</view>
</scroll-view>
<view class="input-area">
<input v-model="input" placeholder="输入消息..." />
<button @click="send" :disabled="loading">
{{ loading ? '发送中...' : '发送' }}
</button>
</view>
</view>
</template>
<script>
import Vue from 'vue';
import VueCompositionAPI from '@vue/composition-api';
import { useChat } from '@lingshuai/chat-uniapp/vue2';
Vue.use(VueCompositionAPI);
export default {
setup() {
const input = ref('');
const { messages, loading, error, sendMessage, resetConversation } = useChat({
apiKey: 'sk_live_xxx',
appId: 'your-project-id'
});
const send = () => {
if (input.value.trim()) {
sendMessage(input.value);
input.value = '';
}
};
return {
input,
messages,
loading,
error,
send,
resetConversation
};
}
};
</script>会话管理
SDK 自动管理会话:
- 首次对话时,后端返回
conversationId - SDK 自动保存并在后续请求中带上
- 会话历史自动持久化到本地存储
- 重启应用后自动恢复上次会话
const { conversationId, resetConversation } = useChat(config);
// 开始新对话
resetConversation();
// 当前会话 ID
console.log(conversationId.value);API 参考
useChat(config)
参数 (ChatConfig):
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| apiKey | string | ✅ | API 密钥 (sk_live_xxx) |
| appId | string | ✅ | 项目 ID |
| baseUrl | string | ❌ | API 基础地址(默认:https://pinyou.xin/api) |
| timeout | number | ❌ | 请求超时时间(毫秒,默认:30000) |
| userId | string | ❌ | 用户标识 |
| sessionId | string | ❌ | 会话标识(自动生成) |
| maxRetries | number | ❌ | 请求失败最大重试次数(默认:3) |
| retryDelay | number | ❌ | 重试初始延迟毫秒数,指数退避(默认:1000) |
| maxStoredMessages | number | ❌ | 本地存储最大消息数(默认:100) |
| autoCleanup | boolean | ❌ | 超出限制时自动清理旧消息(默认:true) |
返回值 (UseChatReturn):
| 属性 | 类型 | 说明 |
|------|------|------|
| messages | Ref<Message[]> | 消息列表 |
| loading | Ref | 加载状态 |
| error | Ref<string | null> | 错误信息 |
| conversationId | Ref<string | null> | 当前会话 ID |
| sendMessage | (content: string) => Promise | 发送消息 |
| resetConversation | () => Promise | 开始新对话 |
| clearHistory | () => Promise | 清除当前会话的本地历史记录 |
| getStorageInfo | () => Promise | 获取存储信息(消息数、大小等) |
| exportMessages | () => Promise | 导出消息为 JSON 字符串 |
| importMessages | (jsonString: string) => Promise | 从 JSON 字符串导入消息 |
| abort | () => void | 中断流式传输 |
Message 类型
interface Message {
id: string; // 消息 ID
conversationId: string; // 会话 ID
role: 'user' | 'assistant'; // 角色
content: string; // 内容
status: 'sending' | 'streaming' | 'success' | 'error'; // 状态
createdAt: Date; // 创建时间
error?: string; // 错误信息(status 为 error 时)
}平台差异说明
微信小程序
- ✅ 完整支持流式传输(
enableChunked+onChunkReceived) - 需要在
manifest.json中配置域名白名单:{ "mp-weixin": { "setting": { "urlCheck": false }, "permission": { "scope.userLocation": { "desc": "你的位置信息将用于小程序位置接口的效果展示" } } } }
H5
- ✅ 使用浏览器原生
fetch+ReadableStream - 注意跨域问题(需要后端配置 CORS)
App 端
- ✅ 优先使用 RenderJS 实现真正的流式传输(
fetch+ReadableStream) - 如未挂载
RenderStreamWorker组件,自动降级为plus.net.XMLHttpRequest模拟流式 - 需要在
main.js中全局注册组件(见下方说明)
App 端启用真流式(推荐)
App 端默认使用 plus.net 模拟流式(先拉取全部数据再逐字显示)。要启用真正的流式传输,需注册 RenderStreamWorker 组件:
1. 在 main.js 中全局注册:
import RenderStreamWorker from '@lingshuai/chat-uniapp/components/RenderStreamWorker';
Vue.component('RenderStreamWorker', RenderStreamWorker);2. 在使用聊天的页面模板中放置组件:
<template>
<view>
<RenderStreamWorker />
<!-- 你的聊天 UI -->
</view>
</template>组件不可见,不影响布局。如果不放置该组件,SDK 会自动降级为 plus.net 模拟流式,功能不受影响。
其他小程序
- ⚠️ 自动降级为非流式传输
- 需要在各平台后台配置域名白名单
高级用法
直接使用 ApiClient
如果不需要 Vue 响应式,可以直接使用底层 ApiClient:
import { ApiClient, EventEmitter } from '@lingshuai/chat-uniapp';
const events = new EventEmitter();
const client = new ApiClient({
apiKey: 'sk_live_xxx',
appId: 'your-project-id'
}, events);
// 监听事件
events.on('message:stream:chunk', (data) => {
console.log('收到消息块:', data.chunk);
});
// 发送消息
await client.sendMessage({
content: 'Hello',
stream: true
});
// 重置会话
client.resetConversation();自定义存储
import { UniAppStorage } from '@lingshuai/chat-uniapp';
const storage = new UniAppStorage(200); // 最多存储 200 条消息
// 保存会话(自动清理旧消息)
await storage.saveConversation('conv_123', messages);
// 加载会话
const messages = await storage.getConversation('conv_123');
// 保存当前会话 ID
await storage.saveCurrentConversationId('conv_123');
// 获取当前会话 ID
const currentId = await storage.getCurrentConversationId();
// 清除指定会话
await storage.clearConversation('conv_123');
// 获取存储信息
const info = await storage.getStorageInfo('conv_123');
console.log(`消息数: ${info.messageCount}, 占用: ${info.estimatedSize}`);
// 导出/导入消息
const json = await storage.exportMessages('conv_123');
await storage.importMessages('conv_123', json);平台检测
import { detectPlatform, getPlatformCapabilities } from '@lingshuai/chat-uniapp';
const platform = detectPlatform();
console.log('当前平台:', platform); // 'weixin-mp' | 'h5' | 'app' | ...
const capabilities = getPlatformCapabilities(platform);
console.log('是否支持流式:', capabilities.supportsStream);
console.log('是否支持 enableChunked:', capabilities.supportsChunked);注意事项
- 域名白名单:小程序平台需要在后台配置 API 域名白名单
- 存储限制:小程序本地存储有大小限制(通常 10MB),可通过
maxStoredMessages控制消息数量,开启autoCleanup自动清理旧消息 - 网络环境:弱网环境下建议增加超时时间,SDK 内置指数退避重试机制(可通过
maxRetries和retryDelay配置) - Vue 2 项目:需要安装
@vue/composition-api并在main.js中注册 - 中文字符:微信小程序的 ArrayBuffer 解码已处理 UTF-8 多字节字符(包括跨分片的不完整字节序列)
- 跨域问题:H5 端需要后端配置 CORS 允许跨域请求
故障排查
微信小程序无法连接
- 检查域名白名单配置
- 开发阶段可在开发者工具中关闭域名校验
- 检查 API Key 和 App ID 是否正确
H5 跨域错误
后端需要配置 CORS:
@CrossOrigin(origins = "*")
@RestController
public class ChatController {
// ...
}App 端流式传输问题
App 端优先使用 RenderJS 实现真流式,如遇问题:
- 确认已在
main.js中全局注册RenderStreamWorker组件 - 确认聊天页面模板中已放置
<RenderStreamWorker />标签 - 如未使用 RenderJS,SDK 会降级为
plus.net模拟流式,确认plus对象可用(需在plus ready之后) - 确认网络请求域名已配置为安全域名
Vue 2 响应式问题
确保使用 Vue 2 兼容的数组操作:
// ✅ 正确
messages.value.push(newMessage);
// ❌ 错误(Vue 2 无法检测)
messages.value[0] = newMessage;许可证
MIT
支持
如有问题,请提交 Issue 或联系技术支持。
