ibc-ai-web-sdk 2.0.2 → 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +347 -493
- package/dist/index.cjs.js +952 -329
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +952 -329
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +952 -329
- package/dist/index.umd.js.map +1 -1
- package/dist/index.umd.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,607 +1,461 @@
|
|
|
1
|
-
# IBC AI Web SDK v2
|
|
1
|
+
# IBC AI Web SDK v2
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> 纯 JavaScript 实现的 AI 智能体对话组件,基于 Web Components,支持任意前端框架。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 快速开始
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- 🔌 **框架无关** - 可在Vue/React/Angular/Svelte/原生HTML中无缝使用
|
|
9
|
-
- 🎨 **主题可定制** - 支持亮色/暗色主题,CSS变量自定义
|
|
10
|
-
- 💬 **流式响应** - 支持SSE流式输出,实时显示AI回复
|
|
11
|
-
- 📱 **响应式设计** - 适配桌面端和移动端
|
|
12
|
-
- ♿ **无障碍访问** - 遵循ARIA规范,支持键盘操作
|
|
13
|
-
- 🎯 **轻量级** - Gzip后 < 15KB
|
|
7
|
+
### CDN 引入(最简单)
|
|
14
8
|
|
|
15
|
-
|
|
9
|
+
```html
|
|
10
|
+
<script src="https://unpkg.com/ibc-ai-web-sdk@2/dist/index.umd.min.js"></script>
|
|
11
|
+
<script>
|
|
12
|
+
const dialog = AIWebSDK.create({
|
|
13
|
+
apiEndpoint: '/v1/app/completion',
|
|
14
|
+
appId: 'your-app-id',
|
|
15
|
+
userId: 'user-123',
|
|
16
|
+
bizType: 'chat',
|
|
17
|
+
token: 'your-auth-token'
|
|
18
|
+
});
|
|
19
|
+
dialog.open();
|
|
20
|
+
</script>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### npm 安装
|
|
16
24
|
|
|
17
25
|
```bash
|
|
18
26
|
npm install ibc-ai-web-sdk
|
|
19
27
|
```
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
```js
|
|
30
|
+
import { createAIChatDialog } from 'ibc-ai-web-sdk';
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
const dialog = createAIChatDialog({
|
|
33
|
+
apiEndpoint: '/v1/app/completion',
|
|
34
|
+
appId: 'your-app-id',
|
|
35
|
+
userId: 'user-123',
|
|
36
|
+
bizType: 'chat',
|
|
37
|
+
token: 'your-auth-token'
|
|
38
|
+
});
|
|
39
|
+
dialog.open();
|
|
25
40
|
```
|
|
26
41
|
|
|
27
|
-
|
|
42
|
+
### 内嵌模式(作为页面组件嵌入)
|
|
28
43
|
|
|
29
|
-
|
|
44
|
+
指定 `target` 即可将对话组件嵌入到页面的某个容器内,而非浮窗形式:
|
|
30
45
|
|
|
31
46
|
```html
|
|
32
|
-
|
|
33
|
-
<html>
|
|
34
|
-
<head>
|
|
35
|
-
<title>AI Chat Demo</title>
|
|
36
|
-
</head>
|
|
37
|
-
<body>
|
|
38
|
-
<!-- 触发按钮 -->
|
|
39
|
-
<button onclick="openChat()">打开AI助手</button>
|
|
40
|
-
|
|
41
|
-
<script type="module">
|
|
42
|
-
import { createAIChatDialog } from './node_modules/ibc-ai-web-sdk/dist/index.esm.js';
|
|
43
|
-
|
|
44
|
-
// 或CDN方式:
|
|
45
|
-
// const dialog = AICreateChatDialog({...});
|
|
46
|
-
|
|
47
|
-
let chatInstance;
|
|
48
|
-
|
|
49
|
-
function openChat() {
|
|
50
|
-
if (!chatInstance) {
|
|
51
|
-
chatInstance = createAIChatDialog({
|
|
52
|
-
apiBaseUrl: 'https://your-api.com/ai',
|
|
53
|
-
authToken: 'your-token',
|
|
54
|
-
title: '智能客服',
|
|
55
|
-
placeholder: '请输入您的问题...',
|
|
56
|
-
theme: 'light'
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
chatInstance.open();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// 暴露到全局供onclick调用
|
|
64
|
-
window.openChat = openChat;
|
|
65
|
-
</script>
|
|
66
|
-
</body>
|
|
67
|
-
</html>
|
|
47
|
+
<div id="chat-box" style="width:480px;height:680px"></div>
|
|
68
48
|
```
|
|
69
49
|
|
|
70
|
-
|
|
50
|
+
```js
|
|
51
|
+
AIWebSDK.create({
|
|
52
|
+
target: '#chat-box', // 挂载容器
|
|
53
|
+
apiEndpoint: '/v1/app/completion',
|
|
54
|
+
appId: 'your-app-id',
|
|
55
|
+
userId: 'user-123',
|
|
56
|
+
bizType: 'chat',
|
|
57
|
+
token: 'your-auth-token'
|
|
58
|
+
});
|
|
59
|
+
// 内嵌模式自动展开,无需调用 open()
|
|
60
|
+
```
|
|
71
61
|
|
|
72
|
-
|
|
62
|
+
> **npm 用户**:将 `AIWebSDK.create()` 替换为 `createAIChatDialog()` 即可。
|
|
73
63
|
|
|
74
|
-
|
|
75
|
-
<template>
|
|
76
|
-
<div>
|
|
77
|
-
<button @click="openChat">打开AI助手</button>
|
|
78
|
-
|
|
79
|
-
<!-- 使用组件包装器 -->
|
|
80
|
-
<AiChatWrapper
|
|
81
|
-
:visible.sync="showChat"
|
|
82
|
-
:config="chatConfig"
|
|
83
|
-
@message-send="onMessageSend"
|
|
84
|
-
@message-received="onMessageReceived"
|
|
85
|
-
@close="showChat = false"
|
|
86
|
-
/>
|
|
87
|
-
</div>
|
|
88
|
-
</template>
|
|
64
|
+
---
|
|
89
65
|
|
|
90
|
-
|
|
91
|
-
|
|
66
|
+
## 配置选项
|
|
67
|
+
|
|
68
|
+
| 参数 | 类型 | 默认值 | 必填 | 说明 |
|
|
69
|
+
|------|------|--------|------|------|
|
|
70
|
+
| `apiEndpoint` | string | `/v1/app/completion` | 是 | 对话接口地址 |
|
|
71
|
+
| `apiBaseUrl` | string | `''` | | API 基础地址,拼接到各 endpoint 前 |
|
|
72
|
+
| `appId` | string | `''` | 是 | 智能体应用 ID |
|
|
73
|
+
| `userId` | string | `''` | 是 | 用户标识 |
|
|
74
|
+
| `bizType` | string | `''` | 是 | 业务类型标识 |
|
|
75
|
+
| `token` | string | `''` | | 认证 Token,自动添加到 Authorization 头 |
|
|
76
|
+
| `title` | string | `'AI 助手'` | | 对话框标题(loadAppDetail 会自动覆盖) |
|
|
77
|
+
| `welcomeText` | string | `'Hi,我是智能助手 ~'` | | 欢迎语 |
|
|
78
|
+
| `welcomeDesc` | string | `'全新自动化能力上线...'` | | 欢迎描述 |
|
|
79
|
+
| `theme` | string\|object | `'default'` | | 主题,见下方[主题定制](#主题定制) |
|
|
80
|
+
| `suggestions` | array | 内置默认建议 | | 欢迎页建议列表 `[{ label, value }]` |
|
|
81
|
+
| `timeout` | number | `60000` | | 请求超时(毫秒) |
|
|
82
|
+
| `maxLength` | number | `500` | | 输入最大字符数 |
|
|
83
|
+
| `enableDrag` | boolean | `true` | | 是否允许拖拽对话框 |
|
|
84
|
+
| `headers` | object | `{}` | | 附加请求头 |
|
|
85
|
+
| `extendInfo` | object | `{}` | | 随请求发送的扩展信息 |
|
|
86
|
+
|
|
87
|
+
### Token 刷新
|
|
92
88
|
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
提供 `refreshTokenFn` 即可,SDK 会自动处理过期检测和刷新。
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
createAIChatDialog({
|
|
93
|
+
token: 'initial-access-token',
|
|
94
|
+
tokenExpiresAt: Date.now() + 30 * 60 * 1000, // Token 过期时间戳
|
|
95
|
+
refreshToken: 'initial-refresh-token', // 可选
|
|
96
|
+
|
|
97
|
+
refreshTokenFn: async ({ token, refreshToken, userId }) => {
|
|
98
|
+
const res = await fetch('/api/auth/refresh', {
|
|
99
|
+
method: 'POST',
|
|
100
|
+
headers: { 'Content-Type': 'application/json' },
|
|
101
|
+
body: JSON.stringify({ token, refreshToken, userId })
|
|
102
|
+
});
|
|
103
|
+
const data = await res.json();
|
|
95
104
|
return {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
apiBaseUrl: '/api/ai',
|
|
99
|
-
authToken: '',
|
|
100
|
-
title: 'AI 助手',
|
|
101
|
-
welcomeMessage: '你好!我是AI助手,有什么可以帮助您的吗?'
|
|
102
|
-
}
|
|
105
|
+
token: data.accessToken,
|
|
106
|
+
expiresAt: data.expiresAt * 1000
|
|
103
107
|
};
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
mounted() {
|
|
107
|
-
// 注册Vue插件
|
|
108
|
-
installVuePlugin(this.$root.constructor); // Vue 2
|
|
109
|
-
// 或在 main.js 中全局注册:
|
|
110
|
-
// import { installVuePlugin } from 'ibc-ai-web-sdk';
|
|
111
|
-
// Vue.use(installVuePlugin);
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
methods: {
|
|
115
|
-
openChat() {
|
|
116
|
-
this.showChat = true;
|
|
117
|
-
},
|
|
118
|
-
|
|
119
|
-
onMessageSend(message) {
|
|
120
|
-
console.log('用户发送:', message.content);
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
onMessageReceived(message) {
|
|
124
|
-
console.log('AI回复:', message.content);
|
|
125
|
-
}
|
|
126
108
|
}
|
|
127
|
-
};
|
|
128
|
-
</script>
|
|
109
|
+
});
|
|
129
110
|
```
|
|
130
111
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
112
|
+
| 参数 | 类型 | 说明 |
|
|
113
|
+
|------|------|------|
|
|
114
|
+
| `token` | string | 认证 Token |
|
|
115
|
+
| `tokenExpiresAt` | number | Token 过期时间戳(毫秒) |
|
|
116
|
+
| `refreshToken` | string | refresh token |
|
|
117
|
+
| `refreshTokenFn` | function | 刷新函数,返回新 token 信息 |
|
|
118
|
+
| `onTokenRefreshed` | function | 刷新成功回调 |
|
|
119
|
+
| `onTokenExpired` | function | 刷新失败回调 |
|
|
120
|
+
```
|
|
139
121
|
|
|
140
|
-
|
|
141
|
-
import { ref, onMounted, onUnmounted } from 'vue';
|
|
142
|
-
import { createAIChatDialog } from 'ibc-ai-web-sdk';
|
|
122
|
+
### 高级配置
|
|
143
123
|
|
|
144
|
-
|
|
124
|
+
```js
|
|
125
|
+
createAIChatDialog({
|
|
126
|
+
// 各端点自定义
|
|
127
|
+
streamEndpoint: '/v1/app/completion/stream',
|
|
128
|
+
stopEndpoint: '/v1/app/completion/stop',
|
|
129
|
+
conversationQueryEndpoint: '/v1/app/conversation/query',
|
|
130
|
+
conversationDeleteEndpoint: '/v1/app/conversation/delete',
|
|
131
|
+
|
|
132
|
+
// 鉴权函数(可选)
|
|
133
|
+
authFn: async (token, userId) => {
|
|
134
|
+
// throw 或 reject 表示拒绝访问
|
|
135
|
+
},
|
|
145
136
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
title: '智能助手',
|
|
150
|
-
theme: 'dark',
|
|
151
|
-
width: 500,
|
|
152
|
-
height: 650,
|
|
153
|
-
|
|
154
|
-
// 回调事件
|
|
155
|
-
onMessageSend: (msg) => console.log('发送:', msg),
|
|
156
|
-
onMessageReceived: (msg) => console.log('收到:', msg),
|
|
157
|
-
onError: (err) => console.error('错误:', err)
|
|
158
|
-
});
|
|
159
|
-
});
|
|
137
|
+
// 页脚信息
|
|
138
|
+
footerIdentity: 'UIN:123456',
|
|
139
|
+
footerDisclaimer: '推荐和回答由 AI 生成,仅供参考',
|
|
160
140
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
141
|
+
// 历史
|
|
142
|
+
historyDays: 30,
|
|
143
|
+
historyPageSize: 20,
|
|
164
144
|
|
|
165
|
-
|
|
166
|
-
|
|
145
|
+
// 移动端
|
|
146
|
+
mobileMode: true // undefined = 自动检测
|
|
167
147
|
});
|
|
168
|
-
</script>
|
|
169
148
|
```
|
|
170
149
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
#### 使用Hook(推荐)
|
|
174
|
-
|
|
175
|
-
```jsx
|
|
176
|
-
import React from 'react';
|
|
177
|
-
import { useAIChat } from 'ibc-ai-web-sdk';
|
|
150
|
+
---
|
|
178
151
|
|
|
179
|
-
|
|
180
|
-
const { open, close, messages, isLoading } = useAIChat({
|
|
181
|
-
apiBaseUrl: process.env.REACT_APP_AI_API_URL,
|
|
182
|
-
authToken: localStorage.getItem('token'),
|
|
183
|
-
title: 'AI 智能助手',
|
|
184
|
-
placeholder: '输入您的问题...',
|
|
185
|
-
theme: 'light',
|
|
186
|
-
|
|
187
|
-
// 回调
|
|
188
|
-
onMessageSend: (message) => {
|
|
189
|
-
console.log('用户发送:', message);
|
|
190
|
-
},
|
|
191
|
-
|
|
192
|
-
onMessageReceived: ({ content }) => {
|
|
193
|
-
console.log('AI回复:', content);
|
|
194
|
-
},
|
|
195
|
-
|
|
196
|
-
onError: (error) => {
|
|
197
|
-
console.error('发生错误:', error);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
152
|
+
## 实例方法
|
|
200
153
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
<h1>My App</h1>
|
|
204
|
-
|
|
205
|
-
<button onClick={open}>
|
|
206
|
-
{isLoading ? '对话中...' : '打开AI助手'}
|
|
207
|
-
</button>
|
|
208
|
-
|
|
209
|
-
{/* 显示消息历史 */}
|
|
210
|
-
<div className="message-history">
|
|
211
|
-
{messages.map((msg) => (
|
|
212
|
-
<div key={msg.id} className={`message ${msg.role}`}>
|
|
213
|
-
<strong>{msg.role === 'user' ? '我' : 'AI'}:</strong>
|
|
214
|
-
{msg.content}
|
|
215
|
-
</div>
|
|
216
|
-
))}
|
|
217
|
-
</div>
|
|
218
|
-
|
|
219
|
-
<button onClick={close}>关闭</button>
|
|
220
|
-
</div>
|
|
221
|
-
);
|
|
222
|
-
}
|
|
154
|
+
```js
|
|
155
|
+
const dialog = createAIChatDialog(config);
|
|
223
156
|
|
|
224
|
-
|
|
157
|
+
dialog.open(); // 打开对话框
|
|
158
|
+
dialog.close(); // 关闭对话框
|
|
159
|
+
dialog.toggle(); // 切换显示/隐藏
|
|
160
|
+
dialog.destroy(); // 销毁实例
|
|
161
|
+
dialog.updateConfig({ // 动态更新配置
|
|
162
|
+
title: '新标题',
|
|
163
|
+
token: 'new-token'
|
|
164
|
+
});
|
|
165
|
+
dialog.clearChat(); // 清空对话,开始新会话
|
|
166
|
+
dialog.stopGeneration(); // 停止当前 AI 生成
|
|
225
167
|
```
|
|
226
168
|
|
|
227
|
-
|
|
169
|
+
---
|
|
228
170
|
|
|
229
|
-
|
|
230
|
-
import React, { Component } from 'react';
|
|
231
|
-
import { createAIChatDialog } from 'ibc-ai-web-sdk';
|
|
171
|
+
## 事件与回调
|
|
232
172
|
|
|
233
|
-
|
|
234
|
-
constructor(props) {
|
|
235
|
-
super(props);
|
|
236
|
-
this.chatRef = null;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
componentDidMount() {
|
|
240
|
-
this.chatRef = createAIChatDialog({
|
|
241
|
-
apiBaseUrl: '/api/ai',
|
|
242
|
-
title: 'AI 助手',
|
|
243
|
-
|
|
244
|
-
onMessageSend: (msg) => {
|
|
245
|
-
console.log('发送:', msg);
|
|
246
|
-
},
|
|
247
|
-
|
|
248
|
-
onMessageReceived: (data) => {
|
|
249
|
-
console.log('收到:', data);
|
|
250
|
-
this.props.onReceive?.(data);
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
componentWillUnmount() {
|
|
256
|
-
if (this.chatRef) {
|
|
257
|
-
this.chatRef.destroy();
|
|
258
|
-
}
|
|
259
|
-
}
|
|
173
|
+
支持两种方式监听,效果一样:
|
|
260
174
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
175
|
+
**方式一:回调函数**
|
|
176
|
+
```js
|
|
177
|
+
createAIChatDialog({
|
|
178
|
+
onOpen: () => console.log('对话框打开'),
|
|
179
|
+
onClose: () => console.log('对话框关闭'),
|
|
180
|
+
onLoad: (client) => console.log('SDK 初始化完成'),
|
|
181
|
+
onMessageSend: (msg) => console.log('用户发送:', msg),
|
|
182
|
+
onMessageReceived: (data) => console.log('AI 回复:', data),
|
|
183
|
+
onError: (err) => console.error('错误:', err)
|
|
184
|
+
});
|
|
185
|
+
```
|
|
275
186
|
|
|
276
|
-
|
|
187
|
+
**方式二:事件监听**
|
|
188
|
+
```js
|
|
189
|
+
dialog.addEventListener('open', () => {});
|
|
190
|
+
dialog.addEventListener('close', () => {});
|
|
191
|
+
dialog.addEventListener('init', (e) => { console.log(e.detail.config); });
|
|
192
|
+
dialog.addEventListener('message-send', (e) => { console.log(e.detail); });
|
|
193
|
+
dialog.addEventListener('message-received', (e) => { console.log(e.detail); });
|
|
194
|
+
dialog.addEventListener('error', (e) => { console.error(e.detail); });
|
|
195
|
+
dialog.addEventListener('clear', () => {});
|
|
196
|
+
dialog.addEventListener('stop', () => {});
|
|
197
|
+
dialog.addEventListener('loading-change', (e) => { console.log(e.detail.loading); });
|
|
277
198
|
```
|
|
278
199
|
|
|
279
|
-
|
|
200
|
+
---
|
|
280
201
|
|
|
281
|
-
|
|
282
|
-
// ai-chat.service.ts
|
|
283
|
-
import { Injectable, OnDestroy } from '@angular/core';
|
|
284
|
-
import { createAIChatDialog, AIChatDialog } from 'ibc-ai-web-sdk';
|
|
202
|
+
## 主题定制
|
|
285
203
|
|
|
286
|
-
|
|
287
|
-
providedIn: 'root'
|
|
288
|
-
})
|
|
289
|
-
export class AiChatService implements OnDestroy {
|
|
290
|
-
private dialog: AIChatDialog | null = null;
|
|
204
|
+
### 预设主题(16 种)
|
|
291
205
|
|
|
292
|
-
|
|
206
|
+
直接传字符串名(不区分大小写):
|
|
293
207
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
}
|
|
208
|
+
```js
|
|
209
|
+
createAIChatDialog({ theme: 'dark' });
|
|
210
|
+
createAIChatDialog({ theme: 'ocean' });
|
|
211
|
+
createAIChatDialog({ theme: 'purple' });
|
|
212
|
+
```
|
|
302
213
|
|
|
303
|
-
|
|
304
|
-
this.init(); // 确保已初始化
|
|
305
|
-
this.dialog?.open();
|
|
306
|
-
}
|
|
214
|
+
全部预设:`default` `dark` `fresh` `vibrant` `romantic` `purple` `ocean` `twilight` `mint` `rose` `aurora` `lavender` `coral` `jade` `starsky` `sunset`
|
|
307
215
|
|
|
308
|
-
|
|
309
|
-
this.dialog?.close();
|
|
310
|
-
}
|
|
216
|
+
### 自定义主题
|
|
311
217
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
218
|
+
```js
|
|
219
|
+
createAIChatDialog({
|
|
220
|
+
theme: {
|
|
221
|
+
colors: {
|
|
222
|
+
primary: '#8b5cf6',
|
|
223
|
+
primaryLight: '#a78bfa',
|
|
224
|
+
primaryDark: '#7c3aed',
|
|
225
|
+
background: '#faf5ff',
|
|
226
|
+
text: '#1f2937',
|
|
227
|
+
textSecondary: '#6b7280',
|
|
228
|
+
userBubble: '#8b5cf6',
|
|
229
|
+
aiBubble: '#f3f4f6',
|
|
230
|
+
border: '#e5e7eb',
|
|
231
|
+
inputBackground: '#f9fafb',
|
|
232
|
+
inputBorder: '#d1d5db',
|
|
233
|
+
error: '#ef4444',
|
|
234
|
+
success: '#22c55e',
|
|
235
|
+
warning: '#f59e0b'
|
|
236
|
+
},
|
|
237
|
+
borderRadius: {
|
|
238
|
+
dialog: '16px',
|
|
239
|
+
bubble: '12px',
|
|
240
|
+
button: '50%',
|
|
241
|
+
input: '28px'
|
|
242
|
+
},
|
|
243
|
+
fontSize: {
|
|
244
|
+
title: '15px',
|
|
245
|
+
welcomeText: '17px',
|
|
246
|
+
message: '14px',
|
|
247
|
+
time: '11px'
|
|
320
248
|
}
|
|
321
249
|
}
|
|
322
|
-
|
|
323
|
-
ngOnDestroy(): void {
|
|
324
|
-
this.dialog?.destroy();
|
|
325
|
-
}
|
|
326
|
-
}
|
|
250
|
+
});
|
|
327
251
|
```
|
|
328
252
|
|
|
329
|
-
|
|
330
|
-
// app.component.ts
|
|
331
|
-
import { Component } from '@angular/core';
|
|
332
|
-
import { AiChatService } from './ai-chat.service';
|
|
333
|
-
|
|
334
|
-
@Component({
|
|
335
|
-
selector: 'app-root',
|
|
336
|
-
template: `
|
|
337
|
-
<button (click)="openChat()">打开AI助手</button>
|
|
338
|
-
`
|
|
339
|
-
})
|
|
340
|
-
export class AppComponent {
|
|
341
|
-
constructor(private aiChat: AiChatService) {}
|
|
342
|
-
|
|
343
|
-
openChat(): void {
|
|
344
|
-
this.aiChat.open();
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
```
|
|
253
|
+
---
|
|
348
254
|
|
|
349
|
-
|
|
255
|
+
## 框架集成示例
|
|
350
256
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
chat = createAIChatDialog({
|
|
360
|
-
apiBaseUrl: '/api/ai',
|
|
361
|
-
title: 'Svelte AI Chat',
|
|
362
|
-
|
|
363
|
-
onMessageSend: (msg) => {
|
|
364
|
-
console.log('发送:', msg);
|
|
365
|
-
},
|
|
366
|
-
|
|
367
|
-
onMessageReceived: (data) => {
|
|
368
|
-
console.log('收到:', data);
|
|
369
|
-
}
|
|
370
|
-
});
|
|
371
|
-
});
|
|
257
|
+
### Vue 3 (Composition API)
|
|
258
|
+
|
|
259
|
+
```vue
|
|
260
|
+
<script setup>
|
|
261
|
+
import { ref, onMounted, onUnmounted } from 'vue';
|
|
262
|
+
import { createAIChatDialog } from 'ibc-ai-web-sdk';
|
|
263
|
+
|
|
264
|
+
const chat = ref(null);
|
|
372
265
|
|
|
373
|
-
|
|
374
|
-
|
|
266
|
+
onMounted(() => {
|
|
267
|
+
chat.value = createAIChatDialog({
|
|
268
|
+
apiEndpoint: '/v1/app/completion',
|
|
269
|
+
appId: 'your-app-id',
|
|
270
|
+
userId: 'user-123',
|
|
271
|
+
bizType: 'chat',
|
|
272
|
+
token: 'your-token',
|
|
273
|
+
theme: 'ocean',
|
|
274
|
+
onMessageSend: (msg) => console.log('发送:', msg),
|
|
275
|
+
onMessageReceived: (data) => console.log('收到:', data),
|
|
276
|
+
onError: (err) => console.error('错误:', err)
|
|
375
277
|
});
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
onUnmounted(() => chat.value?.destroy());
|
|
376
281
|
</script>
|
|
377
282
|
|
|
378
|
-
<
|
|
379
|
-
|
|
380
|
-
</
|
|
283
|
+
<template>
|
|
284
|
+
<button @click="chat?.open()">打开 AI 助手</button>
|
|
285
|
+
</template>
|
|
381
286
|
```
|
|
382
287
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
| 参数 | 类型 | 默认值 | 说明 |
|
|
386
|
-
|------|------|--------|------|
|
|
387
|
-
| `apiBaseUrl` | `string` | `'/api/ai'` | API基础URL |
|
|
388
|
-
| `authToken` | `string` | `''` | 认证Token |
|
|
389
|
-
| `defaultParams` | `Object` | `{}` | 默认请求参数 |
|
|
390
|
-
| `placeholder` | `string` | `'请输入您的问题...'` | 输入框占位符 |
|
|
391
|
-
| `title` | `string` | `'AI 智能助手'` | 对话框标题 |
|
|
392
|
-
| `width` | `number` | `420` | 对话框宽度(px) |
|
|
393
|
-
| `height` | `number` | `600` | 对话框高度(px) |
|
|
394
|
-
| `theme` | `string` | `'light'` | 主题:`light` / `dark` |
|
|
395
|
-
| `showDragHandle` | `boolean` | `true` | 是否允许拖拽头部移动位置 |
|
|
396
|
-
| `enableHistory` | `boolean` | `true` | 是否启用消息历史记录 |
|
|
397
|
-
| `maxHistoryLength` | `number` | `50` | 最大历史消息数量 |
|
|
398
|
-
| `welcomeMessage` | `string` | - | 欢迎语(空状态时显示) |
|
|
399
|
-
| `errorMessage` | `string` | - | 错误提示文案 |
|
|
400
|
-
| `networkErrorMessage` | `string` | - | 网络错误提示文案 |
|
|
401
|
-
| `emptyMessageError` | `string` | - | 空消息错误提示文案 |
|
|
402
|
-
| `streamingEnabled` | `boolean` | `true` | 是否启用流式响应(SSE) |
|
|
403
|
-
| `requestTimeout` | `number` | `30000` | 请求超时时间(ms) |
|
|
404
|
-
| `customStyles` | `Object` | `null` | 自定义CSS变量 |
|
|
405
|
-
|
|
406
|
-
### 回调函数
|
|
407
|
-
|
|
408
|
-
| 回调 | 参数 | 说明 |
|
|
409
|
-
|------|------|------|
|
|
410
|
-
| `onMessageSend` | `(message: Object)` | 用户发送消息时触发 |
|
|
411
|
-
| `onMessageReceived` | `(data: {content, done})` | 收到AI回复时触发(流式模式下多次触发) |
|
|
412
|
-
| `onError` | `(error: Error)` | 发生错误时触发 |
|
|
413
|
-
| `onOpen` | - | 对话框打开时触发 |
|
|
414
|
-
| `onClose` | - | 对话框关闭时触发 |
|
|
415
|
-
|
|
416
|
-
## 🎨 主题定制
|
|
288
|
+
### React
|
|
417
289
|
|
|
418
|
-
|
|
290
|
+
```jsx
|
|
291
|
+
import { useEffect, useRef } from 'react';
|
|
292
|
+
import { createAIChatDialog } from 'ibc-ai-web-sdk';
|
|
419
293
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
294
|
+
function App() {
|
|
295
|
+
const chatRef = useRef(null);
|
|
296
|
+
|
|
297
|
+
useEffect(() => {
|
|
298
|
+
chatRef.current = createAIChatDialog({
|
|
299
|
+
apiEndpoint: '/v1/app/completion',
|
|
300
|
+
appId: 'your-app-id',
|
|
301
|
+
userId: 'user-123',
|
|
302
|
+
bizType: 'chat',
|
|
303
|
+
token: 'your-token',
|
|
304
|
+
onMessageReceived: (data) => console.log('回复:', data)
|
|
305
|
+
});
|
|
306
|
+
return () => chatRef.current?.destroy();
|
|
307
|
+
}, []);
|
|
431
308
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
```css
|
|
435
|
-
:host {
|
|
436
|
-
--ai-primary-color: #2563eb; /* 主色调 */
|
|
437
|
-
--ai-primary-hover: #1d4ed8; /* 主色悬停态 */
|
|
438
|
-
--ai-bg-color: #ffffff; /* 背景色 */
|
|
439
|
-
--ai-text-color: #1f2937; /* 文字颜色 */
|
|
440
|
-
--ai-text-secondary: #6b7280; /* 次要文字颜色 */
|
|
441
|
-
--ai-border-color: #e5e7eb; /* 边框颜色 */
|
|
442
|
-
--ai-user-bg: gradient(...); /* 用户消息背景 */
|
|
443
|
-
--ai-assistant-bg: #f3f4f6; /* 助手消息背景 */
|
|
444
|
-
--ai-input-bg: #f9fafb; /* 输入框背景 */
|
|
445
|
-
--ai-shadow: shadow(...); /* 阴影效果 */
|
|
446
|
-
--ai-overlay: rgba(0,0,0,0.5); /* 遮罩层颜色 */
|
|
447
|
-
--ai-border-radius: 12px; /* 圆角大小 */
|
|
448
|
-
--ai-header-height: 56px; /* 头部高度 */
|
|
309
|
+
return <button onClick={() => chatRef.current?.open()}>打开 AI 助手</button>;
|
|
449
310
|
}
|
|
450
311
|
```
|
|
451
312
|
|
|
452
|
-
|
|
313
|
+
### 原生 HTML
|
|
453
314
|
|
|
454
|
-
```
|
|
455
|
-
|
|
456
|
-
const dialog = createAIChatDialog(config);
|
|
457
|
-
|
|
458
|
-
// 控制显示
|
|
459
|
-
dialog.open(); // 打开对话框
|
|
460
|
-
dialog.close(); // 关闭对话框
|
|
461
|
-
dialog.toggle(forceState?); // 切换状态
|
|
462
|
-
|
|
463
|
-
// 消息操作
|
|
464
|
-
dialog.addMessage(message); // 手动添加消息
|
|
465
|
-
dialog.clearMessages(); // 清空消息历史
|
|
466
|
-
dialog.sendMessage(text); // 发送消息(程序化调用)
|
|
315
|
+
```html
|
|
316
|
+
<button onclick="openChat()">打开 AI 助手</button>
|
|
467
317
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
dialog.
|
|
318
|
+
<script src="https://unpkg.com/ibc-ai-web-sdk@2/dist/index.umd.min.js"></script>
|
|
319
|
+
<script>
|
|
320
|
+
const dialog = AIWebSDK.create({
|
|
321
|
+
apiEndpoint: '/v1/app/completion',
|
|
322
|
+
appId: 'your-app-id',
|
|
323
|
+
userId: 'user-123',
|
|
324
|
+
bizType: 'chat',
|
|
325
|
+
token: 'your-token'
|
|
326
|
+
});
|
|
471
327
|
|
|
472
|
-
|
|
473
|
-
dialog.
|
|
328
|
+
function openChat() {
|
|
329
|
+
dialog.open();
|
|
330
|
+
}
|
|
331
|
+
</script>
|
|
474
332
|
```
|
|
475
333
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
```javascript
|
|
479
|
-
const dialog = createAIChatDialog();
|
|
480
|
-
|
|
481
|
-
// 使用addEventListener
|
|
482
|
-
dialog.addEventListener('open', () => console.log('打开'));
|
|
483
|
-
dialog.addEventListener('close', () => console.log('关闭'));
|
|
484
|
-
dialog.addEventListener('message-send', (e) => {
|
|
485
|
-
console.log('发送的消息:', e.detail);
|
|
486
|
-
});
|
|
487
|
-
dialog.addEventListener('message-received', (e) => {
|
|
488
|
-
console.log('收到的回复:', e.detail);
|
|
489
|
-
});
|
|
490
|
-
dialog.addEventListener('error', (e) => {
|
|
491
|
-
console.error('错误:', e.detail);
|
|
492
|
-
});
|
|
493
|
-
|
|
494
|
-
// 或在配置中使用回调
|
|
495
|
-
createAIChatDialog({
|
|
496
|
-
onOpen: () => {},
|
|
497
|
-
onClose: () => {},
|
|
498
|
-
onMessageSend: (msg) => {},
|
|
499
|
-
onMessageReceived: (data) => {},
|
|
500
|
-
onError: (err) => {}
|
|
501
|
-
});
|
|
502
|
-
```
|
|
334
|
+
---
|
|
503
335
|
|
|
504
|
-
##
|
|
336
|
+
## 服务端 API 规范
|
|
505
337
|
|
|
506
|
-
SDK
|
|
338
|
+
SDK 向后端发起以下请求,你需要实现对应的接口:
|
|
507
339
|
|
|
508
|
-
### POST `/
|
|
340
|
+
### 对话接口 `POST {apiEndpoint}`(默认 `/v1/app/completion`)
|
|
509
341
|
|
|
510
342
|
**请求体:**
|
|
511
343
|
```json
|
|
512
344
|
{
|
|
513
|
-
"
|
|
514
|
-
"
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
345
|
+
"appId": "your-app-id",
|
|
346
|
+
"prompt": "用户输入的消息",
|
|
347
|
+
"userId": "user-123",
|
|
348
|
+
"bizType": "chat",
|
|
349
|
+
"requestId": "req_1719000000000_abc123"
|
|
518
350
|
}
|
|
519
351
|
```
|
|
520
352
|
|
|
521
|
-
|
|
353
|
+
携带 `conversationId` 时会继续已有会话:
|
|
522
354
|
```json
|
|
523
355
|
{
|
|
524
|
-
"
|
|
525
|
-
"
|
|
356
|
+
"appId": "your-app-id",
|
|
357
|
+
"prompt": "继续聊天",
|
|
358
|
+
"userId": "user-123",
|
|
359
|
+
"bizType": "chat",
|
|
360
|
+
"requestId": "req_1719000000001_def456",
|
|
361
|
+
"conversationId": "conv_xxx"
|
|
526
362
|
}
|
|
527
363
|
```
|
|
528
364
|
|
|
529
|
-
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
data:
|
|
365
|
+
**普通响应(非流式):**
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"success": true,
|
|
369
|
+
"code": 200,
|
|
370
|
+
"message": "",
|
|
371
|
+
"data": {
|
|
372
|
+
"content": "AI 的回复内容",
|
|
373
|
+
"conversationId": "conv_xxx"
|
|
374
|
+
}
|
|
375
|
+
}
|
|
536
376
|
```
|
|
537
377
|
|
|
538
|
-
|
|
539
|
-
- Header: `Authorization: Bearer <token>`
|
|
540
|
-
- 或通过配置 `authToken` 参数自动添加
|
|
378
|
+
### 流式接口 `POST {streamEndpoint}`(默认 `/v1/app/completion/stream`)
|
|
541
379
|
|
|
542
|
-
|
|
380
|
+
请求体同上,响应为 SSE(Server-Sent Events)格式:
|
|
543
381
|
|
|
544
|
-
```
|
|
545
|
-
|
|
546
|
-
npm install
|
|
382
|
+
```
|
|
383
|
+
event: [START]
|
|
547
384
|
|
|
548
|
-
|
|
549
|
-
|
|
385
|
+
event: message
|
|
386
|
+
data: 您好
|
|
550
387
|
|
|
551
|
-
|
|
552
|
-
|
|
388
|
+
event: message
|
|
389
|
+
data: ,有什么可以帮您的?
|
|
553
390
|
|
|
554
|
-
|
|
555
|
-
|
|
391
|
+
event: [DONE]
|
|
392
|
+
data: {"conversationId":"conv_xxx","tokens":{"input":10,"output":15}}
|
|
393
|
+
```
|
|
556
394
|
|
|
557
|
-
|
|
558
|
-
npm run lint
|
|
395
|
+
**支持的 SSE 事件类型:**
|
|
559
396
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
397
|
+
| event | 说明 |
|
|
398
|
+
|-------|------|
|
|
399
|
+
| `[START]` | 流式开始 |
|
|
400
|
+
| `message` | 文本增量 |
|
|
401
|
+
| `[THINKING]` | 思考/推理过程 |
|
|
402
|
+
| `[TOOL_START]` / `[TOOL_RESULT]` / `[TOOL_END]` | 工具调用 |
|
|
403
|
+
| `NODE_START` / `NODE_PROGRESS` / `NODE_COMPLETE` | 工作流节点 |
|
|
404
|
+
| `[HITL]` | 人机交互中断 |
|
|
405
|
+
| `[ERROR]` | 错误 |
|
|
406
|
+
| `[DONE]` | 流式结束 |
|
|
563
407
|
|
|
564
|
-
|
|
408
|
+
### 应用详情 `GET /v1/app/{appId}`
|
|
565
409
|
|
|
566
|
-
|
|
410
|
+
初始化时自动调用,返回应用名称、欢迎语、建议问题:
|
|
567
411
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
412
|
+
```json
|
|
413
|
+
{
|
|
414
|
+
"success": true,
|
|
415
|
+
"code": 200,
|
|
416
|
+
"data": {
|
|
417
|
+
"name": "客服助手",
|
|
418
|
+
"description": "专业客服 AI",
|
|
419
|
+
"prologue": "你好!我可以帮你解答问题\n- 我要退货\n- 查看订单状态\n- 联系人工客服"
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
```
|
|
574
423
|
|
|
575
|
-
|
|
424
|
+
### 其他可选接口
|
|
576
425
|
|
|
577
|
-
|
|
426
|
+
| 接口 | 默认路径 | 用途 |
|
|
427
|
+
|------|----------|------|
|
|
428
|
+
| 停止生成 | `POST /v1/app/completion/stop` | 停止当前流式输出 |
|
|
429
|
+
| 会话查询 | `POST /v1/app/conversation/query` | 查询历史会话列表 |
|
|
430
|
+
| 会话删除 | `POST /v1/app/conversation/delete` | 删除指定会话 |
|
|
578
431
|
|
|
579
|
-
|
|
580
|
-
// v1.x (Vue组件)
|
|
581
|
-
import AIChatDialog from 'ibc-ai-web-sdk';
|
|
582
|
-
// <AIChatDialog :visible.sync="visible" :config="config" />
|
|
432
|
+
### 认证
|
|
583
433
|
|
|
584
|
-
|
|
585
|
-
import { createAIChatDialog } from 'ibc-ai-web-sdk';
|
|
434
|
+
所有请求自动携带 `Authorization: Bearer {token}`。提供 `refreshTokenFn` 后 Token 过期会自动刷新,无需手动处理。
|
|
586
435
|
|
|
587
|
-
|
|
588
|
-
apiBaseUrl: '/api/ai',
|
|
589
|
-
// ... 其他配置不变
|
|
590
|
-
});
|
|
436
|
+
---
|
|
591
437
|
|
|
592
|
-
|
|
438
|
+
## 构建与开发
|
|
439
|
+
|
|
440
|
+
```bash
|
|
441
|
+
npm install
|
|
442
|
+
npm run dev # 开发模式(监听文件变化)
|
|
443
|
+
npm run build # 构建
|
|
444
|
+
npm run lint # 代码检查
|
|
445
|
+
npm test # 测试
|
|
593
446
|
```
|
|
594
447
|
|
|
595
|
-
|
|
596
|
-
1. **移除Vue依赖** - 不再需要Vue运行时
|
|
597
|
-
2. **API更简洁** - `createAIChatDialog()` 返回实例对象
|
|
598
|
-
3. **完全隔离** - Shadow DOM确保样式不会污染宿主页面
|
|
599
|
-
4. **更多框架支持** - 原生支持React Hook、Angular Service等
|
|
448
|
+
构建产出 `dist/`:
|
|
600
449
|
|
|
601
|
-
|
|
450
|
+
| 文件 | 格式 | 用途 |
|
|
451
|
+
|------|------|------|
|
|
452
|
+
| `index.esm.js` | ES Module | Vite/Webpack/Rollup |
|
|
453
|
+
| `index.cjs.js` | CommonJS | require() |
|
|
454
|
+
| `index.umd.js` | UMD | 浏览器直接引入(开发版) |
|
|
455
|
+
| `index.umd.min.js` | UMD | 浏览器直接引入(生产版) |
|
|
602
456
|
|
|
603
|
-
|
|
457
|
+
---
|
|
604
458
|
|
|
605
|
-
##
|
|
459
|
+
## License
|
|
606
460
|
|
|
607
|
-
MIT
|
|
461
|
+
MIT
|