@blueking/ai-ui-sdk 0.0.9-beta.1 → 0.0.9-beta.2

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.
Files changed (3) hide show
  1. package/README.md +420 -0
  2. package/dist/main.js +1 -1
  3. package/package.json +1 -1
package/README.md ADDED
@@ -0,0 +1,420 @@
1
+ # 蓝鲸 AI UI SDK
2
+
3
+ ## 介绍
4
+
5
+ 蓝鲸 AI UI SDK (@blueking/ai-ui-sdk) 是一个用于快速构建 AI 应用前端界面的工具包。它提供了一系列组件和 hooks,帮助开发者简化 AI 聊天界面的开发过程,包括聊天功能、引用资料展示、AI 思考过程可视化等功能。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm install @blueking/ai-ui-sdk
11
+ ```
12
+
13
+ ## 主要功能
14
+
15
+ - **聊天功能**:管理 AI 对话的完整生命周期
16
+ - **引用资料展示**:显示 AI 在回答中引用的文档资料
17
+ - **思考过程可视化**:展示 AI 的思考过程和推理步骤
18
+ - **内容总结**:快速对对话内容进行摘要总结
19
+ - **统一样式**:提供一致的 UI 样式和图标
20
+ - **可拖拽和缩放的聊天窗口**:支持自定义位置和大小的聊天界面
21
+ - **快捷指令功能**:支持预设的快捷操作和自定义指令
22
+ - **多语言支持**:内置国际化支持
23
+
24
+ ## 使用指南
25
+
26
+ ### 基本设置
27
+
28
+ ```typescript
29
+ import { useStyle, useChat, useClickProxy } from '@blueking/ai-ui-sdk';
30
+
31
+ // 引入样式和图标
32
+ useStyle();
33
+
34
+ // 设置全局点击代理事件
35
+ useClickProxy();
36
+
37
+ // 初始化聊天
38
+ const {
39
+ currentSession,
40
+ sessionContents,
41
+ sendChat,
42
+ stopChat,
43
+ setCurrentSession,
44
+ currentSessionLoading,
45
+ reGenerateChat,
46
+ reSendChat,
47
+ deleteChat,
48
+ } = useChat({
49
+ handleStart: () => {
50
+ console.log('聊天开始');
51
+ },
52
+ handleText: () => {
53
+ console.log('收到文本消息');
54
+ },
55
+ handleEnd: () => {
56
+ console.log('聊天结束');
57
+ },
58
+ requestOptions: {
59
+ url: 'your-api-endpoint',
60
+ },
61
+ });
62
+ ```
63
+
64
+ ### 创建聊天会话
65
+
66
+ ```typescript
67
+ // 设置当前会话
68
+ const session: ISession = {
69
+ sessionCode: '1',
70
+ sessionName: 'test',
71
+ model: '',
72
+ };
73
+ setCurrentSession(session);
74
+
75
+ // 发送聊天消息
76
+ sendChat({
77
+ message: '你的问题',
78
+ cite: '选中的文本', // 可选,引用的文本内容
79
+ });
80
+
81
+ // 使用快捷指令发送消息
82
+ sendChat({
83
+ message: '快捷指令标签',
84
+ cite: '选中的文本',
85
+ shortcut: {
86
+ label: '快捷指令名称',
87
+ key: 'shortcut-key',
88
+ prompt: '预设的提示模板',
89
+ icon: '图标', // 可选
90
+ },
91
+ });
92
+
93
+ // 停止正在进行的聊天
94
+ stopChat(session.sessionCode);
95
+ ```
96
+
97
+ ### 完整的聊天界面示例
98
+
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>
150
+ ```
151
+
152
+ ### 快捷指令配置
153
+
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
+ ];
165
+
166
+ // 在组件中使用
167
+ const props = defineProps<{
168
+ shortcuts?: ShortCut[];
169
+ }>();
170
+ ```
171
+
172
+ ## 类型定义
173
+
174
+ ### 会话类型
175
+
176
+ ```typescript
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
+ }
188
+ ```
189
+
190
+ ### 聊天内容类型
191
+
192
+ ```typescript
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
+ }
202
+ ```
203
+
204
+ ### 快捷指令类型
205
+
206
+ ```typescript
207
+ interface ShortCut {
208
+ label: string;
209
+ key: string;
210
+ prompt: string;
211
+ icon?: string;
212
+ }
213
+ ```
214
+
215
+ ## 高级功能
216
+
217
+ ### 消息重发和重新生成
218
+
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
+ };
229
+ ```
230
+
231
+ ### 消息删除
232
+
233
+ ```typescript
234
+ const handleDelete = (index: number) => {
235
+ deleteChat(index);
236
+ };
237
+ ```
238
+
239
+ ## 样式定制
240
+
241
+ SDK 提供了基础的样式和主题支持,你可以通过覆盖 CSS 变量来自定义界面外观:
242
+
243
+ ```scss
244
+ .ai-blueking-container {
245
+ // 自定义样式
246
+ }
247
+
248
+ .message-wrapper {
249
+ // 消息列表样式
250
+ }
251
+
252
+ .chat-input-container {
253
+ // 输入框样式
254
+ }
255
+ ```
256
+
257
+ ## 对话组件示例
258
+
259
+ ### 示例:使用 `useChat` Hook
260
+
261
+ 以下是一个完整的对话组件示例,展示了如何正确使用 `useChat` hook。该示例包括如何设置会话、发送消息、处理回调以及配置请求选项。
262
+
263
+ ```typescript
264
+ import { useStyle, useChat } from '@blueking/ai-ui-sdk';
265
+
266
+ // 引入样式和图标
267
+ useStyle();
268
+
269
+ // 初始化聊天
270
+ const {
271
+ currentSession,
272
+ sessionContents,
273
+ sendChat,
274
+ stopChat,
275
+ setCurrentSession,
276
+ currentSessionLoading,
277
+ reGenerateChat,
278
+ reSendChat,
279
+ deleteChat,
280
+ } = useChat({
281
+ handleStart: () => {
282
+ scrollToBottomIfNeeded();
283
+ },
284
+ handleText: () => {
285
+ scrollToBottomIfNeeded();
286
+ },
287
+ handleEnd: () => {
288
+ scrollToBottomIfNeeded();
289
+ },
290
+ requestOptions: {
291
+ url: props.url,
292
+ },
293
+ });
294
+
295
+ // 设置当前会话
296
+ const session: ISession = {
297
+ sessionCode: '1',
298
+ sessionName: 'test',
299
+ model: '',
300
+ };
301
+ setCurrentSession(session);
302
+
303
+ // 发送聊天消息
304
+ sendChat({
305
+ message: '你的问题',
306
+ cite: '选中的文本', // 可选,引用的文本内容
307
+ });
308
+
309
+ // 使用快捷指令发送消息
310
+ sendChat({
311
+ message: '快捷指令标签',
312
+ cite: '选中的文本',
313
+ shortcut: {
314
+ label: '快捷指令名称',
315
+ key: 'shortcut-key',
316
+ prompt: '预设的提示模板',
317
+ icon: '图标', // 可选
318
+ },
319
+ });
320
+
321
+ // 停止正在进行的聊天
322
+ stopChat(session.sessionCode);
323
+
324
+ // 重新生成 AI 回复
325
+ const handleRegenerate = (index: number) => {
326
+ reGenerateChat(index);
327
+ };
328
+
329
+ // 重新发送用户消息
330
+ const handleResend = (index: number, value: { message: string; cite: string }) => {
331
+ reSendChat(index, value);
332
+ };
333
+
334
+ // 删除消息
335
+ const handleDelete = (index: number) => {
336
+ deleteChat(index);
337
+ };
338
+
339
+ // 滚动到底部
340
+ const scrollToBottomIfNeeded = () => {
341
+ // 实现滚动到底部的逻辑
342
+ };
343
+ ```
344
+
345
+ ### 代码说明
346
+
347
+ - **`useStyle()`**: 引入 SDK 的样式和图标。
348
+ - **`useChat()`**: 初始化聊天功能,返回多个方法和状态用于管理聊天会话。
349
+ - **`currentSession`**: 当前会话对象。
350
+ - **`sessionContents`**: 当前会话中的所有消息内容。
351
+ - **`sendChat()`**: 发送聊天消息。
352
+ - **`stopChat()`**: 停止正在进行的聊天。
353
+ - **`setCurrentSession()`**: 设置当前会话。
354
+ - **`currentSessionLoading`**: 当前会话是否正在加载。
355
+ - **`reGenerateChat()`**: 重新生成 AI 回复。
356
+ - **`reSendChat()`**: 重新发送用户消息。
357
+ - **`deleteChat()`**: 删除消息。
358
+ - **`handleStart`**: 聊天开始时的回调函数。
359
+ - **`handleText`**: 收到文本消息时的回调函数。
360
+ - **`handleEnd`**: 聊天结束时的回调函数。
361
+ - **`requestOptions`**: 配置请求选项,包括 API 的 URL。
362
+
363
+ ## 注意事项
364
+
365
+ - SDK 依赖 Vue 3,请确保项目中已安装
366
+ - 建议使用 TypeScript 以获得更好的类型提示
367
+
368
+ ## 版本升级指南
369
+
370
+ ### 从 0.9.x 升级到 1.0.0
371
+
372
+ 1. **更新依赖**:
373
+ ```bash
374
+ npm install @blueking/ai-ui-sdk@1.0.0
375
+ ```
376
+
377
+ 2. **迁移指南**:
378
+ - `useChat` hook 的 `requestOptions` 参数现在需要包含 `url` 属性。
379
+ - 移除了 `useClickProxy`,请使用新的 `useGlobalClickHandler`。
380
+ - 新增了 `useStyle` 的 `theme` 参数,用于自定义主题。
381
+
382
+ 3. **示例**:
383
+ ```typescript
384
+ import { useStyle, useChat } from '@blueking/ai-ui-sdk';
385
+
386
+ // 引入样式和图标
387
+ useStyle({ theme: 'dark' });
388
+
389
+ // 初始化聊天
390
+ const {
391
+ currentSession,
392
+ sessionContents,
393
+ sendChat,
394
+ stopChat,
395
+ setCurrentSession,
396
+ currentSessionLoading,
397
+ reGenerateChat,
398
+ reSendChat,
399
+ deleteChat,
400
+ } = useChat({
401
+ handleStart: () => {
402
+ console.log('聊天开始');
403
+ },
404
+ handleText: () => {
405
+ console.log('收到文本消息');
406
+ },
407
+ handleEnd: () => {
408
+ console.log('聊天结束');
409
+ },
410
+ requestOptions: {
411
+ url: 'your-api-endpoint',
412
+ },
413
+ });
414
+ ```
415
+
416
+ 4. **常见问题**:
417
+ - **Q: 如何处理 API 请求失败?**
418
+ - A: 使用 `try-catch` 块捕获 `sendChat` 和 `reGenerateChat` 的错误。
419
+ - **Q: 如何自定义聊天窗口的样式?**
420
+ - A: 通过覆盖 CSS 变量来自定义界面外观。
package/dist/main.js CHANGED
@@ -243,6 +243,6 @@ url(${D}) 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)},i=()=>{A&&(A.remove(),A=null)};(0,T.onBeforeMount)(()=>{e()}),(0,T.onBeforeUnmount)(()=>{i()})};function L(A,e,i,t,n,o,g){try{var l=A[o](g),a=l.value}catch(A){i(A);return}l.done?e(a):Promise.resolve(a).then(t,n)}function Y(A){return function(){var e=this,i=arguments;return new Promise(function(t,n){var o=A.apply(e,i);function g(A){L(o,t,n,g,l,"next",A)}function l(A){L(o,t,n,g,l,"throw",A)}g(void 0)})}}function O(A,e,i){return e in A?Object.defineProperty(A,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):A[e]=i,A}class f{stream({sessionCode:A,url:e,headers:i,data:t}){var n=this;return Y(function*(){var o,g;yield null===(o=n.handleStart)||void 0===o?void 0:o.call(n,A);let l=new AbortController;n.controllerMap[A]=l,fetch(e,{method:"post",signal:l.signal,headers:function(A){for(var e=1;e<arguments.length;e++){var i=null!=arguments[e]?arguments[e]:{},t=Object.keys(i);"function"==typeof Object.getOwnPropertySymbols&&(t=t.concat(Object.getOwnPropertySymbols(i).filter(function(A){return Object.getOwnPropertyDescriptor(i,A).enumerable}))),t.forEach(function(e){O(A,e,i[e])})}return A}({"Content-Type":"application/json"},i),mode:"cors",credentials:"include",body:JSON.stringify(t)}).then((g=Y(function*(e){let i=e.body.pipeThrough(new window.TextDecoderStream).getReader(),t="";for(;;)try{let{value:o,done:g}=yield i.read();if(!e.ok){n.handleError(A,o||e.statusText,e.status);break}if(g){n.handleEnd(A);break}(t+o.toString()).split("\n").forEach(i=>{let o=i.replace("data:","").trim();if(C(o)){var g,l;let{event:i,content:a,cover:M,documents:s,result:c,code:u,elapsed_time:r,message:N}=JSON.parse(o);if(!1===c||200!==e.status){n.handleError(A,N||"模型调用失败",u);return}switch(i){case"text":n.handleText(A,a,M);break;case"reference_doc":null===(g=n.handleReferenceDoc)||void 0===g||g.call(n,A,s,M);break;case"think":null===(l=n.handleThink)||void 0===l||l.call(n,A,a,M,r);break;case"done":n.handleEnd(A,M?a:"");break;case"error":n.handleError(A,N||"模型调用失败",u)}t=""}else o&&(t=o)})}catch(e){(null==e?void 0:e.code)!==20&&n.handleError(A,`模型调用失败:${e.message}`,e.code);break}}),function(A){return g.apply(this,arguments)}))})()}stop(A){var e,i;return null===(i=this.controllerMap[A])||void 0===i||null===(e=i.abort)||void 0===e||e.call(i),this.handleEnd(A)}constructor({handleStart:A,handleText:e,handleReferenceDoc:i,handleThink:t,handleEnd:n,handleError:o}){O(this,"handleStart",void 0),O(this,"handleText",void 0),O(this,"handleReferenceDoc",void 0),O(this,"handleThink",void 0),O(this,"handleEnd",void 0),O(this,"handleError",void 0),O(this,"controllerMap",void 0),this.handleStart=A,this.handleText=e,this.handleReferenceDoc=i,this.handleThink=t,this.handleEnd=n,this.handleError=o,this.controllerMap={}}}let b=({handleStart:A,handleText:e,handleReferenceDoc:i,handleThink:t,handleEnd:n,handleError:o,requestOptions:g}={})=>{let l="内容正在生成中...",a=(0,T.ref)(),M=(0,T.ref)({}),s=(0,T.ref)([]),N={},d=(0,T.computed)(()=>{let A=[];for(let e=s.value.length-1;e>=0;e--){let i=s.value[e],t=e+1,n=s.value[t];for(;n&&![u.Ai,u.TokenExpired,u.ImageNotSupported,u.Pause,u.Guide].includes(n.role);)t+=1,n=s.value[t];if(i.role===u.System)break;i.status===c.Fail||(null==n?void 0:n.status)===c.Fail&&[u.User,u.UserImage].includes(i.role)||[u.Time,u.System].includes(i.role)||A.unshift(i)}return A}),I=(0,T.computed)(()=>{var A;let e=null===(A=a.value)||void 0===A?void 0:A.sessionCode;return!!e&&M.value[e]}),D=(0,T.computed)(()=>{var A,e,i;let t=[],n=[],o=[],g=s.value.findLastIndex(A=>A.role===u.System&&["已启用角色","已启用模型"].some(e=>A.content.includes(e))),l=0;null===(i=a.value)||void 0===i||null===(e=i.roleInfo)||void 0===e||null===(A=e.content)||void 0===A||A.forEach(A=>{let e=s.value[g+1+l],i=s.value[g+2+l];if((null==e?void 0:e.content)===A.content&&e.role!==u.System&&(t.push(j(e)),l+=1,(null==e?void 0:e.role)===u.Pause)){for(;i&&i.role===u.System;)l+=1,i=s.value[g+1+l];for(;i&&[u.User,u.UserImage].includes(i.role);)t.push(j(i)),l+=1,i=s.value[g+1+l]}}),n.push(...d.value.map(j));let M=A=>{let e=!0;for(let o=A;o<t.length;o++){var i;t[o].content!==(null===(i=n[o-A])||void 0===i?void 0:i.content)&&(e=!1)}return e};for(let A=0;A<t.length;A++){let e=t[A];if(M(A))break;o.push(e)}return o.push(...n),o.forEach(A=>{A.content=m(A.content),A.content=z(A.content)}),o}),E=new f({handleStart:w,handleText:function(A,i,t){let n=B(A);if(n.content===l)n.content=i;else{if(n.status!==c.Loading)return;n.content=t?i:n.content+i}return null==e?void 0:e(A,n)},handleReferenceDoc:function(A,e,t){let n=B(A),o=h(e);return n.content=t?o:n.content+o,null==i?void 0:i(A,n)},handleThink:function(A,e,i,n){let o=B(A);return o.content=k(o.content,e,i,n),null==t?void 0:t(A,o)},handleEnd:function(A,e){let i=B(A);if(i.status===c.Loading)return M.value[A]=!1,e&&(i.content=e),i.status=c.Success,null==n?void 0:n(A,i);(i.content===l||x(i.content))&&v(A,"聊天内容已中断")},handleError:v});function B(A){var e,i;return(null===(e=a.value)||void 0===e?void 0:e.sessionCode)===A?s.value.at(-1):null===(i=N[A])||void 0===i?void 0:i.at(-1)}function C(A){var e;return(null===(e=a.value)||void 0===e?void 0:e.sessionCode)===A?s.value:N[A]}function Q(A,e){C(A).push(e)}function p(A,e,i){var t;let n=(null===(t=a.value)||void 0===t?void 0:t.sessionCode)===A?s.value:N[A],o=[];return e.forEach(A=>{let e=n.findIndex(e=>e.id===A);if(e>-1){let t=n[e-1],g=n[e+1],l=n[e+2];if(n.splice(e,1),o.push(A),[u.Hidden].includes(null==t?void 0:t.role)){let A=n.findIndex(A=>A.id===t.id);n.splice(A,1),o.push(t.id)}if((null==g?void 0:g.role)===u.Ai||i&&[u.Ai,u.Guide,u.TokenExpired,u.ImageNotSupported,u.Pause].includes(null==g?void 0:g.role)){let A=n.findIndex(A=>A.id===g.id);n.splice(A,1),o.push(g.id)}if([u.Guide].includes(null==l?void 0:l.role)&&i){let A=n.findIndex(A=>A.id===l.id);n.splice(A,1),o.push(l.id)}}}),o}function w(e){M.value[e]=!0;let i={sessionCode:e,role:u.Ai,status:c.Loading,content:l};return Q(e,i),null==A?void 0:A(e,i)}function v(A,e,i){let t=B(A);return t.status=c.Fail,t.content=e,M.value[A]=!1,i===r.TokenExpired&&(t.content="抱歉,您的剩余 Token 不足,无法返回回答内容,请先清空当前会话(上下文仍会作为历史记录保留))",t.role=u.TokenExpired),i===r.ImageNotSupported&&(t.content="抱歉,当前模型不支持图片内容解析",t.role=u.ImageNotSupported),null==o?void 0:o(A,t,i)}function L(A,e){var i,t,n;if(!(null===(i=a.value)||void 0===i?void 0:i.sessionCode)||!(null==g?void 0:g.url)||I.value)return;let{message:o,cite:l,shortcut:M}=A,r="";r=M?y(M.prompt,l):l?`${o}: "${l}"`:o,s.value.push({sessionCode:null===(t=a.value)||void 0===t?void 0:t.sessionCode,content:o,role:u.User,status:c.Success,cite:l}),E.stream({sessionCode:null===(n=a.value)||void 0===n?void 0:n.sessionCode,url:g.url,headers:null==g?void 0:g.headers,data:{inputs:{chat_history:D.value.slice(0,D.value.length-1),input:r}}}),null==e||e()}return{currentSession:a,sessionContents:s,sessionContentsMap:N,sessionLoadingMap:M,prompts:D,currentSessionLoading:I,chat:function({sessionCode:A,data:e,url:i,headers:t}){E.stream({sessionCode:A,url:i,data:e,headers:t||(null==g?void 0:g.headers)})},sendChat:L,stopChat:function(A){E.stop(A)},plusSessionContent:Q,updateSessionContent:function(A){var e;let i=((null===(e=a.value)||void 0===e?void 0:e.sessionCode)===A.sessionCode?s.value:N[A.sessionCode]).find(e=>+(e.id||0)==+(A.id||0));i&&Object.assign(i,A)},getSessionContentById:function(A,e){return C(e).find(e=>e.id===A)},getLastSessionContentBySessionCode:B,getSessionContentsBySessionCode:C,setCurrentSession:function(A){a.value=A,(null==A?void 0:A.sessionCode)&&(N[A.sessionCode]||(N[A.sessionCode]=[]),s.value=N[A.sessionCode])},setSessionContents:function(A){a.value&&(N[a.value.sessionCode]=A,s.value=A)},deleteSessionContent:function(A,e){return p(A,[e],!0)},deleteSessionContents:function(A,e){return p(A,e,!1)},handleStartChat:w,handleErrorChat:v,reGenerateChat:function(A){if(s.value[A].role!==u.Ai)return;let e=s.value[A-1].content,i=s.value[A-1].cite;s.value.splice(A-1,s.value.length-A+1),L({message:e,cite:i})},reSendChat:function(A,{message:e,cite:i},t){s.value[A].role===u.User&&(s.value.splice(A,s.value.length-A),L({message:e,cite:i},t))},deleteChat:function(A){if(s.value[A].role===u.User){s.value.splice(A,2);return}s.value.splice(A-1,2)}}},S=({handleStart:A,handleEnd:e,handleError:i}={})=>{let t="",n=new f({handleStart:()=>(t="",null==A?void 0:A()),handleText:(A,e,i)=>{i||"正在思考..."===t?t=e:t+=e},handleEnd:()=>("无话可说"===t&&(t=""),null==e?void 0:e(t)),handleError:(A,e,t)=>null==i?void 0:i(e,t)});return{summary:({content:A,url:e,headers:i,model:t})=>{let o=m(z(A)),g=[{role:s.User,content:`你是一个总结大师,请帮助我对下面这段话进行总结。要求总结精炼,不超过 15 个字!且末尾没有标点符号!请注意:如果你无法总结,请回复“无话可说”!
246
+ }`;(A=document.createElement("style")).textContent=e,document.head.appendChild(A)},i=()=>{A&&(A.remove(),A=null)};(0,T.onBeforeMount)(()=>{e()}),(0,T.onBeforeUnmount)(()=>{i()})};function L(A,e,i,t,n,o,g){try{var l=A[o](g),a=l.value}catch(A){i(A);return}l.done?e(a):Promise.resolve(a).then(t,n)}function Y(A){return function(){var e=this,i=arguments;return new Promise(function(t,n){var o=A.apply(e,i);function g(A){L(o,t,n,g,l,"next",A)}function l(A){L(o,t,n,g,l,"throw",A)}g(void 0)})}}function O(A,e,i){return e in A?Object.defineProperty(A,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):A[e]=i,A}class f{stream({sessionCode:A,url:e,headers:i,data:t}){var n=this;return Y(function*(){var o,g;yield null===(o=n.handleStart)||void 0===o?void 0:o.call(n,A);let l=new AbortController;n.controllerMap[A]=l,fetch(e,{method:"post",signal:l.signal,headers:function(A){for(var e=1;e<arguments.length;e++){var i=null!=arguments[e]?arguments[e]:{},t=Object.keys(i);"function"==typeof Object.getOwnPropertySymbols&&(t=t.concat(Object.getOwnPropertySymbols(i).filter(function(A){return Object.getOwnPropertyDescriptor(i,A).enumerable}))),t.forEach(function(e){O(A,e,i[e])})}return A}({"Content-Type":"application/json"},i),mode:"cors",credentials:"include",body:JSON.stringify(t)}).then((g=Y(function*(e){let i=e.body.pipeThrough(new window.TextDecoderStream).getReader(),t="";for(;;)try{let{value:o,done:g}=yield i.read();if(!e.ok){n.handleError(A,o||e.statusText,e.status);break}if(g){n.handleEnd(A);break}(t+o.toString()).split("\n").forEach(i=>{let o=i.replace("data:","").trim();if(C(o)){var g,l;let{event:i,content:a,cover:M,documents:s,result:c,code:u,elapsed_time:r,message:N}=JSON.parse(o);if(!1===c||200!==e.status){n.handleError(A,N||"模型调用失败",u);return}switch(i){case"text":n.handleText(A,a,M);break;case"reference_doc":null===(g=n.handleReferenceDoc)||void 0===g||g.call(n,A,s,M);break;case"think":null===(l=n.handleThink)||void 0===l||l.call(n,A,a,M,r);break;case"done":n.handleEnd(A,M?a:"");break;case"error":n.handleError(A,N||"模型调用失败",u)}t=""}else o&&(t=o)})}catch(e){(null==e?void 0:e.code)!==20&&n.handleError(A,`模型调用失败:${e.message}`,e.code);break}}),function(A){return g.apply(this,arguments)}))})()}stop(A){var e,i;return null===(i=this.controllerMap[A])||void 0===i||null===(e=i.abort)||void 0===e||e.call(i),this.handleEnd(A)}constructor({handleStart:A,handleText:e,handleReferenceDoc:i,handleThink:t,handleEnd:n,handleError:o}){O(this,"handleStart",void 0),O(this,"handleText",void 0),O(this,"handleReferenceDoc",void 0),O(this,"handleThink",void 0),O(this,"handleEnd",void 0),O(this,"handleError",void 0),O(this,"controllerMap",void 0),this.handleStart=A,this.handleText=e,this.handleReferenceDoc=i,this.handleThink=t,this.handleEnd=n,this.handleError=o,this.controllerMap={}}}let b=({handleStart:A,handleText:e,handleReferenceDoc:i,handleThink:t,handleEnd:n,handleError:o,requestOptions:g}={})=>{let l="内容正在生成中...",a=(0,T.ref)(),M=(0,T.ref)({}),s=(0,T.ref)([]),N={},d=(0,T.computed)(()=>{let A=[];for(let e=s.value.length-1;e>=0;e--){let i=s.value[e],t=e+1,n=s.value[t];for(;n&&![u.Ai,u.TokenExpired,u.ImageNotSupported,u.Pause,u.Guide].includes(n.role);)t+=1,n=s.value[t];if(i.role===u.System)break;i.status===c.Fail||(null==n?void 0:n.status)===c.Fail&&[u.User,u.UserImage].includes(i.role)||[u.Time,u.System].includes(i.role)||A.unshift(i)}return A}),I=(0,T.computed)(()=>{var A;let e=null===(A=a.value)||void 0===A?void 0:A.sessionCode;return!!e&&M.value[e]}),D=(0,T.computed)(()=>{var A,e,i;let t=[],n=[],o=[],g=s.value.findLastIndex(A=>A.role===u.System&&["已启用角色","已启用模型"].some(e=>A.content.includes(e))),l=0;null===(i=a.value)||void 0===i||null===(e=i.roleInfo)||void 0===e||null===(A=e.content)||void 0===A||A.forEach(A=>{let e=s.value[g+1+l],i=s.value[g+2+l];if((null==e?void 0:e.content)===A.content&&e.role!==u.System&&(t.push(j(e)),l+=1,(null==e?void 0:e.role)===u.Pause)){for(;i&&i.role===u.System;)l+=1,i=s.value[g+1+l];for(;i&&[u.User,u.UserImage].includes(i.role);)t.push(j(i)),l+=1,i=s.value[g+1+l]}}),n.push(...d.value.map(j));let M=A=>{let e=!0;for(let o=A;o<t.length;o++){var i;t[o].content!==(null===(i=n[o-A])||void 0===i?void 0:i.content)&&(e=!1)}return e};for(let A=0;A<t.length;A++){let e=t[A];if(M(A))break;o.push(e)}return o.push(...n),o.forEach(A=>{A.content=m(A.content),A.content=z(A.content)}),o}),E=new f({handleStart:w,handleText:function(A,i,t){let n=B(A);if(n.content===l)n.content=i;else{if(n.status!==c.Loading)return;n.content=t?i:n.content+i}return null==e?void 0:e(A,n)},handleReferenceDoc:function(A,e,t){let n=B(A),o=h(e);return n.content=t?o:n.content+o,null==i?void 0:i(A,n)},handleThink:function(A,e,i,n){let o=B(A);return o.content=k(o.content,e,i,n),null==t?void 0:t(A,o)},handleEnd:function(A,e){let i=B(A);if(i.status===c.Loading)return M.value[A]=!1,(i.content===l||x(i.content))&&v(A,"聊天内容已中断"),e&&(i.content=e),i.status=c.Success,null==n?void 0:n(A,i)},handleError:v});function B(A){var e,i;return(null===(e=a.value)||void 0===e?void 0:e.sessionCode)===A?s.value.at(-1):null===(i=N[A])||void 0===i?void 0:i.at(-1)}function C(A){var e;return(null===(e=a.value)||void 0===e?void 0:e.sessionCode)===A?s.value:N[A]}function Q(A,e){C(A).push(e)}function p(A,e,i){var t;let n=(null===(t=a.value)||void 0===t?void 0:t.sessionCode)===A?s.value:N[A],o=[];return e.forEach(A=>{let e=n.findIndex(e=>e.id===A);if(e>-1){let t=n[e-1],g=n[e+1],l=n[e+2];if(n.splice(e,1),o.push(A),[u.Hidden].includes(null==t?void 0:t.role)){let A=n.findIndex(A=>A.id===t.id);n.splice(A,1),o.push(t.id)}if((null==g?void 0:g.role)===u.Ai||i&&[u.Ai,u.Guide,u.TokenExpired,u.ImageNotSupported,u.Pause].includes(null==g?void 0:g.role)){let A=n.findIndex(A=>A.id===g.id);n.splice(A,1),o.push(g.id)}if([u.Guide].includes(null==l?void 0:l.role)&&i){let A=n.findIndex(A=>A.id===l.id);n.splice(A,1),o.push(l.id)}}}),o}function w(e){M.value[e]=!0;let i={sessionCode:e,role:u.Ai,status:c.Loading,content:l};return Q(e,i),null==A?void 0:A(e,i)}function v(A,e,i){let t=B(A);return t.status=c.Fail,t.content=e,M.value[A]=!1,i===r.TokenExpired&&(t.content="抱歉,您的剩余 Token 不足,无法返回回答内容,请先清空当前会话(上下文仍会作为历史记录保留))",t.role=u.TokenExpired),i===r.ImageNotSupported&&(t.content="抱歉,当前模型不支持图片内容解析",t.role=u.ImageNotSupported),null==o?void 0:o(A,t,i)}function L(A,e){var i,t,n;if(!(null===(i=a.value)||void 0===i?void 0:i.sessionCode)||!(null==g?void 0:g.url)||I.value)return;let{message:o,cite:l,shortcut:M}=A,r="";r=M?y(M.prompt,l):l?`${o}: "${l}"`:o,s.value.push({sessionCode:null===(t=a.value)||void 0===t?void 0:t.sessionCode,content:o,role:u.User,status:c.Success,cite:l}),E.stream({sessionCode:null===(n=a.value)||void 0===n?void 0:n.sessionCode,url:g.url,headers:null==g?void 0:g.headers,data:{inputs:{chat_history:D.value.slice(0,D.value.length-1),input:r}}}),null==e||e()}return{currentSession:a,sessionContents:s,sessionContentsMap:N,sessionLoadingMap:M,prompts:D,currentSessionLoading:I,chat:function({sessionCode:A,data:e,url:i,headers:t}){E.stream({sessionCode:A,url:i,data:e,headers:t||(null==g?void 0:g.headers)})},sendChat:L,stopChat:function(A){E.stop(A)},plusSessionContent:Q,updateSessionContent:function(A){var e;let i=((null===(e=a.value)||void 0===e?void 0:e.sessionCode)===A.sessionCode?s.value:N[A.sessionCode]).find(e=>+(e.id||0)==+(A.id||0));i&&Object.assign(i,A)},getSessionContentById:function(A,e){return C(e).find(e=>e.id===A)},getLastSessionContentBySessionCode:B,getSessionContentsBySessionCode:C,setCurrentSession:function(A){a.value=A,(null==A?void 0:A.sessionCode)&&(N[A.sessionCode]||(N[A.sessionCode]=[]),s.value=N[A.sessionCode])},setSessionContents:function(A){a.value&&(N[a.value.sessionCode]=A,s.value=A)},deleteSessionContent:function(A,e){return p(A,[e],!0)},deleteSessionContents:function(A,e){return p(A,e,!1)},handleStartChat:w,handleErrorChat:v,reGenerateChat:function(A){if(s.value[A].role!==u.Ai)return;let e=s.value[A-1].content,i=s.value[A-1].cite;s.value.splice(A-1,s.value.length-A+1),L({message:e,cite:i})},reSendChat:function(A,{message:e,cite:i},t){s.value[A].role===u.User&&(s.value.splice(A,s.value.length-A),L({message:e,cite:i},t))},deleteChat:function(A){if(s.value[A].role===u.User){s.value.splice(A,2);return}s.value.splice(A-1,2)}}},S=({handleStart:A,handleEnd:e,handleError:i}={})=>{let t="",n=new f({handleStart:()=>(t="",null==A?void 0:A()),handleText:(A,e,i)=>{i||"正在思考..."===t?t=e:t+=e},handleEnd:()=>("无话可说"===t&&(t=""),null==e?void 0:e(t)),handleError:(A,e,t)=>null==i?void 0:i(e,t)});return{summary:({content:A,url:e,headers:i,model:t})=>{let o=m(z(A)),g=[{role:s.User,content:`你是一个总结大师,请帮助我对下面这段话进行总结。要求总结精炼,不超过 15 个字!且末尾没有标点符号!请注意:如果你无法总结,请回复“无话可说”!
247
247
  文字如下:
248
248
  ${o}`}];n.stream({sessionCode:"summary",url:e,data:{prompts:g,model:t},headers:i})}}};I(86),I(84);let U=()=>{w(),v()},G=E.default;if("undefined"!=typeof window){let{currentScript:A}=window.document,e=A&&A.src.match(/(.+\/)[^/]+\.js(\?.*)?$/);e&&(I.p=e[1])}var R=D.eo,F=D.In,Z=D.c_,W=D.bJ,H=D.Ay,P=D.DA,J=D.Y_,X=D.a2,K=D.X3,_=D.S0;export{R as HttpErrorCode,F as SessionContentRole,Z as SessionContentStatus,W as SessionPromptRole,H as default,P as transferSessionContent2SessionPrompt,J as useChat,X as useClickProxy,K as useStyle,_ as useSummary};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blueking/ai-ui-sdk",
3
- "version": "0.0.9-beta.1",
3
+ "version": "0.0.9-beta.2",
4
4
  "description": "蓝鲸AI UI SDK",
5
5
  "main": "dist/main.js",
6
6
  "types": "dist/main.d.ts",