@blueking/ai-ui-sdk 0.0.13 → 0.0.15-beta.1

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 (53) hide show
  1. package/README.md +290 -0
  2. package/dist/common/chart-helper.d.ts +1 -1
  3. package/dist/common/chart-helper.js +173 -0
  4. package/dist/common/util.d.ts +21 -0
  5. package/dist/common/util.js +143 -0
  6. package/dist/css/fonts/iconcool.eot +0 -0
  7. package/dist/css/fonts/iconcool.svg +53 -0
  8. package/dist/css/fonts/iconcool.ttf +0 -0
  9. package/dist/css/fonts/iconcool.woff +0 -0
  10. package/dist/css/iconcool.js +10 -0
  11. package/dist/css/style.css +43 -0
  12. package/dist/hooks/use-chat.d.ts +843 -18
  13. package/dist/hooks/use-chat.js +533 -0
  14. package/dist/hooks/use-click-proxy.js +77 -0
  15. package/dist/hooks/use-http.d.ts +15 -0
  16. package/dist/hooks/use-http.js +48 -0
  17. package/dist/hooks/use-reference-doc.d.ts +1 -1
  18. package/dist/hooks/use-reference-doc.js +185 -0
  19. package/dist/hooks/use-style.js +11 -0
  20. package/dist/hooks/use-summary.d.ts +1 -1
  21. package/dist/hooks/use-summary.js +55 -0
  22. package/dist/hooks/use-think.js +135 -0
  23. package/dist/http/fetch/error-interceptor.d.ts +3 -0
  24. package/dist/http/fetch/error-interceptor.js +6 -0
  25. package/dist/http/fetch/index.d.ts +25 -0
  26. package/dist/http/fetch/request-error.d.ts +6 -0
  27. package/dist/http/fetch/request-error.js +25 -0
  28. package/dist/http/fetch/success-interceptor.d.ts +3 -0
  29. package/dist/http/fetch/success-interceptor.js +92 -0
  30. package/dist/http/helper/knowledge.d.ts +43 -0
  31. package/dist/http/helper/knowledge.js +227 -0
  32. package/dist/http/helper/permission.d.ts +7 -0
  33. package/dist/http/helper/permission.js +28 -0
  34. package/dist/http/helper/session.d.ts +31 -0
  35. package/dist/http/helper/session.js +147 -0
  36. package/dist/http/helper/tool.d.ts +13 -0
  37. package/dist/http/helper/tool.js +49 -0
  38. package/dist/main.d.ts +12 -2
  39. package/dist/main.js +22 -239
  40. package/dist/types/enum.d.ts +36 -0
  41. package/dist/types/enum.js +101 -0
  42. package/dist/types/file.d.ts +13 -0
  43. package/dist/types/file.js +1 -0
  44. package/dist/types/knowledge.d.ts +133 -0
  45. package/dist/types/knowledge.js +1 -0
  46. package/dist/types/permission.d.ts +48 -0
  47. package/dist/types/permission.js +1 -0
  48. package/dist/types/{type.d.ts → session.d.ts} +84 -23
  49. package/dist/types/session.js +1 -0
  50. package/dist/types/tool.d.ts +60 -0
  51. package/dist/types/tool.js +1 -0
  52. package/package.json +3 -3
  53. package/dist/common/type-transform.d.ts +0 -7
package/README.md ADDED
@@ -0,0 +1,290 @@
1
+ # @blueking/ai-ui-sdk
2
+
3
+ 蓝鲸 AI UI SDK 是一个用于快速构建 AI 聊天界面的 Vue 3 组件库。该 SDK 提供了一系列易用的 Hooks 和工具,帮助开发者轻松集成 AI 对话、内容总结、样式管理等功能。
4
+
5
+ ## 安装
6
+
7
+ ```bash
8
+ npm install @blueking/ai-ui-sdk
9
+ # 或
10
+ yarn add @blueking/ai-ui-sdk
11
+ ```
12
+
13
+ ## 主要功能
14
+
15
+ ### 1. 聊天功能 (useChat)
16
+
17
+ `useChat` Hook 提供完整的聊天会话管理能力,包括发送消息、接收回复、管理会话状态等功能。
18
+
19
+ #### 基本用法
20
+
21
+ ```typescript
22
+ import { useChat } from '@blueking/ai-ui-sdk';
23
+
24
+ const {
25
+ currentSession, // 当前会话信息
26
+ sessionContents, // 会话内容列表
27
+ sendChat, // 发送消息方法
28
+ stopChat, // 停止生成方法
29
+ setCurrentSession, // 设置当前会话
30
+ currentSessionLoading,// 当前会话加载状态
31
+ reGenerateChat, // 重新生成回复
32
+ reSendChat, // 重新发送消息
33
+ deleteChat, // 删除消息
34
+ } = useChat({
35
+ // 可选回调函数
36
+ handleStart: (sessionCode, sessionContent) => {
37
+ // 开始生成回复时的回调
38
+ },
39
+ handleText: (sessionCode, sessionContent) => {
40
+ // 接收到文本时的回调
41
+ },
42
+ handleEnd: (sessionCode, sessionContent) => {
43
+ // 生成完成时的回调
44
+ },
45
+ // 请求配置
46
+ requestOptions: {
47
+ url: 'https://your-api-endpoint.com',
48
+ headers: { /* 自定义请求头 */ }
49
+ }
50
+ });
51
+
52
+ // 设置当前会话
53
+ setCurrentSession({
54
+ sessionCode: 'session-1',
55
+ sessionName: 'My Chat',
56
+ model: 'gpt-3.5',
57
+ });
58
+
59
+ // 发送消息
60
+ sendChat({
61
+ message: '你好,AI 助手',
62
+ cite: '可选的引用内容',
63
+ });
64
+
65
+ // 停止生成回复
66
+ stopChat('session-1');
67
+ ```
68
+
69
+ ### 2. 内容总结 (useSummary)
70
+
71
+ `useSummary` Hook 提供文本内容自动总结功能。
72
+
73
+ ```typescript
74
+ import { useSummary } from '@blueking/ai-ui-sdk';
75
+
76
+ const { summary } = useSummary({
77
+ handleStart: () => {
78
+ // 开始总结时的回调
79
+ },
80
+ handleEnd: (summaryText) => {
81
+ // 总结完成时的回调,返回总结文本
82
+ },
83
+ handleError: (message, code) => {
84
+ // 出错时的回调
85
+ }
86
+ });
87
+
88
+ // 使用总结功能
89
+ summary({
90
+ content: '需要总结的长文本内容...',
91
+ url: 'https://your-summary-api.com',
92
+ headers: { /* 自定义请求头 */ },
93
+ model: 'gpt-3.5', // 可选的模型指定
94
+ });
95
+ ```
96
+
97
+ ### 3. 点击代理 (useClickProxy)
98
+
99
+ `useClickProxy` Hook 提供全局点击事件代理,用于处理代码块展开/收起、全屏显示、复制代码、下载文件等功能。
100
+
101
+ ```typescript
102
+ import { useClickProxy } from '@blueking/ai-ui-sdk';
103
+
104
+ // 在组件挂载前添加全局点击代理,卸载前自动移除
105
+ useClickProxy();
106
+ ```
107
+
108
+ ### 4. 样式管理 (useStyle)
109
+
110
+ `useStyle` Hook 用于引入和管理 SDK 所需的全局样式。在应用入口处调用一次即可。
111
+
112
+ ```typescript
113
+ import { useStyle } from '@blueking/ai-ui-sdk';
114
+
115
+ // 引入全局样式
116
+ useStyle();
117
+ ```
118
+
119
+ ## 类型定义
120
+
121
+ SDK 提供了丰富的类型定义,以支持 TypeScript 开发。
122
+
123
+ ### 会话类型
124
+
125
+ ```typescript
126
+ // 会话信息
127
+ interface ISession {
128
+ sessionCode: string; // 会话编码
129
+ sessionName: string; // 会话名称
130
+ model: string; // 使用的模型
131
+ roleInfo?: { // 角色信息(可选)
132
+ collectionId: number;
133
+ collectionName: string;
134
+ content: ISessionPrompt[];
135
+ variables: any[];
136
+ };
137
+ }
138
+
139
+ // 会话内容
140
+ interface ISessionContent {
141
+ id?: number; // 内容ID
142
+ role: SessionContentRole;// 角色类型
143
+ content: string; // 内容文本
144
+ status?: SessionContentStatus; // 状态
145
+ sessionCode: string; // 所属会话编码
146
+ cite?: string; // 引用内容
147
+ time?: string; // 时间戳
148
+ }
149
+
150
+ // 快捷方式
151
+ interface ShortCut {
152
+ label: string; // 显示文本
153
+ key: string; // 唯一标识
154
+ prompt: string; // 提示词模板
155
+ icon?: string; // 图标(可选)
156
+ }
157
+ ```
158
+
159
+ ### 枚举值
160
+
161
+ ```typescript
162
+ // 会话内容角色
163
+ enum SessionContentRole {
164
+ Ai = 'ai', // AI 回复
165
+ User = 'user', // 用户消息
166
+ System = 'system', // 系统消息
167
+ // ... 更多角色类型
168
+ }
169
+
170
+ // 会话内容状态
171
+ enum SessionContentStatus {
172
+ Fail = 'fail', // 失败
173
+ Loading = 'loading', // 加载中
174
+ Success = 'success', // 成功
175
+ }
176
+ ```
177
+
178
+ ## 完整示例
179
+
180
+ 下面是一个完整的使用示例,展示了如何在 Vue 3 组件中集成 SDK:
181
+
182
+ ```vue
183
+ <template>
184
+ <div class="chat-container">
185
+ <!-- 消息列表 -->
186
+ <div class="message-list">
187
+ <div v-for="message in sessionContents" :key="message.id" class="message">
188
+ <div class="avatar">
189
+ {{ message.role === 'user' ? '👤' : '🤖' }}
190
+ </div>
191
+ <div class="content">{{ message.content }}</div>
192
+ </div>
193
+ </div>
194
+
195
+ <!-- 输入框 -->
196
+ <div class="input-area">
197
+ <input
198
+ v-model="inputMessage"
199
+ @keyup.enter="handleSend"
200
+ placeholder="请输入消息..."
201
+ />
202
+ <button @click="handleSend" :disabled="currentSessionLoading">
203
+ {{ currentSessionLoading ? '生成中...' : '发送' }}
204
+ </button>
205
+ <button v-if="currentSessionLoading" @click="handleStop">停止</button>
206
+ </div>
207
+ </div>
208
+ </template>
209
+
210
+ <script setup lang="ts">
211
+ import { ref } from 'vue';
212
+ import { useChat, useStyle, useClickProxy } from '@blueking/ai-ui-sdk';
213
+
214
+ // 引入全局样式
215
+ useStyle();
216
+
217
+ // 添加点击代理
218
+ useClickProxy();
219
+
220
+ // 初始化聊天功能
221
+ const {
222
+ currentSession,
223
+ sessionContents,
224
+ sendChat,
225
+ stopChat,
226
+ setCurrentSession,
227
+ currentSessionLoading,
228
+ } = useChat({
229
+ handleStart: () => {
230
+ console.log('开始生成回复');
231
+ },
232
+ handleEnd: () => {
233
+ console.log('回复生成完成');
234
+ },
235
+ requestOptions: {
236
+ url: 'https://your-chat-api.com',
237
+ }
238
+ });
239
+
240
+ // 设置当前会话
241
+ setCurrentSession({
242
+ sessionCode: 'session-' + Date.now(),
243
+ sessionName: '新对话',
244
+ model: 'gpt-3.5',
245
+ });
246
+
247
+ const inputMessage = ref('');
248
+
249
+ // 发送消息
250
+ const handleSend = () => {
251
+ if (!inputMessage.value.trim()) return;
252
+
253
+ sendChat({
254
+ message: inputMessage.value,
255
+ });
256
+
257
+ inputMessage.value = '';
258
+ };
259
+
260
+ // 停止生成
261
+ const handleStop = () => {
262
+ if (currentSession.value?.sessionCode) {
263
+ stopChat(currentSession.value.sessionCode);
264
+ }
265
+ };
266
+ </script>
267
+ ```
268
+
269
+ ## 注意事项
270
+
271
+ 1. 确保在应用中只调用一次 `useStyle()` 以避免样式重复注入
272
+ 2. `useClickProxy()` 应在组件挂载前调用,会自动在组件卸载时移除事件监听
273
+ 3. 发送消息前必须通过 `setCurrentSession()` 设置当前会话
274
+ 4. 所有网络请求需要在 `requestOptions` 中配置正确的 API 地址
275
+
276
+ ## 高级功能
277
+
278
+ SDK 还提供了以下高级功能:
279
+
280
+ - 支持引用上下文进行提问
281
+ - 支持快捷操作菜单配置
282
+ - 支持代码块的展开/收起、全屏显示、复制、下载
283
+ - 支持响应内容的重新生成和删除
284
+ - 支持会话内容的自动滚动
285
+
286
+ ## 版本兼容性
287
+
288
+ - 需要 Vue 3.x
289
+ - TypeScript 4.x 或更高版本
290
+ - 现代浏览器(Chrome, Firefox, Safari, Edge)
@@ -1,4 +1,4 @@
1
- import type { Document } from '../types/type';
1
+ import type { Document } from '../types/session';
2
2
  type HandleStart = (sessionCode: string) => any;
3
3
  type HandleText = (sessionCode: string, message: string, cover?: boolean) => void;
4
4
  type HandleReferenceDoc = (sessionCode: string, documents: Document[], cover?: boolean) => void;
@@ -0,0 +1,173 @@
1
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
2
+ try {
3
+ var info = gen[key](arg);
4
+ var value = info.value;
5
+ } catch (error) {
6
+ reject(error);
7
+ return;
8
+ }
9
+ if (info.done) {
10
+ resolve(value);
11
+ } else {
12
+ Promise.resolve(value).then(_next, _throw);
13
+ }
14
+ }
15
+ function _async_to_generator(fn) {
16
+ return function() {
17
+ var self = this, args = arguments;
18
+ return new Promise(function(resolve, reject) {
19
+ var gen = fn.apply(self, args);
20
+ function _next(value) {
21
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
22
+ }
23
+ function _throw(err) {
24
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
25
+ }
26
+ _next(undefined);
27
+ });
28
+ };
29
+ }
30
+ function _define_property(obj, key, value) {
31
+ if (key in obj) {
32
+ Object.defineProperty(obj, key, {
33
+ value: value,
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true
37
+ });
38
+ } else {
39
+ obj[key] = value;
40
+ }
41
+ return obj;
42
+ }
43
+ function _object_spread(target) {
44
+ for(var i = 1; i < arguments.length; i++){
45
+ var source = arguments[i] != null ? arguments[i] : {};
46
+ var ownKeys = Object.keys(source);
47
+ if (typeof Object.getOwnPropertySymbols === "function") {
48
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
49
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
50
+ }));
51
+ }
52
+ ownKeys.forEach(function(key) {
53
+ _define_property(target, key, source[key]);
54
+ });
55
+ }
56
+ return target;
57
+ }
58
+ import { isJSON } from './util.js';
59
+ export class ChatHelper {
60
+ stream({ sessionCode, url, headers, data }) {
61
+ var _this = this;
62
+ return _async_to_generator(function*() {
63
+ var _this_handleStart, _this1;
64
+ // 开始
65
+ yield (_this_handleStart = (_this1 = _this).handleStart) === null || _this_handleStart === void 0 ? void 0 : _this_handleStart.call(_this1, sessionCode);
66
+ // 记录 controller
67
+ const controller = new AbortController();
68
+ _this.controllerMap[sessionCode] = controller;
69
+ // 发送请求
70
+ fetch(url, {
71
+ method: 'post',
72
+ signal: controller.signal,
73
+ headers: _object_spread({
74
+ 'Content-Type': 'application/json'
75
+ }, headers),
76
+ mode: 'cors',
77
+ credentials: 'include',
78
+ body: JSON.stringify(data)
79
+ }).then(function() {
80
+ var _ref = _async_to_generator(function*(response) {
81
+ const reader = response.body.pipeThrough(new window.TextDecoderStream()).getReader();
82
+ // 临时存储数据
83
+ let temp = '';
84
+ while(true){
85
+ try {
86
+ const { value, done } = yield reader.read();
87
+ // 接口异常处理
88
+ if (!response.ok) {
89
+ let message = value || response.statusText;
90
+ try {
91
+ const json = JSON.parse(message);
92
+ message = json.message || json.error.message || message;
93
+ } catch (error) {
94
+ console.error(error.message || error);
95
+ }
96
+ _this.handleError(sessionCode, message, response.status);
97
+ break;
98
+ }
99
+ // 接口完成
100
+ if (done) {
101
+ _this.handleEnd(sessionCode);
102
+ break;
103
+ }
104
+ const values = (temp + value.toString()).split('\n');
105
+ values.forEach((value)=>{
106
+ const item = value.replace('data:', '').trim();
107
+ if (isJSON(item)) {
108
+ const { event, content, cover, documents, result, code, elapsed_time, message } = JSON.parse(item);
109
+ // 业务错误处理
110
+ if (result === false || response.status !== 200) {
111
+ _this.handleError(sessionCode, message || '模型调用失败', code);
112
+ return;
113
+ }
114
+ switch(event){
115
+ case 'text':
116
+ _this.handleText(sessionCode, content, cover);
117
+ break;
118
+ case 'reference_doc':
119
+ var _this_handleReferenceDoc, _this1;
120
+ (_this_handleReferenceDoc = (_this1 = _this).handleReferenceDoc) === null || _this_handleReferenceDoc === void 0 ? void 0 : _this_handleReferenceDoc.call(_this1, sessionCode, documents, cover);
121
+ break;
122
+ case 'think':
123
+ var _this_handleThink, _this2;
124
+ (_this_handleThink = (_this2 = _this).handleThink) === null || _this_handleThink === void 0 ? void 0 : _this_handleThink.call(_this2, sessionCode, content, cover, elapsed_time);
125
+ break;
126
+ case 'done':
127
+ _this.handleEnd(sessionCode, cover ? content : '');
128
+ break;
129
+ case 'error':
130
+ _this.handleError(sessionCode, message || '模型调用失败', code);
131
+ break;
132
+ }
133
+ temp = '';
134
+ } else if (item) {
135
+ temp = item;
136
+ }
137
+ });
138
+ } catch (error) {
139
+ if ((error === null || error === void 0 ? void 0 : error.code) !== 20) {
140
+ _this.handleError(sessionCode, `模型调用失败:${error.message}`, error.code);
141
+ }
142
+ break;
143
+ }
144
+ }
145
+ });
146
+ return function(response) {
147
+ return _ref.apply(this, arguments);
148
+ };
149
+ }());
150
+ })();
151
+ }
152
+ stop(sessionCode) {
153
+ var _this_controllerMap_sessionCode_abort, _this_controllerMap_sessionCode;
154
+ (_this_controllerMap_sessionCode = this.controllerMap[sessionCode]) === null || _this_controllerMap_sessionCode === void 0 ? void 0 : (_this_controllerMap_sessionCode_abort = _this_controllerMap_sessionCode.abort) === null || _this_controllerMap_sessionCode_abort === void 0 ? void 0 : _this_controllerMap_sessionCode_abort.call(_this_controllerMap_sessionCode);
155
+ return this.handleEnd(sessionCode);
156
+ }
157
+ constructor({ handleStart, handleText, handleReferenceDoc, handleThink, handleEnd, handleError }){
158
+ _define_property(this, "handleStart", void 0);
159
+ _define_property(this, "handleText", void 0);
160
+ _define_property(this, "handleReferenceDoc", void 0);
161
+ _define_property(this, "handleThink", void 0);
162
+ _define_property(this, "handleEnd", void 0);
163
+ _define_property(this, "handleError", void 0);
164
+ _define_property(this, "controllerMap", void 0);
165
+ this.handleStart = handleStart;
166
+ this.handleText = handleText;
167
+ this.handleReferenceDoc = handleReferenceDoc;
168
+ this.handleThink = handleThink;
169
+ this.handleEnd = handleEnd;
170
+ this.handleError = handleError;
171
+ this.controllerMap = {};
172
+ }
173
+ }
@@ -1,9 +1,30 @@
1
+ /**
2
+ * 节流,每隔一段时间执行
3
+ * @param {*} fn 需要执行的函数
4
+ * @param {*} delay 延迟时间,默认200
5
+ * @returns
6
+ */
7
+ export declare const throttle: <T1, T2, R>(fn: (p1?: T1, p2?: T2) => R, delay?: number) => (p1?: T1, p2?: T2) => false | undefined;
1
8
  /**
2
9
  * 判断是否是 JSON 字符串
3
10
  * @param str 字符串
4
11
  * @returns 是否是 JSON 字符串
5
12
  */
6
13
  export declare const isJSON: (str: string) => boolean;
14
+ /**
15
+ * 检查是不是 object 类型
16
+ * @param item
17
+ * @returns {boolean}
18
+ */
19
+ export declare function isObject(item: any): boolean;
20
+ /**
21
+ * 深度合并多个对象
22
+ * @param objectArray 待合并列表
23
+ * @returns {object} 合并后的对象
24
+ */
25
+ export declare function deepMerge(...objectArray: object[]): any;
26
+ export declare const mergeStringWithoutLeadingSlash: (str1?: string, str2?: string) => string;
27
+ export declare const mergeStringWithoutLastSlash: (str1?: string, str2?: string) => string;
7
28
  /**
8
29
  * 响应时间格式化
9
30
  * @param val 待格式化时间,xxms
@@ -0,0 +1,143 @@
1
+ import { Message } from 'bkui-vue';
2
+ /**
3
+ * 节流,每隔一段时间执行
4
+ * @param {*} fn 需要执行的函数
5
+ * @param {*} delay 延迟时间,默认200
6
+ * @returns
7
+ */ export const throttle = (fn, delay = 200)=>{
8
+ let valid = true;
9
+ return function(p1, p2) {
10
+ if (!valid) {
11
+ return false;
12
+ }
13
+ valid = false;
14
+ setTimeout(()=>{
15
+ fn(p1, p2);
16
+ valid = true;
17
+ }, delay);
18
+ };
19
+ };
20
+ /**
21
+ * 判断是否是 JSON 字符串
22
+ * @param str 字符串
23
+ * @returns 是否是 JSON 字符串
24
+ */ export const isJSON = (str)=>{
25
+ try {
26
+ JSON.parse(str);
27
+ return true;
28
+ } catch (e) {
29
+ return false;
30
+ }
31
+ };
32
+ /**
33
+ * 检查是不是 object 类型
34
+ * @param item
35
+ * @returns {boolean}
36
+ */ export function isObject(item) {
37
+ return Object.prototype.toString.apply(item) === '[object Object]';
38
+ }
39
+ /**
40
+ * 深度合并多个对象
41
+ * @param objectArray 待合并列表
42
+ * @returns {object} 合并后的对象
43
+ */ export function deepMerge(...objectArray) {
44
+ return objectArray.reduce((acc, obj)=>{
45
+ Object.keys(obj || {}).forEach((key)=>{
46
+ const pVal = acc[key];
47
+ const oVal = obj[key];
48
+ if (isObject(pVal) && isObject(oVal)) {
49
+ acc[key] = deepMerge(pVal, oVal);
50
+ } else {
51
+ acc[key] = oVal;
52
+ }
53
+ });
54
+ return acc;
55
+ }, {});
56
+ }
57
+ // 合并字符串,如果是 / 开头就去掉它
58
+ export const mergeStringWithoutLeadingSlash = (str1 = '', str2 = '')=>{
59
+ const result = `${str1}/${str2}`;
60
+ if (result.startsWith('/')) {
61
+ return result.slice(1);
62
+ }
63
+ return result;
64
+ };
65
+ // 合并字符串,如果是 / 结尾就去掉它
66
+ export const mergeStringWithoutLastSlash = (str1 = '', str2 = '')=>{
67
+ const result = `${str1}/${str2}`;
68
+ if (result.endsWith('/')) {
69
+ return result.slice(0, -1);
70
+ }
71
+ return result;
72
+ };
73
+ /**
74
+ * 响应时间格式化
75
+ * @param val 待格式化时间,xxms
76
+ * @returns 格式化后的时间,xx小时xx分钟xx秒
77
+ */ export function durationFormatter(val) {
78
+ const hours = Math.floor(val / 3600000);
79
+ const minutes = Math.floor(val % 3600000 / 60000);
80
+ const seconds = Math.floor(val % 60000 / 1000);
81
+ const milliseconds = val % 1000;
82
+ const parts = [];
83
+ if (hours > 0) {
84
+ parts.push(`${hours}h`);
85
+ }
86
+ if (minutes > 0) {
87
+ parts.push(`${minutes}min`);
88
+ }
89
+ if (seconds > 0) {
90
+ parts.push(`${seconds}s`);
91
+ }
92
+ if (milliseconds > 0) {
93
+ parts.push(`${milliseconds.toFixed(2)}ms`);
94
+ }
95
+ return parts.join(' ');
96
+ }
97
+ /**
98
+ * 前端下载文件
99
+ * @param {*} source 文件内容
100
+ * @param {*} filename 文件名
101
+ */ export function handleDownLoad(source, filename = 'ai.txt') {
102
+ const downloadEl = document.createElement('a');
103
+ const blob = new Blob([
104
+ source
105
+ ]);
106
+ downloadEl.download = filename;
107
+ downloadEl.href = URL.createObjectURL(blob);
108
+ downloadEl.style.display = 'none';
109
+ document.body.appendChild(downloadEl);
110
+ downloadEl.click();
111
+ document.body.removeChild(downloadEl);
112
+ }
113
+ export const handleCopy = (text)=>{
114
+ const textarea = document.createElement('textarea');
115
+ textarea.value = text;
116
+ document.body.appendChild(textarea);
117
+ textarea.select();
118
+ document.execCommand('copy');
119
+ Message({
120
+ theme: 'success',
121
+ message: '复制成功'
122
+ });
123
+ document.body.removeChild(textarea);
124
+ };
125
+ /**
126
+ * 处理提示词模板,替换模板中的变量
127
+ * @param prompt 提示词模板
128
+ * @param selectedText 选中的文本
129
+ * @returns 处理后的提示词
130
+ */ export const processPromptTemplate = (prompt, selectedText)=>{
131
+ return prompt.replace(/\{\{\s*SELECTED_TEXT\s*\}\}/g, selectedText || '');
132
+ };
133
+ /**
134
+ * 获取全屏的父元素
135
+ * @param target 全屏按钮
136
+ * @returns 全屏的父元素
137
+ */ export const getFullScreenWrap = (target)=>{
138
+ let parentElement = target.parentElement;
139
+ while(parentElement && !(parentElement === null || parentElement === void 0 ? void 0 : parentElement.classList.contains('full-screen-wrap'))){
140
+ parentElement = parentElement === null || parentElement === void 0 ? void 0 : parentElement.parentElement;
141
+ }
142
+ return parentElement;
143
+ };
Binary file