更新记录

uni-ai-chat 1.1(2026-07-30) 下载此版本

✅ 第一阶段开发完成 - 项目骨架 + 核心 Chat UI 组件

按照 uni-ai-chat-plugin-plan.md 计划,第一阶段(第1周)的所有文件已创建完成:


平台兼容性

uni-app(5.08)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
- - - - - - - -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - -

🤖 uni-ai-chat 插件使用说明

UniApp AI 智能对话组件 — 支持多模型接入、SSE 流式输出、会话管理、暗黑模式、国际化等特性。


📋 目录

  1. 快速开始
  2. 安装与配置
  3. 组件 Props
  4. 组件 Events
  5. 组件 Methods
  6. 支持的模型
  7. 项目结构
  8. 完整示例
  9. 高级用法
  10. 常见问题

🚀 快速开始

1. 安装依赖

npm install uni-ai-chat pinia
# 或
yarn add uni-ai-chat pinia

2. 注册组件

main.js 中注册 Pinia 和组件:

import { createSSRApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

export function createApp() {
  const app = createSSRApp(App)

  // 注册 Pinia 状态管理(必须)
  app.use(createPinia())

  return { app }
}

3. 页面中使用

<template>
  <view class="chat-page">
    <UniAiChat
      apiKey="your-api-key-here"
      model="gpt-4o-mini"
      systemPrompt="你是一个智能助手,请用中文回答用户的问题。"
      :contextRounds="10"
      @error="handleError"
    />
  </view>
</template>

<script setup>
import UniAiChat from '@/uni-ai-chat/components/uni-ai-chat/index.vue'

function handleError(error) {
  console.error('Chat error:', error.message)
}
</script>

<style>
.chat-page {
  height: 100vh;
}
</style>

📦 安装与配置

方式一:npm 安装(推荐)

npm install uni-ai-chat

方式二:手动引入

uni-ai-chat 目录复制到项目的 uni_modules/components/ 目录下,然后直接引用:

import UniAiChat from '@/uni-ai-chat/components/uni-ai-chat/index.vue'

配置 Vite 别名

vite.config.js 中配置 @ 别名:

import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
import path from 'path'

export default defineConfig({
  plugins: [uni()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './')
    }
  }
})

微信小程序注意事项

微信小程序不支持 AbortController,需要引入 polyfill:

// main.js 顶部
import './uni-ai-chat/utils/abort-controller-polyfill.js'

📖 组件 Props

参数 类型 默认值 必填 说明
apiKey String '' API Key,用于调用 AI 模型接口
model String 'gpt-4o-mini' 模型名称,详见支持的模型
apiEndpoint String '' 自定义 API 端点,留空使用模型默认端点
systemPrompt String '你是一个智能助手...' 系统提示词,定义 AI 角色和行为
contextRounds Number 10 上下文记忆轮数(每轮一问一答)
temperature Number 0.7 温度参数 (0-2),值越高回答越随机
maxTokens Number 2048 最大 Token 数,限制单次回答长度
enableVoice Boolean false 是否启用语音输入按钮
darkMode Boolean/String 'auto' 暗黑模式:true 开启、false 关闭、'auto' 跟随系统
locale String '' 语言设置:'zh-CN''en-US''ja-JP''ko-KR',留空自动检测
showSessionList Boolean true 是否显示左侧会话列表
sessionListTitle String '' 会话列表标题,留空使用默认
inputPlaceholder String '' 输入框占位符文本,留空使用默认
emptyText String '' 空状态提示文本,留空使用默认

Props 使用示例

<UniAiChat
  :apiKey="'sk-xxx'"
  :model="'deepseek-chat'"
  :apiEndpoint="'https://api.deepseek.com/v1'"
  :systemPrompt="'你是一名资深的前端工程师,擅长 Vue 和 UniApp 开发。'"
  :contextRounds="20"
  :temperature="0.8"
  :maxTokens="4096"
  :enableVoice="true"
  :darkMode="'auto'"
  :locale="'zh-CN'"
  :showSessionList="true"
  :sessionListTitle="'历史对话'"
  :inputPlaceholder="'请输入您的问题...'"
  :emptyText="'开始一段新的对话吧 ✨'"
/>

📡 组件 Events

事件名 说明 回调参数
@error 请求出错时触发 (error: Error)
@send 发送消息时触发 (message: Object){ id, role, content, timestamp }
@response 收到完整响应时触发 (response: String) — 完整响应文本
@sessionChange 切换会话时触发 (sessionId: String)

Events 使用示例

<template>
  <UniAiChat
    ref="chatRef"
    :apiKey="apiKey"
    @error="onError"
    @send="onSend"
    @response="onResponse"
    @sessionChange="onSessionChange"
  />
</template>

<script setup>
function onError(error) {
  console.error('请求出错:', error.message)
  uni.showToast({ title: `错误:${error.message}`, icon: 'none' })
}

function onSend(message) {
  console.log('用户发送消息:', message.content)
}

function onResponse(response) {
  console.log('AI 响应完成')
}

function onSessionChange(sessionId) {
  console.log('切换到会话:', sessionId)
}
</script>

🛠️ 组件 Methods

通过 ref 获取组件实例后调用:

方法名 说明 参数
toggleDarkMode() 切换暗黑模式
clearMessages() 清除当前会话所有消息
createSession() 创建新会话
switchSession(id) 切换到指定会话 sessionId: String

Methods 使用示例

<template>
  <view>
    <button @click="toggleDark">切换暗黑模式</button>
    <button @click="clearChat">清除对话</button>
    <button @click="newSession">新建会话</button>

    <UniAiChat ref="chatRef" :apiKey="apiKey" />
  </view>
</template>

<script setup>
import { ref } from 'vue'

const chatRef = ref(null)
const apiKey = 'sk-xxx'

function toggleDark() {
  chatRef.value?.toggleDarkMode()
}

function clearChat() {
  chatRef.value?.clearMessages()
}

function newSession() {
  chatRef.value?.createSession()
}
</script>

🤖 支持的模型

模型标识 模型名称 提供商 适配器 默认端点
gpt-4o GPT-4o OpenAI openai https://api.openai.com/v1
gpt-4o-mini GPT-4o Mini OpenAI openai https://api.openai.com/v1
deepseek-chat DeepSeek V3 DeepSeek openai https://api.deepseek.com/v1
ernie-4.0 文心一言 4.0 百度 ernie https://aip.baidubce.com/rpc/2.0/ai_custom/v1/wenxinworkshop/chat
qwen-max 通义千问 Max 阿里云 qwen https://dashscope.aliyuncs.com/api/v1

使用自定义模型

如果使用与 OpenAI 兼容接口的模型(如 Claude 通过 API 代理、本地 LLM 等),只需设置 apiEndpoint 即可:

<UniAiChat
  apiKey="sk-xxx"
  model="gpt-4o-mini"  <!-- 模型标识可自定义 -->
  apiEndpoint="https://your-proxy.com/v1"
/>

🏗️ 项目结构

uni-ai-chat/
├── components/
│   └── uni-ai-chat/          # 核心组件
│       ├── index.vue          # 主组件入口(聊天界面整体布局)
│       ├── chat-message.vue   # 消息气泡组件(渲染对话消息)
│       ├── chat-input.vue     # 输入框组件(文本输入/发送/停止)
│       ├── chat-session.vue   # 会话列表组件(管理多会话)
│       ├── sse-parser.js      # SSE 流式解析器(解析 AI 流式响应)
│       └── style.scss         # 样式文件(浅色/深色主题)
├── utils/
│   ├── api.js                 # API 请求封装(多模型适配、流式请求)
│   ├── storage.js             # 本地存储工具(基于 uni-storage)
│   ├── markdown.js            # Markdown 渲染工具(解析→节点树→HTML)
│   └── i18n.js                # 国际化工具(中/英/日/韩)
├── store/
│   └── chat.js                # Pinia 状态管理(会话、消息、流式更新)
├── config/
│   └── index.js               # 配置文件(模型列表、默认参数、存储键名)
├── USAGE.md                   # 本使用说明文档
├── README.md                  # 项目简介文档
└── package.json               # 包信息

💻 完整示例

基础聊天页面

<template>
  <view class="chat-container">
    <!-- 顶部工具栏 -->
    <view class="toolbar" :style="{ paddingTop: safeAreaTop + 'px' }">
      <view class="toolbar-left">
        <button class="tool-btn" @click="toggleSessionList">
          <text>☰</text>
        </button>
      </view>
      <view class="toolbar-center">
        <text class="toolbar-title">AI 智能对话</text>
        <text class="toolbar-subtitle">{{ currentModelName }}</text>
      </view>
      <view class="toolbar-right">
        <button class="tool-btn" @click="toggleDark">
          <text>{{ isDark ? '☀️' : '🌙' }}</text>
        </button>
        <button class="tool-btn" @click="showSettings = true">
          <text>⚙️</text>
        </button>
      </view>
    </view>

    <!-- 聊天组件 -->
    <view class="chat-wrapper">
      <UniAiChat
        ref="chatRef"
        :apiKey="settings.apiKey"
        :model="settings.model"
        :apiEndpoint="settings.apiEndpoint"
        :systemPrompt="settings.systemPrompt"
        :contextRounds="settings.contextRounds"
        :temperature="settings.temperature"
        :maxTokens="settings.maxTokens"
        :darkMode="isDark ? true : 'auto'"
        :showSessionList="showSessions"
        @error="handleError"
      />
    </view>

    <!-- 设置弹窗 -->
    <view class="modal-overlay" v-if="showSettings" @click="showSettings = false">
      <view class="modal-content" @click.stop>
        <view class="modal-header">
          <text>⚙️ 设置</text>
          <button @click="showSettings = false">✕</button>
        </view>
        <scroll-view class="modal-body" scroll-y>
          <view class="form-group">
            <text>API Key</text>
            <input v-model="settings.apiKey" type="text" password />
          </view>
          <view class="form-group">
            <text>系统提示词</text>
            <textarea v-model="settings.systemPrompt" maxlength="500" />
          </view>
          <view class="form-group">
            <text>上下文轮数:{{ settings.contextRounds }}</text>
            <slider v-model="settings.contextRounds" :min="1" :max="50" />
          </view>
        </scroll-view>
        <view class="modal-footer">
          <button @click="saveSettings">保存设置</button>
        </view>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, reactive, computed, onMounted } from 'vue'
import UniAiChat from '@/uni-ai-chat/components/uni-ai-chat/index.vue'
import { SUPPORTED_MODELS } from '@/uni-ai-chat/config/index'

const chatRef = ref(null)
const isDark = ref(false)
const showSettings = ref(false)
const showSessions = ref(true)
const safeAreaTop = ref(44)

const settings = reactive({
  apiKey: '',
  model: 'gpt-4o-mini',
  apiEndpoint: '',
  systemPrompt: '你是一个智能助手,请用中文回答用户的问题。',
  contextRounds: 10,
  temperature: 0.7,
  maxTokens: 2048
})

const currentModelName = computed(() => {
  return SUPPORTED_MODELS[settings.model]?.name || settings.model
})

onMounted(() => {
  loadSettings()
  // 适配状态栏高度
  try {
    const info = uni.getSystemInfoSync()
    safeAreaTop.value = (info.statusBarHeight || 20) + 44
  } catch (e) {}
})

function toggleDark() {
  isDark.value = !isDark.value
  chatRef.value?.toggleDarkMode()
}

function toggleSessionList() {
  showSessions.value = !showSessions.value
}

function loadSettings() {
  try {
    const saved = uni.getStorageSync('chat-settings')
    if (saved) Object.assign(settings, saved)
  } catch (e) {}
}

function saveSettings() {
  try {
    uni.setStorageSync('chat-settings', settings)
  } catch (e) {}
  showSettings.value = false
  uni.showToast({ title: '设置已保存', icon: 'success' })
}

function handleError(error) {
  uni.showToast({ title: error.message, icon: 'none' })
}
</script>

<style>
.chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #F5F5F5;
}

.toolbar {
  display: flex;
  align-items: center;
  padding: 6px 12px;
  background-color: #FFFFFF;
  border-bottom: 1px solid #E5E5EA;
  z-index: 10;
}

.toolbar-center {
  flex: 1;
  text-align: center;
}

.toolbar-title {
  font-size: 16px;
  font-weight: 600;
}

.toolbar-subtitle {
  font-size: 11px;
  color: #8E8E93;
}

.chat-wrapper {
  flex: 1;
  overflow: hidden;
}

/* 设置弹窗样式 */
.modal-overlay {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,0.4);
  z-index: 1000;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.modal-content {
  width: 100%;
  max-height: 80vh;
  background: #FFFFFF;
  border-radius: 16px 16px 0 0;
}

.modal-body {
  padding: 16px 20px;
  max-height: 50vh;
}

.form-group {
  margin-bottom: 16px;
}

.form-group text {
  display: block;
  font-size: 14px;
  margin-bottom: 6px;
}

.form-group input,
.form-group textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid #E5E5EA;
  border-radius: 8px;
  font-size: 14px;
  background: #F5F5F5;
  box-sizing: border-box;
}

.form-group textarea {
  height: 80px;
  resize: none;
}
</style>

🔧 高级用法

1. 自定义 API 代理

通过后端代理转发请求,避免前端暴露 API Key:

<UniAiChat
  :apiKey="'proxy-token'"
  :apiEndpoint="'https://your-backend.com/api/chat'"
  :model="'gpt-4o'"
/>

后端代理示例(Node.js):

app.post('/api/chat', async (req, res) => {
  const response = await fetch('https://api.openai.com/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`
    },
    body: JSON.stringify(req.body)
  })

  // 流式转发
  response.body.pipe(res)
})

2. 多模型切换

<template>
  <view>
    <picker :range="modelList" @change="onModelChange">
      <text>{{ currentModel }}</text>
    </picker>
    <UniAiChat ref="chatRef" :apiKey="apiKey" :model="currentModel" />
  </view>
</template>

<script setup>
import { ref, computed } from 'vue'
import { SUPPORTED_MODELS } from '@/uni-ai-chat/config/index'

const currentModel = ref('gpt-4o-mini')
const modelList = computed(() => 
  Object.entries(SUPPORTED_MODELS).map(([key, val]) => `${val.name} (${key})`)
)

function onModelChange(e) {
  const keys = Object.keys(SUPPORTED_MODELS)
  currentModel.value = keys[e.detail.value]
}
</script>

3. 暗黑模式跟随系统

<UniAiChat
  :darkMode="'auto'"
  @sessionChange="onSessionChange"
/>

配合外部切换按钮:

function toggleDarkMode() {
  chatRef.value?.toggleDarkMode()
}

4. 国际化配置

<!-- 英文 -->
<UniAiChat :locale="'en-US'" />

<!-- 日文 -->
<UniAiChat :locale="'ja-JP'" />

<!-- 韩文 -->
<UniAiChat :locale="'ko-KR'" />

5. 移动端适配(隐藏会话列表)

<template>
  <UniAiChat
    :showSessionList="!isMobile"
    @sessionChange="onSessionChange"
  />
</template>

<script setup>
import { ref, onMounted } from 'vue'

const isMobile = ref(false)

onMounted(() => {
  try {
    const info = uni.getSystemInfoSync()
    isMobile.value = info.windowWidth < 768
  } catch (e) {}
})
</script>

❓ 常见问题

Q1: 如何获取 API Key?

Q2: 为什么消息发送后没有响应?

  1. 检查 apiKey 是否正确配置
  2. 检查网络连接是否正常
  3. 查看控制台是否有 CORS 错误(微信小程序需配置合法域名)
  4. 检查 API 余额是否充足

Q3: 微信小程序中无法使用?

微信小程序需要:

  1. manifest.jsonmp-weixin 中配置 urlCheck: false
  2. 在微信公众平台配置 request 合法域名(如 api.openai.com
  3. 引入 AbortController polyfill

Q4: 如何清除所有聊天记录?

// 通过组件方法清除当前会话
chatRef.value?.clearMessages()

// 或通过 Storage 工具清除所有数据
import Storage from '@/uni-ai-chat/utils/storage'
Storage.clearAll()

Q5: 如何自定义样式?

组件使用 CSS 变量控制主题,可以覆盖这些变量:

/* 覆盖主题色 */
.uni-ai-chat {
  --chat-user-bubble: #4CAF50;   /* 用户气泡颜色 */
  --chat-link-color: #FF5722;    /* 链接/主题色 */
  --chat-bg: #FAFAFA;            /* 背景色 */
}

Q6: 支持哪些平台?

  • ✅ H5(浏览器)
  • ✅ 微信小程序
  • ✅ App(iOS/Android)
  • ✅ 支付宝小程序
  • ✅ 百度小程序
  • ✅ 头条小程序

Q7: 如何接入其他模型?

如果模型使用 OpenAI 兼容接口,直接设置 apiEndpoint 即可:

<UniAiChat
  apiKey="sk-xxx"
  model="custom-model"
  apiEndpoint="https://your-api.com/v1"
/>

如需添加新的模型适配器,可在 config/index.js 中添加模型配置,并在 utils/api.js 中添加对应的请求格式处理。


📄 许可证

MIT License © 2024


💡 提示: 更多信息请查看 README.md 或访问项目主页。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

暂无用户评论。