@blueking/ai-ui-sdk 0.0.4 → 0.0.5
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 +170 -237
- package/dist/hooks/use-chat.d.ts +3 -5
- package/dist/main.js +1 -1
- package/dist/types/type.d.ts +16 -0
- package/package.json +1 -1
package/README.md
CHANGED
@@ -17,6 +17,9 @@ npm install @blueking/ai-ui-sdk
|
|
17
17
|
- **思考过程可视化**:展示 AI 的思考过程和推理步骤
|
18
18
|
- **内容总结**:快速对对话内容进行摘要总结
|
19
19
|
- **统一样式**:提供一致的 UI 样式和图标
|
20
|
+
- **可拖拽和缩放的聊天窗口**:支持自定义位置和大小的聊天界面
|
21
|
+
- **快捷指令功能**:支持预设的快捷操作和自定义指令
|
22
|
+
- **多语言支持**:内置国际化支持
|
20
23
|
|
21
24
|
## 使用指南
|
22
25
|
|
@@ -28,35 +31,33 @@ import { useStyle, useChat, useClickProxy } from '@blueking/ai-ui-sdk';
|
|
28
31
|
// 引入样式和图标
|
29
32
|
useStyle();
|
30
33
|
|
31
|
-
//
|
34
|
+
// 设置全局点击代理事件
|
32
35
|
useClickProxy();
|
33
36
|
|
34
37
|
// 初始化聊天
|
35
38
|
const {
|
36
39
|
currentSession,
|
37
40
|
sessionContents,
|
38
|
-
|
41
|
+
sendChat,
|
39
42
|
stopChat,
|
40
|
-
setCurrentSession
|
43
|
+
setCurrentSession,
|
44
|
+
currentSessionLoading,
|
45
|
+
reGenerateChat,
|
46
|
+
reSendChat,
|
47
|
+
deleteChat,
|
41
48
|
} = useChat({
|
42
|
-
handleStart: (
|
43
|
-
console.log('聊天开始'
|
44
|
-
},
|
45
|
-
handleText: (sessionCode, sessionContent) => {
|
46
|
-
console.log('收到文本消息', sessionContent.content);
|
47
|
-
},
|
48
|
-
handleReferenceDoc: (sessionCode, sessionContent) => {
|
49
|
-
console.log('收到引用资料');
|
49
|
+
handleStart: () => {
|
50
|
+
console.log('聊天开始');
|
50
51
|
},
|
51
|
-
|
52
|
-
console.log('
|
52
|
+
handleText: () => {
|
53
|
+
console.log('收到文本消息');
|
53
54
|
},
|
54
|
-
handleEnd: (
|
55
|
+
handleEnd: () => {
|
55
56
|
console.log('聊天结束');
|
56
57
|
},
|
57
|
-
|
58
|
-
|
59
|
-
}
|
58
|
+
requestOptions: {
|
59
|
+
url: 'your-api-endpoint',
|
60
|
+
},
|
60
61
|
});
|
61
62
|
```
|
62
63
|
|
@@ -64,265 +65,197 @@ const {
|
|
64
65
|
|
65
66
|
```typescript
|
66
67
|
// 设置当前会话
|
67
|
-
|
68
|
-
sessionCode: '
|
69
|
-
sessionName: '
|
70
|
-
model: '
|
68
|
+
const session: ISession = {
|
69
|
+
sessionCode: '1',
|
70
|
+
sessionName: 'test',
|
71
|
+
model: '',
|
72
|
+
};
|
73
|
+
setCurrentSession(session);
|
74
|
+
|
75
|
+
// 发送聊天消息
|
76
|
+
sendChat({
|
77
|
+
message: '你的问题',
|
78
|
+
cite: '选中的文本', // 可选,引用的文本内容
|
71
79
|
});
|
72
80
|
|
73
|
-
//
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
+
// 使用快捷指令发送消息
|
82
|
+
sendChat({
|
83
|
+
message: '快捷指令标签',
|
84
|
+
cite: '选中的文本',
|
85
|
+
shortcut: {
|
86
|
+
label: '快捷指令名称',
|
87
|
+
key: 'shortcut-key',
|
88
|
+
prompt: '预设的提示模板',
|
89
|
+
icon: '图标', // 可选
|
81
90
|
},
|
82
|
-
headers: {
|
83
|
-
'Authorization': 'Bearer your-api-token'
|
84
|
-
}
|
85
91
|
});
|
86
92
|
|
87
93
|
// 停止正在进行的聊天
|
88
|
-
stopChat(
|
94
|
+
stopChat(session.sessionCode);
|
89
95
|
```
|
90
96
|
|
91
|
-
###
|
92
|
-
|
93
|
-
```typescript
|
94
|
-
import { useSummary } from '@blueking/ai-ui-sdk';
|
95
|
-
|
96
|
-
const { summary } = useSummary({
|
97
|
-
handleStart: () => {
|
98
|
-
console.log('开始生成摘要');
|
99
|
-
},
|
100
|
-
handleEnd: (text) => {
|
101
|
-
console.log('摘要生成完成:', text);
|
102
|
-
},
|
103
|
-
handleError: (message, code) => {
|
104
|
-
console.error('摘要生成失败:', message, code);
|
105
|
-
}
|
106
|
-
});
|
97
|
+
### 完整的聊天界面示例
|
107
98
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
99
|
+
```vue
|
100
|
+
<template>
|
101
|
+
<div class="ai-blueking-wrapper">
|
102
|
+
<vue-draggable-resizable
|
103
|
+
v-if="isShow"
|
104
|
+
:active="isShow"
|
105
|
+
:draggable="true"
|
106
|
+
:h="height"
|
107
|
+
:min-height="minHeight"
|
108
|
+
:min-width="minWidth"
|
109
|
+
:parent="true"
|
110
|
+
:prevent-deactivation="true"
|
111
|
+
:resizable="true"
|
112
|
+
:w="width"
|
113
|
+
:x="left"
|
114
|
+
:y="top"
|
115
|
+
class-name="ai-blueking-container-wrapper"
|
116
|
+
drag-handle=".drag-handle"
|
117
|
+
@dragging="handleDragging"
|
118
|
+
@resizing="handleResizing"
|
119
|
+
>
|
120
|
+
<div class="ai-blueking-container">
|
121
|
+
<!-- 聊天界面内容 -->
|
122
|
+
<div class="content-wrapper">
|
123
|
+
<div class="message-wrapper">
|
124
|
+
<render-message
|
125
|
+
v-for="(message, index) in sessionContents"
|
126
|
+
:key="message.id"
|
127
|
+
:message="message"
|
128
|
+
:index="index"
|
129
|
+
@delete="handleDelete"
|
130
|
+
@regenerate="handleRegenerate"
|
131
|
+
@resend="handleResend"
|
132
|
+
/>
|
133
|
+
</div>
|
134
|
+
|
135
|
+
<div class="chat-input-container">
|
136
|
+
<ChatInputBox
|
137
|
+
v-model="inputMessage"
|
138
|
+
:loading="currentSessionLoading"
|
139
|
+
:shortcuts="shortcuts"
|
140
|
+
@send="handleSendMessage"
|
141
|
+
@shortcut-click="handleShortcutClick"
|
142
|
+
@stop="handleStop"
|
143
|
+
/>
|
144
|
+
</div>
|
145
|
+
</div>
|
146
|
+
</div>
|
147
|
+
</vue-draggable-resizable>
|
148
|
+
</div>
|
149
|
+
</template>
|
117
150
|
```
|
118
151
|
|
119
|
-
|
120
|
-
|
121
|
-
### 会话内容展示
|
122
|
-
|
123
|
-
SDK 可以将 AI 回复渲染为包含以下元素的富文本内容:
|
124
|
-
|
125
|
-
1. **引用资料**:显示 AI 回答中引用的文档
|
126
|
-
```html
|
127
|
-
<section class="knowledge-head click-close">
|
128
|
-
找到 X 篇资料参考
|
129
|
-
<i class="ai-ui-sdk-icon icon-angle-up"></i>
|
130
|
-
</section>
|
131
|
-
<ul class="knowledge-body">
|
132
|
-
<!-- 引用资料列表 -->
|
133
|
-
</ul>
|
134
|
-
```
|
135
|
-
|
136
|
-
2. **思考过程**:展示 AI 的思考过程
|
137
|
-
```html
|
138
|
-
<section class="think-head click-close">
|
139
|
-
<i class="ai-ui-sdk-icon icon-sikao"></i>思考中...
|
140
|
-
<i class="ai-ui-sdk-icon icon-angle-up"></i>
|
141
|
-
</section>
|
142
|
-
<section class="think-body">
|
143
|
-
<!-- 思考内容 -->
|
144
|
-
</section>
|
145
|
-
```
|
146
|
-
|
147
|
-
## 开发者指南
|
148
|
-
|
149
|
-
### 架构概览
|
150
|
-
|
151
|
-
SDK 主要由以下模块组成:
|
152
|
+
### 快捷指令配置
|
152
153
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
154
|
+
```typescript
|
155
|
+
// 默认快捷指令示例
|
156
|
+
const DEFAULT_SHORTCUTS: ShortCut[] = [
|
157
|
+
{
|
158
|
+
label: '解释代码',
|
159
|
+
key: 'explain-code',
|
160
|
+
prompt: '请解释以下代码的功能:{ SELECTED_TEXT }',
|
161
|
+
icon: 'code-icon',
|
162
|
+
},
|
163
|
+
// 更多快捷指令...
|
164
|
+
];
|
160
165
|
|
161
|
-
|
162
|
-
|
163
|
-
|
166
|
+
// 在组件中使用
|
167
|
+
const props = defineProps<{
|
168
|
+
shortcuts?: ShortCut[];
|
169
|
+
}>();
|
170
|
+
```
|
164
171
|
|
165
|
-
|
172
|
+
## 类型定义
|
166
173
|
|
167
|
-
|
174
|
+
### 会话类型
|
168
175
|
|
169
176
|
```typescript
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
// 自定义实现
|
182
|
-
},
|
183
|
-
|
184
|
-
// 接收引用资料时的处理
|
185
|
-
handleReferenceDoc: (sessionCode, sessionContent) => {
|
186
|
-
// 自定义实现
|
187
|
-
},
|
188
|
-
|
189
|
-
// 接收思考过程时的处理
|
190
|
-
handleThink: (sessionCode, sessionContent) => {
|
191
|
-
// 自定义实现
|
192
|
-
},
|
193
|
-
|
194
|
-
// 结束时的处理
|
195
|
-
handleEnd: (sessionCode, sessionContent) => {
|
196
|
-
// 自定义实现
|
197
|
-
},
|
198
|
-
|
199
|
-
// 出错时的处理
|
200
|
-
handleError: (sessionCode, sessionContent, code) => {
|
201
|
-
// 自定义实现
|
202
|
-
}
|
203
|
-
});
|
177
|
+
interface ISession {
|
178
|
+
sessionCode: string;
|
179
|
+
sessionName: string;
|
180
|
+
model: string;
|
181
|
+
roleInfo?: {
|
182
|
+
collectionId: number;
|
183
|
+
collectionName: string;
|
184
|
+
content: ISessionPrompt[];
|
185
|
+
variables: any[];
|
186
|
+
};
|
187
|
+
}
|
204
188
|
```
|
205
189
|
|
206
|
-
###
|
207
|
-
|
208
|
-
SDK 使用 Vue 3 的响应式系统管理会话内容状态:
|
190
|
+
### 聊天内容类型
|
209
191
|
|
210
192
|
```typescript
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
193
|
+
interface ISessionContent {
|
194
|
+
id?: number;
|
195
|
+
role: SessionContentRole;
|
196
|
+
content: string;
|
197
|
+
status?: SessionContentStatus;
|
198
|
+
sessionCode: string;
|
199
|
+
cite?: string;
|
200
|
+
time?: string;
|
201
|
+
}
|
219
202
|
```
|
220
203
|
|
221
|
-
###
|
222
|
-
|
223
|
-
SDK 期望后端返回的流式响应格式如下:
|
204
|
+
### 快捷指令类型
|
224
205
|
|
206
|
+
```typescript
|
207
|
+
interface ShortCut {
|
208
|
+
label: string;
|
209
|
+
key: string;
|
210
|
+
prompt: string;
|
211
|
+
icon?: string;
|
212
|
+
}
|
225
213
|
```
|
226
|
-
data: {"event":"text","content":"文本内容","cover":false}
|
227
|
-
|
228
|
-
data: {"event":"reference_doc","documents":[{"metadata":{"file_path":"文件路径","path":"路径","preview_path":"预览路径"}}]}
|
229
214
|
|
230
|
-
|
215
|
+
## 高级功能
|
231
216
|
|
232
|
-
|
217
|
+
### 消息重发和重新生成
|
233
218
|
|
234
|
-
|
219
|
+
```typescript
|
220
|
+
// 重新生成 AI 回复
|
221
|
+
const handleRegenerate = (index: number) => {
|
222
|
+
reGenerateChat(index);
|
223
|
+
};
|
224
|
+
|
225
|
+
// 重新发送用户消息
|
226
|
+
const handleResend = (index: number, value: { message: string; cite: string }) => {
|
227
|
+
reSendChat(index, value);
|
228
|
+
};
|
235
229
|
```
|
236
230
|
|
237
|
-
|
238
|
-
|
239
|
-
以下是一个简单的 AI 聊天应用示例:
|
240
|
-
|
241
|
-
```vue
|
242
|
-
<template>
|
243
|
-
<div class="chat-container">
|
244
|
-
<div class="chat-messages" ref="messagesRef">
|
245
|
-
<div v-for="message in sessionContents" :key="message.id"
|
246
|
-
:class="['message', message.role]">
|
247
|
-
<div v-if="message.role === 'user'" class="user-message">
|
248
|
-
{{ message.content }}
|
249
|
-
</div>
|
250
|
-
<div v-else-if="message.role === 'ai'" class="ai-message"
|
251
|
-
v-html="message.content"></div>
|
252
|
-
</div>
|
253
|
-
</div>
|
254
|
-
|
255
|
-
<div class="chat-input">
|
256
|
-
<input v-model="inputMessage" @keyup.enter="sendMessage"
|
257
|
-
placeholder="输入您的问题..."/>
|
258
|
-
<button @click="sendMessage">发送</button>
|
259
|
-
</div>
|
260
|
-
</div>
|
261
|
-
</template>
|
231
|
+
### 消息删除
|
262
232
|
|
263
|
-
|
264
|
-
|
265
|
-
|
233
|
+
```typescript
|
234
|
+
const handleDelete = (index: number) => {
|
235
|
+
deleteChat(index);
|
236
|
+
};
|
237
|
+
```
|
266
238
|
|
267
|
-
|
268
|
-
useClickProxy();
|
239
|
+
## 样式定制
|
269
240
|
|
270
|
-
|
271
|
-
const messagesRef = ref(null);
|
241
|
+
SDK 提供了基础的样式和主题支持,你可以通过覆盖 CSS 变量来自定义界面外观:
|
272
242
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
plusSessionContent
|
278
|
-
} = useChat();
|
243
|
+
```scss
|
244
|
+
.ai-blueking-container {
|
245
|
+
// 自定义样式
|
246
|
+
}
|
279
247
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
sessionCode: 'demo_session',
|
284
|
-
sessionName: '演示对话',
|
285
|
-
model: 'your-model-id'
|
286
|
-
});
|
287
|
-
});
|
248
|
+
.message-wrapper {
|
249
|
+
// 消息列表样式
|
250
|
+
}
|
288
251
|
|
289
|
-
|
290
|
-
|
291
|
-
if (!inputMessage.value.trim()) return;
|
292
|
-
|
293
|
-
// 添加用户消息
|
294
|
-
plusSessionContent('demo_session', {
|
295
|
-
sessionCode: 'demo_session',
|
296
|
-
role: SessionContentRole.User,
|
297
|
-
content: inputMessage.value
|
298
|
-
});
|
299
|
-
|
300
|
-
// 发送聊天请求
|
301
|
-
chat({
|
302
|
-
sessionCode: 'demo_session',
|
303
|
-
url: 'https://your-api-endpoint/chat',
|
304
|
-
data: {
|
305
|
-
model: 'your-model-id',
|
306
|
-
message: inputMessage.value
|
307
|
-
}
|
308
|
-
});
|
309
|
-
|
310
|
-
// 清空输入框
|
311
|
-
inputMessage.value = '';
|
252
|
+
.chat-input-container {
|
253
|
+
// 输入框样式
|
312
254
|
}
|
313
|
-
</script>
|
314
255
|
```
|
315
256
|
|
316
|
-
## API 参考
|
317
|
-
|
318
|
-
请参考源代码中的类型定义获取完整 API 参考。
|
319
|
-
|
320
257
|
## 注意事项
|
321
258
|
|
322
|
-
- SDK 依赖 Vue 3
|
323
|
-
-
|
324
|
-
- 处理复杂的 markdown 或代码展示时,建议使用专门的渲染库
|
325
|
-
|
326
|
-
## 许可证
|
259
|
+
- SDK 依赖 Vue 3,请确保项目中已安装
|
260
|
+
- 建议使用 TypeScript 以获得更好的类型提示
|
327
261
|
|
328
|
-
ISC
|
package/dist/hooks/use-chat.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import type { ISessionContent, ISession, ISessionPrompt, ChatCallbacks } from '../types/type.ts';
|
1
|
+
import type { ISessionContent, ISession, ISessionPrompt, ChatCallbacks, BasicChatContent, ShortcutChatContent } from '../types/type.ts';
|
2
2
|
import { SessionContentRole, SessionContentStatus } from '../types/enum';
|
3
3
|
type SessionContentsMap = {
|
4
4
|
[key: string]: ISessionContent[];
|
@@ -49,10 +49,7 @@ export declare const useChat: <T extends ISession = ISession>({ handleStart, han
|
|
49
49
|
url: string;
|
50
50
|
headers?: Record<string, string>;
|
51
51
|
}) => void;
|
52
|
-
sendChat: (content:
|
53
|
-
message: string;
|
54
|
-
cite?: string;
|
55
|
-
}, callback?: () => void) => void;
|
52
|
+
sendChat: (content: BasicChatContent | ShortcutChatContent, callback?: () => void) => void;
|
56
53
|
stopChat: (sessionCode: string) => void;
|
57
54
|
plusSessionContent: (sessionCode: string, sessionContent: ISessionContent) => void;
|
58
55
|
updateSessionContent: (sessionContent: ISessionContent) => void;
|
@@ -70,5 +67,6 @@ export declare const useChat: <T extends ISession = ISession>({ handleStart, han
|
|
70
67
|
message: string;
|
71
68
|
cite?: string;
|
72
69
|
}, callback?: () => void) => void;
|
70
|
+
deleteChat: (index: number) => void;
|
73
71
|
};
|
74
72
|
export {};
|
package/dist/main.js
CHANGED
@@ -243,6 +243,6 @@ url(${m}) format("embedded-opentype");
|
|
243
243
|
&~ .knowledge-head {
|
244
244
|
margin-bottom: 8px;
|
245
245
|
}
|
246
|
-
}`;(A=document.createElement("style")).textContent=e,document.head.appendChild(A)},t=()=>{A&&(A.remove(),A=null)};(0,a.onBeforeMount)(()=>{e()}),(0,a.onBeforeUnmount)(()=>{t()})};function f(A,e,t,n,i,o,l){try{var s=A[o](l),a=s.value}catch(A){t(A);return}s.done?e(a):Promise.resolve(a).then(n,i)}function Q(A){return function(){var e=this,t=arguments;return new Promise(function(n,i){var o=A.apply(e,t);function l(A){f(o,n,i,l,s,"next",A)}function s(A){f(o,n,i,l,s,"throw",A)}l(void 0)})}}function w(A,e,t){return e in A?Object.defineProperty(A,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):A[e]=t,A}class b{stream({sessionCode:A,url:e,headers:t,data:n}){var i=this;return Q(function*(){var o,l;yield null===(o=i.handleStart)||void 0===o?void 0:o.call(i,A);let s=new AbortController;i.controllerMap[A]=s,fetch(e,{method:"post",signal:s.signal,headers:function(A){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},n=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(t).filter(function(A){return Object.getOwnPropertyDescriptor(t,A).enumerable}))),n.forEach(function(e){w(A,e,t[e])})}return A}({"Content-Type":"application/json"},t),mode:"cors",credentials:"include",body:JSON.stringify(n)}).then((l=Q(function*(e){let t=e.body.pipeThrough(new window.TextDecoderStream).getReader(),n="";for(;;)try{let{value:o,done:l}=yield t.read();if(!e.ok){i.handleError(A,o||e.statusText,e.status);break}if(l){i.handleEnd(A);break}(n+o.toString()).split("\n").forEach(t=>{let o=t.replace("data:","").trim();if(d(o)){var l,s;let{event:t,content:a,cover:r,documents:d,result:c,code:u,elapsed_time:B,message:g}=JSON.parse(o);if(!1===c||200!==e.status){i.handleError(A,g||"模型调用失败",u);return}switch(t){case"text":i.handleText(A,a,r);break;case"reference_doc":null===(l=i.handleReferenceDoc)||void 0===l||l.call(i,A,d,r);break;case"think":null===(s=i.handleThink)||void 0===s||s.call(i,A,a,r,B);break;case"done":i.handleEnd(A,r?a:"");break;case"error":i.handleError(A,g||"模型调用失败",u)}n=""}else o&&(n=o)})}catch(e){(null==e?void 0:e.code)!==20&&i.handleError(A,`模型调用失败:${e.message}`,e.code);break}}),function(A){return l.apply(this,arguments)}))})()}stop(A){var e,t;return null===(t=this.controllerMap[A])||void 0===t||null===(e=t.abort)||void 0===e||e.call(t),this.handleEnd(A)}constructor({handleStart:A,handleText:e,handleReferenceDoc:t,handleThink:n,handleEnd:i,handleError:o}){w(this,"handleStart",void 0),w(this,"handleText",void 0),w(this,"handleReferenceDoc",void 0),w(this,"handleThink",void 0),w(this,"handleEnd",void 0),w(this,"handleError",void 0),w(this,"controllerMap",void 0),this.handleStart=A,this.handleText=e,this.handleReferenceDoc=t,this.handleThink=n,this.handleEnd=i,this.handleError=o,this.controllerMap={}}}let k=({handleStart:A,handleText:i,handleReferenceDoc:o,handleThink:l,handleEnd:r,handleError:d,requestOptions:c}={})=>{let u="内容正在生成中...",h=(0,a.ref)(),v=(0,a.ref)({}),f=(0,a.ref)([]),Q={},w=(0,a.computed)(()=>{let A=[];for(let n=f.value.length-1;n>=0;n--){let i=f.value[n],o=n+1,l=f.value[o];for(;l&&![t.Ai,t.TokenExpired,t.ImageNotSupported,t.Pause,t.Guide].includes(l.role);)o+=1,l=f.value[o];if(i.role===t.System)break;i.status===e.Fail||(null==l?void 0:l.status)===e.Fail&&[t.User,t.UserImage].includes(i.role)||[t.Time,t.System].includes(i.role)||A.unshift(i)}return A}),k=(0,a.computed)(()=>{var A;let e=null===(A=h.value)||void 0===A?void 0:A.sessionCode;return!!e&&v.value[e]}),C=(0,a.computed)(()=>{var A,e,n;let i=[],o=[],l=[],a=f.value.findLastIndex(A=>A.role===t.System&&["已启用角色","已启用模型"].some(e=>A.content.includes(e))),r=0;null===(n=h.value)||void 0===n||null===(e=n.roleInfo)||void 0===e||null===(A=e.content)||void 0===A||A.forEach(A=>{let e=f.value[a+1+r],n=f.value[a+2+r];if((null==e?void 0:e.content)===A.content&&e.role!==t.System&&(i.push(s(e)),r+=1,(null==e?void 0:e.role)===t.Pause)){for(;n&&n.role===t.System;)r+=1,n=f.value[a+1+r];for(;n&&[t.User,t.UserImage].includes(n.role);)i.push(s(n)),r+=1,n=f.value[a+1+r]}}),o.push(...w.value.map(s));let d=A=>{let e=!0;for(let n=A;n<i.length;n++){var t;i[n].content!==(null===(t=o[n-A])||void 0===t?void 0:t.content)&&(e=!1)}return e};for(let A=0;A<i.length;A++){let e=i[A];if(d(A))break;l.push(e)}return l.push(...o),l.forEach(A=>{A.content=m(A.content),A.content=g(A.content)}),l}),y=new b({handleStart:R,handleText:function(A,t,n){let o=I(A);if(o.content===u)o.content=t;else{if(o.status!==e.Loading)return;o.content=n?t:o.content+t}return null==i?void 0:i(A,o)},handleReferenceDoc:function(A,e,t){let n=I(A),i=B(e);return n.content=t?i:n.content+i,null==o?void 0:o(A,n)},handleThink:function(A,e,t,n){let i=I(A);return i.content=p(i.content,e,t,n),null==l?void 0:l(A,i)},handleEnd:function(A,t){let n=I(A);if(n.status===e.Loading)return v.value[A]=!1,t&&(n.content=t),n.status=e.Success,null==r?void 0:r(A,n);(n.content===u||E(n.content))&&D(A,"聊天内容已中断")},handleError:D});function I(A){var e,t;return(null===(e=h.value)||void 0===e?void 0:e.sessionCode)===A?f.value.at(-1):null===(t=Q[A])||void 0===t?void 0:t.at(-1)}function G(A){var e;return(null===(e=h.value)||void 0===e?void 0:e.sessionCode)===A?f.value:Q[A]}function x(A,e){G(A).push(e)}function Y(A,e,n){var i;let o=(null===(i=h.value)||void 0===i?void 0:i.sessionCode)===A?f.value:Q[A],l=[];return e.forEach(A=>{let e=o.findIndex(e=>e.id===A);if(e>-1){let i=o[e-1],s=o[e+1],a=o[e+2];if(o.splice(e,1),l.push(A),[t.Hidden].includes(null==i?void 0:i.role)){let A=o.findIndex(A=>A.id===i.id);o.splice(A,1),l.push(i.id)}if((null==s?void 0:s.role)===t.Ai||n&&[t.Ai,t.Guide,t.TokenExpired,t.ImageNotSupported,t.Pause].includes(null==s?void 0:s.role)){let A=o.findIndex(A=>A.id===s.id);o.splice(A,1),l.push(s.id)}if([t.Guide].includes(null==a?void 0:a.role)&&n){let A=o.findIndex(A=>A.id===a.id);o.splice(A,1),l.push(a.id)}}}),l}function R(n){v.value[n]=!0;let i={sessionCode:n,role:t.Ai,status:e.Loading,content:u};return x(n,i),null==A?void 0:A(n,i)}function D(A,i,o){let l=I(A);return l.status=e.Fail,l.content=i,v.value[A]=!1,o===n.TokenExpired&&(l.content="抱歉,您的剩余 Token 不足,无法返回回答内容,请先清空当前会话(上下文仍会作为历史记录保留))",l.role=t.TokenExpired),o===n.ImageNotSupported&&(l.content="抱歉,当前模型不支持图片内容解析",l.role=t.ImageNotSupported),null==d?void 0:d(A,l,o)}function F(A,n){var i,o,l;if(!(null===(i=h.value)||void 0===i?void 0:i.sessionCode)||!(null==c?void 0:c.url)||k.value)return;let{message:s,cite:a}=A;f.value.push({sessionCode:null===(o=h.value)||void 0===o?void 0:o.sessionCode,content:s,role:t.User,status:e.Success,cite:a})
|
246
|
+
}`;(A=document.createElement("style")).textContent=e,document.head.appendChild(A)},t=()=>{A&&(A.remove(),A=null)};(0,a.onBeforeMount)(()=>{e()}),(0,a.onBeforeUnmount)(()=>{t()})};function f(A,e,t,n,i,o,l){try{var s=A[o](l),a=s.value}catch(A){t(A);return}s.done?e(a):Promise.resolve(a).then(n,i)}function Q(A){return function(){var e=this,t=arguments;return new Promise(function(n,i){var o=A.apply(e,t);function l(A){f(o,n,i,l,s,"next",A)}function s(A){f(o,n,i,l,s,"throw",A)}l(void 0)})}}function w(A,e,t){return e in A?Object.defineProperty(A,e,{value:t,enumerable:!0,configurable:!0,writable:!0}):A[e]=t,A}class b{stream({sessionCode:A,url:e,headers:t,data:n}){var i=this;return Q(function*(){var o,l;yield null===(o=i.handleStart)||void 0===o?void 0:o.call(i,A);let s=new AbortController;i.controllerMap[A]=s,fetch(e,{method:"post",signal:s.signal,headers:function(A){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},n=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(t).filter(function(A){return Object.getOwnPropertyDescriptor(t,A).enumerable}))),n.forEach(function(e){w(A,e,t[e])})}return A}({"Content-Type":"application/json"},t),mode:"cors",credentials:"include",body:JSON.stringify(n)}).then((l=Q(function*(e){let t=e.body.pipeThrough(new window.TextDecoderStream).getReader(),n="";for(;;)try{let{value:o,done:l}=yield t.read();if(!e.ok){i.handleError(A,o||e.statusText,e.status);break}if(l){i.handleEnd(A);break}(n+o.toString()).split("\n").forEach(t=>{let o=t.replace("data:","").trim();if(d(o)){var l,s;let{event:t,content:a,cover:r,documents:d,result:c,code:u,elapsed_time:B,message:g}=JSON.parse(o);if(!1===c||200!==e.status){i.handleError(A,g||"模型调用失败",u);return}switch(t){case"text":i.handleText(A,a,r);break;case"reference_doc":null===(l=i.handleReferenceDoc)||void 0===l||l.call(i,A,d,r);break;case"think":null===(s=i.handleThink)||void 0===s||s.call(i,A,a,r,B);break;case"done":i.handleEnd(A,r?a:"");break;case"error":i.handleError(A,g||"模型调用失败",u)}n=""}else o&&(n=o)})}catch(e){(null==e?void 0:e.code)!==20&&i.handleError(A,`模型调用失败:${e.message}`,e.code);break}}),function(A){return l.apply(this,arguments)}))})()}stop(A){var e,t;return null===(t=this.controllerMap[A])||void 0===t||null===(e=t.abort)||void 0===e||e.call(t),this.handleEnd(A)}constructor({handleStart:A,handleText:e,handleReferenceDoc:t,handleThink:n,handleEnd:i,handleError:o}){w(this,"handleStart",void 0),w(this,"handleText",void 0),w(this,"handleReferenceDoc",void 0),w(this,"handleThink",void 0),w(this,"handleEnd",void 0),w(this,"handleError",void 0),w(this,"controllerMap",void 0),this.handleStart=A,this.handleText=e,this.handleReferenceDoc=t,this.handleThink=n,this.handleEnd=i,this.handleError=o,this.controllerMap={}}}let k=({handleStart:A,handleText:i,handleReferenceDoc:o,handleThink:l,handleEnd:r,handleError:d,requestOptions:c}={})=>{let u="内容正在生成中...",h=(0,a.ref)(),v=(0,a.ref)({}),f=(0,a.ref)([]),Q={},w=(0,a.computed)(()=>{let A=[];for(let n=f.value.length-1;n>=0;n--){let i=f.value[n],o=n+1,l=f.value[o];for(;l&&![t.Ai,t.TokenExpired,t.ImageNotSupported,t.Pause,t.Guide].includes(l.role);)o+=1,l=f.value[o];if(i.role===t.System)break;i.status===e.Fail||(null==l?void 0:l.status)===e.Fail&&[t.User,t.UserImage].includes(i.role)||[t.Time,t.System].includes(i.role)||A.unshift(i)}return A}),k=(0,a.computed)(()=>{var A;let e=null===(A=h.value)||void 0===A?void 0:A.sessionCode;return!!e&&v.value[e]}),C=(0,a.computed)(()=>{var A,e,n;let i=[],o=[],l=[],a=f.value.findLastIndex(A=>A.role===t.System&&["已启用角色","已启用模型"].some(e=>A.content.includes(e))),r=0;null===(n=h.value)||void 0===n||null===(e=n.roleInfo)||void 0===e||null===(A=e.content)||void 0===A||A.forEach(A=>{let e=f.value[a+1+r],n=f.value[a+2+r];if((null==e?void 0:e.content)===A.content&&e.role!==t.System&&(i.push(s(e)),r+=1,(null==e?void 0:e.role)===t.Pause)){for(;n&&n.role===t.System;)r+=1,n=f.value[a+1+r];for(;n&&[t.User,t.UserImage].includes(n.role);)i.push(s(n)),r+=1,n=f.value[a+1+r]}}),o.push(...w.value.map(s));let d=A=>{let e=!0;for(let n=A;n<i.length;n++){var t;i[n].content!==(null===(t=o[n-A])||void 0===t?void 0:t.content)&&(e=!1)}return e};for(let A=0;A<i.length;A++){let e=i[A];if(d(A))break;l.push(e)}return l.push(...o),l.forEach(A=>{A.content=m(A.content),A.content=g(A.content)}),l}),y=new b({handleStart:R,handleText:function(A,t,n){let o=I(A);if(o.content===u)o.content=t;else{if(o.status!==e.Loading)return;o.content=n?t:o.content+t}return null==i?void 0:i(A,o)},handleReferenceDoc:function(A,e,t){let n=I(A),i=B(e);return n.content=t?i:n.content+i,null==o?void 0:o(A,n)},handleThink:function(A,e,t,n){let i=I(A);return i.content=p(i.content,e,t,n),null==l?void 0:l(A,i)},handleEnd:function(A,t){let n=I(A);if(n.status===e.Loading)return v.value[A]=!1,t&&(n.content=t),n.status=e.Success,null==r?void 0:r(A,n);(n.content===u||E(n.content))&&D(A,"聊天内容已中断")},handleError:D});function I(A){var e,t;return(null===(e=h.value)||void 0===e?void 0:e.sessionCode)===A?f.value.at(-1):null===(t=Q[A])||void 0===t?void 0:t.at(-1)}function G(A){var e;return(null===(e=h.value)||void 0===e?void 0:e.sessionCode)===A?f.value:Q[A]}function x(A,e){G(A).push(e)}function Y(A,e,n){var i;let o=(null===(i=h.value)||void 0===i?void 0:i.sessionCode)===A?f.value:Q[A],l=[];return e.forEach(A=>{let e=o.findIndex(e=>e.id===A);if(e>-1){let i=o[e-1],s=o[e+1],a=o[e+2];if(o.splice(e,1),l.push(A),[t.Hidden].includes(null==i?void 0:i.role)){let A=o.findIndex(A=>A.id===i.id);o.splice(A,1),l.push(i.id)}if((null==s?void 0:s.role)===t.Ai||n&&[t.Ai,t.Guide,t.TokenExpired,t.ImageNotSupported,t.Pause].includes(null==s?void 0:s.role)){let A=o.findIndex(A=>A.id===s.id);o.splice(A,1),l.push(s.id)}if([t.Guide].includes(null==a?void 0:a.role)&&n){let A=o.findIndex(A=>A.id===a.id);o.splice(A,1),l.push(a.id)}}}),l}function R(n){v.value[n]=!0;let i={sessionCode:n,role:t.Ai,status:e.Loading,content:u};return x(n,i),null==A?void 0:A(n,i)}function D(A,i,o){let l=I(A);return l.status=e.Fail,l.content=i,v.value[A]=!1,o===n.TokenExpired&&(l.content="抱歉,您的剩余 Token 不足,无法返回回答内容,请先清空当前会话(上下文仍会作为历史记录保留))",l.role=t.TokenExpired),o===n.ImageNotSupported&&(l.content="抱歉,当前模型不支持图片内容解析",l.role=t.ImageNotSupported),null==d?void 0:d(A,l,o)}function F(A,n){var i,o,l;if(!(null===(i=h.value)||void 0===i?void 0:i.sessionCode)||!(null==c?void 0:c.url)||k.value)return;let{message:s,cite:a,shortcut:r}=A,d="";d=r?r.prompt.replace("{ SELECTED_TEXT }",a):a?`${s}: "${a}"`:s,f.value.push({sessionCode:null===(o=h.value)||void 0===o?void 0:o.sessionCode,content:s,role:t.User,status:e.Success,cite:a}),y.stream({sessionCode:null===(l=h.value)||void 0===l?void 0:l.sessionCode,url:c.url,headers:null==c?void 0:c.headers,data:{inputs:{chat_history:C.value.slice(0,C.value.length-1),input:d}}}),null==n||n()}return{currentSession:h,sessionContents:f,sessionContentsMap:Q,sessionLoadingMap:v,prompts:C,currentSessionLoading:k,chat:function({sessionCode:A,data:e,url:t,headers:n}){y.stream({sessionCode:A,url:t,data:e,headers:n||(null==c?void 0:c.headers)})},sendChat:F,stopChat:function(A){y.stop(A)},plusSessionContent:x,updateSessionContent:function(A){var e;let t=((null===(e=h.value)||void 0===e?void 0:e.sessionCode)===A.sessionCode?f.value:Q[A.sessionCode]).find(e=>+(e.id||0)==+(A.id||0));t&&Object.assign(t,A)},getSessionContentById:function(A,e){return G(e).find(e=>e.id===A)},getLastSessionContentBySessionCode:I,getSessionContentsBySessionCode:G,setCurrentSession:function(A){h.value=A,(null==A?void 0:A.sessionCode)&&(Q[A.sessionCode]||(Q[A.sessionCode]=[]),f.value=Q[A.sessionCode])},setSessionContents:function(A){h.value&&(Q[h.value.sessionCode]=A,f.value=A)},deleteSessionContent:function(A,e){return Y(A,[e],!0)},deleteSessionContents:function(A,e){return Y(A,e,!1)},handleStartChat:R,handleErrorChat:D,reGenerateChat:function(A){if(f.value[A].role!==t.Ai)return;let e=f.value[A-1].content,n=f.value[A-1].cite;f.value.splice(A-1,2),F({message:e,cite:n})},reSendChat:function(A,{message:e,cite:n},i){f.value[A].role===t.User&&(f.value.splice(A,f.value.length-A),F({message:e,cite:n},i))},deleteChat:function(A){if(f.value[A].role===t.User){f.value.splice(A,2);return}f.value.splice(A-1,2)}}},C=({handleStart:e,handleEnd:t,handleError:n}={})=>{let i="",o=new b({handleStart:()=>(i="",null==e?void 0:e()),handleText:(A,e,t)=>{t||"正在思考..."===i?i=e:i+=e},handleEnd:()=>("无话可说"===i&&(i=""),null==t?void 0:t(i)),handleError:(A,e,t)=>null==n?void 0:n(e,t)});return{summary:({content:e,url:t,headers:n,model:i})=>{let l=m(g(e)),s=[{role:A.User,content:`你是一个总结大师,请帮助我对下面这段话进行总结。要求总结精炼,不超过 15 个字!且末尾没有标点符号!请注意:如果你无法总结,请回复“无话可说”!
|
247
247
|
文字如下:
|
248
248
|
${l}`}];o.stream({sessionCode:"summary",url:t,data:{prompts:s,model:i},headers:n})}}},y=()=>{i(86),i(84),h(),v()},I=l.default;if("undefined"!=typeof window){let{currentScript:A}=window.document,e=A&&A.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);e&&(i.p=e[1])}})(),o})());
|
package/dist/types/type.d.ts
CHANGED
@@ -58,3 +58,19 @@ export interface SummaryCallbacks {
|
|
58
58
|
handleEnd?: (text: string) => void;
|
59
59
|
handleError?: (message: string, code?: string) => void;
|
60
60
|
}
|
61
|
+
export type BasicChatContent = {
|
62
|
+
message: string;
|
63
|
+
cite?: string;
|
64
|
+
shortcut?: never;
|
65
|
+
};
|
66
|
+
export type ShortcutChatContent = {
|
67
|
+
message: string;
|
68
|
+
cite: string;
|
69
|
+
shortcut: ShortCut;
|
70
|
+
};
|
71
|
+
export interface ShortCut {
|
72
|
+
label: string;
|
73
|
+
key: string;
|
74
|
+
prompt: string;
|
75
|
+
icon?: string;
|
76
|
+
}
|