ai-chat-sidebar
v1.0.17
Published
基于 Vue 3 的 AI 对话侧边栏组件,用于连接已部署的 LangGraph 服务
Maintainers
Readme
AI Chat Sidebar
基于 Vue 3 的 AI 对话侧边栏组件,用于连接已部署的 LangGraph 服务,可轻松集成到现有项目中。
注意: 这是一个纯前端组件,需要连接到已部署的 LangGraph 后端服务。
🏗️ 组件架构设计
本项目采用分层架构设计,实现了UI与业务逻辑的完全分离,提供了高度的可复用性和可维护性。
架构层级
┌─────────────────────────────────────────┐
│ UI 层 │
├─────────────────────────────────────────┤
│ ChatBox.vue (纯UI组件) │
│ ChatSidebar.vue (侧边栏容器) │
│ AIChat.vue (开箱即用组件) │
├─────────────────────────────────────────┤
│ 业务逻辑层 │
├─────────────────────────────────────────┤
│ ChatService.ts (聊天服务) │
│ useChat.ts (组合式函数) │
├─────────────────────────────────────────┤
│ 数据层 │
├─────────────────────────────────────────┤
│ LangGraphService.ts (WebSocket服务) │
│ remoteConfig.ts (配置管理) │
└─────────────────────────────────────────┘设计原则
职责分离:
- UI层:只负责界面展示,通过 props 和 events 通信
- 业务逻辑层:封装聊天相关业务逻辑
- 数据层:处理WebSocket连接和数据管理
高度可复用:
ChatBox.vue:纯UI组件,可在任何地方使用ChatService.ts:独立的服务类,可被多个组件使用useChat.ts:组合式函数,提供响应式状态管理
灵活的使用方式:
- 开箱即用:
<AIChat />一行代码搞定 - 自定义UI:使用
ChatBox+useChat - 完全自定义:直接使用
ChatService
- 开箱即用:
✨ 特性
- 🎨 现代化 UI - 基于 Element Plus 的美观界面
- 📱 响应式设计 - 支持移动端和桌面端
- 🔄 实时流式对话 - 支持 LangGraph 的流式响应
- 🎛️ 高度可配置 - 丰富的配置选项
- 📦 npm 包 - 可直接安装使用
- 🔌 TypeScript 支持 - 完整的类型定义
- 🎯 多实例支持 - 可在同一页面使用多个对话组件
- 🎨 丰富组件支持 - 代码块、表格、图表、文档、文件预览等
- 🔧 LangGraph 集成 - 连接已部署的 LangGraph 服务
- 🌐 远程服务器支持 - 支持连接多个远程 LangGraph 服务
- ⚙️ 服务器管理 - 可视化的服务器配置和管理界面
🏗️ 项目架构
你的项目 (前端组件)
↓ WebSocket/HTTP
已部署的 LangGraph 服务 (后端)这是一个纯前端组件库,通过 WebSocket 连接到已部署的 LangGraph 服务。详细架构说明请查看 ARCHITECTURE.md。
📦 安装
npm install ai-chat-sidebar样式引入
安装后需要引入样式文件:
// 在 main.js 或 main.ts 中引入样式
import 'ai-chat-sidebar/dist/style.css'或者在使用组件的文件中引入:
<style>
@import 'ai-chat-sidebar/dist/style.css';
</style>🎮 在线演示
体验重新设计的聊天组件:
# 运行组件设计演示
npm run example:chat-component演示包含:
- 开箱即用组件
- 组合式函数使用
- 自定义UI组件
- 服务层直接使用
🚀 使用方式
方式1: 开箱即用 (推荐)
最简单的使用方式,适合快速集成:
<template>
<AIChat
:config="chatConfig"
:trigger-size="60"
/>
</template>
<script setup>
import AIChat from 'ai-chat-sidebar'
import 'ai-chat-sidebar/dist/style.css'
const chatConfig = {
title: '智能助手',
placeholder: '请输入您的问题...',
assistantName: 'AI',
assistantAvatar: '@/assets/avatar.svg' // 支持静态资源路径
}
</script>重要说明:
- 点击头像图标时会自动连接到测试服务器
- 确保 Element Plus 已正确安装和配置
- 样式文件必须引入才能正常显示
- 导入时使用
import AIChat from 'ai-chat-sidebar',不要使用子路径导入 - 如需连接到其他服务器,可通过
:default-server-id属性指定 - HTTPS 支持:在 HTTPS 页面中会自动使用 WSS 连接,HTTP 页面使用 WS 连接
高级配置示例
<template>
<AIChat
:config="chatConfig"
:default-server-id="'local'"
:trigger-size="60"
/>
</template>
<script setup>
import AIChat from 'ai-chat-sidebar'
import 'ai-chat-sidebar/dist/style.css'
const chatConfig = {
title: '智能助手',
placeholder: '请输入您的问题...',
assistantName: 'AI',
assistantAvatar: '@/assets/avatar.svg',
// 其他配置...
}
</script>方式2: 使用组合式函数
适合需要更多控制权的场景:
<template>
<ChatSidebar
:messages="messages"
:loading="loading"
:is-connected="isConnected"
:is-open="isOpen"
:width="500"
:theme="'light'"
@send="sendMessage"
@close="close"
/>
</template>
<script setup>
import { useChat } from 'ai-chat-sidebar/composables/useChat'
import ChatSidebar from 'ai-chat-sidebar/components/ChatSidebar.vue'
const {
messages,
loading,
isConnected,
isOpen,
sendMessage,
close,
open
} = useChat({
autoConnect: true,
defaultServerId: 'test',
config: {
title: '我的AI助手',
placeholder: '请输入您的问题...'
}
})
// 打开聊天
const openChat = () => {
open()
}
</script>方式3: 自定义UI
适合需要完全自定义界面的场景:
<template>
<div class="my-chat-container">
<ChatBox
:messages="messages"
:config="chatConfig"
:loading="loading"
:is-connected="isConnected"
:theme="'dark'"
@send="sendMessage"
/>
</div>
</template>
<script setup>
import { useChat } from 'ai-chat-sidebar/composables/useChat'
import ChatBox from 'ai-chat-sidebar/components/ChatBox.vue'
const { messages, loading, isConnected, sendMessage } = useChat({
config: {
title: '自定义聊天',
assistantName: 'AI助手',
showTimestamp: true
}
})
</script>
<style>
.my-chat-container {
width: 100%;
height: 600px;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
</style>方式4: 直接使用服务层
适合需要完全控制业务逻辑的场景:
<template>
<div>
<div v-for="message in messages" :key="message.id">
{{ message.message }}
</div>
<input v-model="inputMessage" @keyup.enter="sendMessage" />
</div>
</template>
<script setup>
import { ChatService } from 'ai-chat-sidebar/services/ChatService'
import { ref, onMounted } from 'vue'
const chatService = new ChatService({
config: {
title: '服务层聊天'
}
})
const messages = chatService.messages
const loading = chatService.loading
const isConnected = chatService.isConnected
const inputMessage = ref('')
const sendMessage = async () => {
if (inputMessage.value.trim()) {
await chatService.sendMessage(inputMessage.value)
inputMessage.value = ''
}
}
onMounted(async () => {
await chatService.connect('test')
})
</script>🚀 快速开始
基础使用 (旧版API,向后兼容)
<template>
<div>
<button @click="openChat">打开 AI 助手</button>
<AIChatSidebar
:is-open="isChatOpen"
:messages="messages"
:loading="loading"
:config="chatConfig"
@open="handleOpen"
@close="handleClose"
@send="handleSend"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { AIChatSidebar } from 'ai-chat-sidebar'
import type { Message, ChatConfig } from 'ai-chat-sidebar'
const isChatOpen = ref(false)
const loading = ref(false)
const messages = ref<Message[]>([])
const chatConfig: ChatConfig = {
title: 'AI 助手',
placeholder: '请输入您的问题...',
showTimestamp: true,
assistantName: 'AI',
assistantAvatar: 'https://example.com/ai-avatar.png',
userAvatar: 'https://example.com/user-avatar.png'
}
const openChat = () => {
isChatOpen.value = true
}
const handleOpen = () => {
console.log('聊天窗口已打开')
}
const handleClose = () => {
isChatOpen.value = false
}
const handleSend = async (message: string) => {
// 添加用户消息
messages.value.push({
id: Date.now().toString(),
content: message,
type: 'user',
timestamp: new Date(),
status: 'sent'
})
// 模拟 AI 响应
loading.value = true
setTimeout(() => {
messages.value.push({
id: (Date.now() + 1).toString(),
content: `我收到了您的消息:"${message}"`,
type: 'assistant',
timestamp: new Date(),
status: 'sent'
})
loading.value = false
}, 1000)
}
</script>与 LangGraph 集成
<template>
<div>
<button @click="openChat">打开 AI 助手</button>
<AIChatSidebar
:is-open="isChatOpen"
:messages="chatStore.messages"
:loading="chatStore.loading"
:config="chatConfig"
@open="handleOpen"
@close="handleClose"
@send="handleSend"
/>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { AIChatSidebar, useChatStore } from 'ai-chat-sidebar'
import type { ChatConfig, LangGraphConfig } from 'ai-chat-sidebar'
const isChatOpen = ref(false)
const chatStore = useChatStore()
const chatConfig: ChatConfig = {
title: 'LangGraph AI 助手',
placeholder: '请输入您的问题...',
showTimestamp: true
}
// LangGraph 配置
const langGraphConfig: LangGraphConfig = {
baseUrl: 'ws://localhost:8000/ws',
apiKey: 'your-api-key',
timeout: 30000
}
onMounted(async () => {
// 连接到 LangGraph 服务
await chatStore.connect()
})
const openChat = () => {
isChatOpen.value = true
}
const handleOpen = () => {
console.log('聊天窗口已打开')
}
const handleClose = () => {
isChatOpen.value = false
}
const handleSend = async (message: string) => {
// 使用 store 发送消息,会自动处理 LangGraph 通信
await chatStore.sendMessage(message)
}
</script>丰富组件支持
组件支持多种丰富的内容类型,包括代码块、表格、图表、文档等:
<template>
<AIChatSidebar
:is-open="true"
:messages="messages"
:config="chatConfig"
@send="handleSend"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { AIChatSidebar } from 'ai-chat-sidebar'
import type { Message } from 'ai-chat-sidebar'
const messages = ref<Message[]>([
// 代码块消息
{
id: '1',
content: 'console.log("Hello World")',
type: 'assistant',
messageType: 'code',
metadata: {
language: 'javascript',
fileName: 'example.js'
},
timestamp: new Date(),
status: 'sent'
},
// 表格消息
{
id: '2',
content: '这是销售数据表格:',
type: 'assistant',
messageType: 'table',
metadata: {
data: [
{ name: '产品A', sales: 1200, growth: '+15%' },
{ name: '产品B', sales: 980, growth: '+8%' }
],
columns: [
{ prop: 'name', label: '产品名称', width: 120 },
{ prop: 'sales', label: '销售额', width: 100 },
{ prop: 'growth', label: '增长率', width: 100 }
]
},
timestamp: new Date(),
status: 'sent'
},
// 图表消息
{
id: '3',
content: '这是销售趋势图表:',
type: 'assistant',
messageType: 'chart',
metadata: {
chartType: 'line',
chartData: {
categories: ['1月', '2月', '3月'],
values: [1200, 1350, 1100]
}
},
timestamp: new Date(),
status: 'sent'
}
])
const handleSend = (message: string) => {
// 处理消息发送
console.log('发送消息:', message)
}
</script>📚 API 文档
AIChatSidebar Props
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| isOpen | boolean | false | 是否显示侧边栏 |
| messages | Message[] | [] | 消息列表 |
| loading | boolean | false | 是否正在加载 |
| disabled | boolean | false | 是否禁用输入 |
| config | ChatConfig | {} | 聊天配置 |
| position | 'left' \| 'right' | 'right' | 侧边栏位置 |
| width | string \| number | '400px' | 侧边栏宽度 |
| theme | 'light' \| 'dark' | 'light' | 主题 |
ChatConfig
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| title | string | 'AI 助手' | 聊天窗口标题 |
| placeholder | string | '请输入消息...' | 输入框占位符 |
| maxLength | number | 1000 | 最大输入长度 |
| autoFocus | boolean | true | 是否自动聚焦 |
| showTimestamp | boolean | false | 是否显示时间戳 |
| assistantName | string | 'AI' | 助手名称 |
| assistantAvatar | string | - | 助手头像 |
| userAvatar | string | - | 用户头像 |
Events
| 事件名 | 参数 | 说明 |
|--------|------|------|
| open | - | 侧边栏打开时触发 |
| close | - | 侧边栏关闭时触发 |
| send | message: string | 发送消息时触发 |
| typing | isTyping: boolean | 输入状态变化时触发 |
| minimize | minimized: boolean | 最小化状态变化时触发 |
Store API
const chatStore = useChatStore()
// 状态
chatStore.messages // 消息列表
chatStore.loading // 加载状态
chatStore.isConnected // 连接状态
chatStore.error // 错误信息
// 方法
await chatStore.sendMessage(message) // 发送消息
await chatStore.connect() // 连接服务
await chatStore.disconnect() // 断开连接
chatStore.clearMessages() // 清空消息
chatStore.retryLastMessage() // 重试最后一条消息🎨 自定义样式
组件支持通过 CSS 变量进行主题定制:
.ai-chat-sidebar {
--sidebar-bg: #ffffff;
--sidebar-border: #e4e7ed;
--message-bg: #ffffff;
--message-user-bg: #409eff;
--message-text-color: #303133;
--message-user-text-color: #ffffff;
--input-bg: #ffffff;
--input-border: #dcdfe6;
--input-focus-border: #409eff;
}🌐 远程服务器连接
服务器管理组件
<template>
<div>
<!-- 服务器管理 -->
<ServerManager />
<!-- 聊天组件 -->
<AIChatSidebar
:visible="showChat"
@close="showChat = false"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { AIChatSidebar, ServerManager } from 'ai-chat-sidebar'
import 'ai-chat-sidebar/dist/style.css'
const showChat = ref(false)
</script>编程式管理
import { remoteConfigManager, langGraphService } from 'ai-chat-sidebar'
// 添加远程服务器
remoteConfigManager.addServer('production', {
name: '生产服务器',
host: 'api.example.com',
port: 443,
protocol: 'wss',
path: '/langgraph/ws',
apiKey: 'your-api-key',
timeout: 180000,
retryAttempts: 3,
description: '生产环境的 LangGraph 服务'
})
// 切换到远程服务器
await langGraphService.switchServer('production')
// 检查连接状态
const status = await langGraphService.checkServerStatus()
console.log('连接状态:', status)服务器配置选项
interface RemoteServerConfig {
name: string // 服务器名称
host: string // 主机地址
port: number // 端口号
protocol: 'ws' | 'wss' // 协议类型
path?: string // WebSocket 路径
apiKey?: string // API 密钥
timeout?: number // 超时时间(ms)
retryAttempts?: number // 重试次数
description?: string // 服务器描述
}演示页面
运行示例项目:
npm run example这个演示页面展示如何:
- 配置你的 LangGraph 服务连接
- 连接到已部署的服务
- 测试连接状态
- 开始聊天对话
- 管理多个服务器配置
🔧 开发
# 安装依赖
npm install
# 开发模式
npm run dev
# 运行示例
npm run example
# 构建
npm run build
# 类型检查
npm run type-check
# 代码检查
npm run lint📚 组件API参考
AIChat 组件
开箱即用的聊天组件,提供完整的聊天功能。
Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| autoConnect | boolean | false | 是否自动连接 |
| defaultServerId | string | - | 默认服务器ID |
| triggerText | string | '开始对话' | 触发器文本 |
| triggerType | string | 'primary' | 触发器类型 |
| triggerSize | string | 'default' | 触发器大小 |
| position | 'left' \| 'right' | 'right' | 侧边栏位置 |
| width | string \| number | '400px' | 侧边栏宽度 |
| theme | 'light' \| 'dark' | 'light' | 主题 |
| config | ChatConfig | {} | 聊天配置 |
Events
| 事件 | 参数 | 说明 |
|------|------|------|
| send | message: string | 发送消息 |
| open | - | 打开聊天 |
| close | - | 关闭聊天 |
| minimize | minimized: boolean | 最小化状态变化 |
| focus | - | 输入框聚焦 |
| blur | - | 输入框失焦 |
| connect | serverId: string | 连接服务器 |
| disconnect | - | 断开连接 |
| error | error: string | 错误事件 |
ChatBox 组件
纯UI聊天框组件,需要外部管理状态。
Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| messages | Message[] | [] | 消息列表 |
| config | ChatConfig | {} | 聊天配置 |
| loading | boolean | false | 加载状态 |
| disabled | boolean | false | 禁用状态 |
| minimized | boolean | false | 最小化状态 |
| showMinimize | boolean | true | 显示最小化按钮 |
| showClose | boolean | true | 显示关闭按钮 |
| theme | 'light' \| 'dark' | 'light' | 主题 |
| isConnected | boolean | false | 连接状态 |
Events
| 事件 | 参数 | 说明 |
|------|------|------|
| send | message: string | 发送消息 |
| minimize | minimized: boolean | 最小化状态变化 |
| close | - | 关闭聊天 |
| focus | - | 输入框聚焦 |
| blur | - | 输入框失焦 |
useChat 组合式函数
提供响应式聊天状态管理的组合式函数。
参数
interface UseChatOptions {
autoConnect?: boolean
defaultServerId?: string
showConnectionStatus?: boolean
config?: ChatConfig
serverId?: string
}返回值
| 属性 | 类型 | 说明 |
|------|------|------|
| isOpen | Ref<boolean> | 是否打开 |
| minimized | Ref<boolean> | 是否最小化 |
| messages | ComputedRef<Message[]> | 消息列表 |
| loading | ComputedRef<boolean> | 加载状态 |
| isConnected | ComputedRef<boolean> | 连接状态 |
| error | ComputedRef<string \| null> | 错误信息 |
| config | ComputedRef<ChatConfig> | 聊天配置 |
| open | () => void | 打开聊天 |
| close | () => void | 关闭聊天 |
| minimize | (value?: boolean) => void | 最小化 |
| connect | (serverId?: string) => Promise<void> | 连接服务器 |
| disconnect | () => Promise<void> | 断开连接 |
| switchServer | (serverId: string) => Promise<void> | 切换服务器 |
| sendMessage | (message: string) => Promise<void> | 发送消息 |
| clearMessages | () => void | 清空消息 |
| retryLastMessage | () => void | 重试最后一条消息 |
| updateConfig | (config: Partial<ChatConfig>) => void | 更新配置 |
ChatService 服务类
独立的聊天服务类,提供完整的聊天业务逻辑。
构造函数
new ChatService(options?: ChatServiceOptions)主要方法
| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| connect | serverId?: string | Promise<void> | 连接服务器 |
| disconnect | - | Promise<void> | 断开连接 |
| switchServer | serverId: string | Promise<void> | 切换服务器 |
| sendMessage | message: string | Promise<void> | 发送消息 |
| addMessage | message: Omit<Message, 'id' \| 'timestamp'> | Message | 添加消息 |
| updateMessage | id: string, updates: Partial<Message> | void | 更新消息 |
| removeMessage | id: string | void | 移除消息 |
| clearMessages | - | void | 清空消息 |
| retryLastMessage | - | void | 重试最后一条消息 |
| updateConfig | config: Partial<ChatConfig> | void | 更新配置 |
| destroy | - | void | 销毁服务 |
🎯 最佳实践
1. 选择合适的组件
- AIChat: 适合快速集成,需要完整聊天功能
- ChatSidebar + useChat: 适合需要自定义布局的场景
- ChatBox + useChat: 适合需要完全自定义UI的场景
- ChatService: 适合需要完全控制业务逻辑的场景
2. 状态管理
- 使用
useChat组合式函数管理状态 - 避免直接操作
ChatService实例 - 通过事件监听器处理状态变化
3. 性能优化
- 使用
v-memo优化消息列表渲染 - 合理使用防抖更新避免频繁重渲染
- 及时清理不需要的监听器
4. 错误处理
- 监听
error事件处理错误 - 提供用户友好的错误提示
- 实现重试机制
5. 主题定制
- 使用 CSS 变量自定义主题
- 支持深色/浅色模式切换
- 保持与项目整体风格一致
📄 许可证
MIT License
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📞 支持
如有问题,请通过以下方式联系:
- GitHub Issues: 提交问题
- Email: [email protected]
