npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lingshuai/chat-uniapp

v1.1.3

Published

UniApp chat SDK for AI-powered platform

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-uniapp

Vue 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);

注意事项

  1. 域名白名单:小程序平台需要在后台配置 API 域名白名单
  2. 存储限制:小程序本地存储有大小限制(通常 10MB),可通过 maxStoredMessages 控制消息数量,开启 autoCleanup 自动清理旧消息
  3. 网络环境:弱网环境下建议增加超时时间,SDK 内置指数退避重试机制(可通过 maxRetriesretryDelay 配置)
  4. Vue 2 项目:需要安装 @vue/composition-api 并在 main.js 中注册
  5. 中文字符:微信小程序的 ArrayBuffer 解码已处理 UTF-8 多字节字符(包括跨分片的不完整字节序列)
  6. 跨域问题:H5 端需要后端配置 CORS 允许跨域请求

故障排查

微信小程序无法连接

  1. 检查域名白名单配置
  2. 开发阶段可在开发者工具中关闭域名校验
  3. 检查 API Key 和 App ID 是否正确

H5 跨域错误

后端需要配置 CORS:

@CrossOrigin(origins = "*")
@RestController
public class ChatController {
    // ...
}

App 端流式传输问题

App 端优先使用 RenderJS 实现真流式,如遇问题:

  1. 确认已在 main.js 中全局注册 RenderStreamWorker 组件
  2. 确认聊天页面模板中已放置 <RenderStreamWorker /> 标签
  3. 如未使用 RenderJS,SDK 会降级为 plus.net 模拟流式,确认 plus 对象可用(需在 plus ready 之后)
  4. 确认网络请求域名已配置为安全域名

Vue 2 响应式问题

确保使用 Vue 2 兼容的数组操作:

// ✅ 正确
messages.value.push(newMessage);

// ❌ 错误(Vue 2 无法检测)
messages.value[0] = newMessage;

许可证

MIT

支持

如有问题,请提交 Issue 或联系技术支持。