@nickyzj2023/utils 1.0.71 → 1.0.73

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/dist/index.d.mts CHANGED
@@ -1,789 +1,815 @@
1
- //#region src/ai/chatCompletions/types.d.ts
2
- declare namespace ChatCompletions {
3
- type Model = {
4
- /** 模型名称(如果不传,会尝试从 /models 读取模型) */model?: string; /** API 基础地址 */
5
- baseUrl: string; /** API 密钥(本地模型可不传) */
6
- apiKey?: string;
7
- };
8
- type TextContent = {
9
- type: "text";
10
- text: string;
11
- };
12
- type ImageContent = {
13
- type: "image_url";
14
- image_url: {
15
- url: string;
16
- };
17
- };
18
- type AudioContent = {
19
- type: "input_audio";
20
- input_audio: {
21
- /** 使用公网可访问的音频文件 URL */url?: string; /** 使用 base64 */
22
- data?: string;
23
- format: string;
24
- };
25
- };
26
- type VideoContent = {
27
- type: "video_url";
28
- video_url: {
29
- url: string;
30
- };
31
- };
32
- type ContentPart = TextContent | ImageContent | AudioContent | VideoContent;
33
- type Message = {
34
- role: "system" | "user" | "assistant" | "tool" | "function"; /** 字节的思考字段 */
35
- reasoning_content?: string | null; /** OpenRouter的思考字段 */
36
- reasoning?: string | null;
37
- content: string | ContentPart[];
38
- name?: string;
39
- tool_calls?: ToolCall[];
40
- tool_call_id?: string;
41
- };
42
- type ToolCall = {
43
- id: string;
44
- type: "function";
45
- function: {
46
- name: string;
47
- arguments: string;
48
- };
49
- };
50
- type ToolDefinition = {
51
- type: "function";
52
- function: {
53
- name: string;
54
- description?: string;
55
- parameters?: Record<string, any>;
56
- };
57
- };
58
- type Usage = {
59
- prompt_tokens: number;
60
- completion_tokens: number;
61
- total_tokens: number;
62
- };
63
- /** 请求非流式 /chat/completions 的响应结果 */
64
- type Response = {
65
- id: string;
66
- object: "chat.completion";
67
- created: number;
68
- model: string;
69
- choices: Array<{
70
- index: number;
71
- message: Message;
72
- finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
73
- }>;
74
- usage: Usage;
75
- system_fingerprint?: string;
76
- };
77
- type ExtraBody = {
78
- /** 工具列表 */tools?: ToolDefinition[]; /** 工具调用函数表,key 为工具名,value 为函数 */
79
- toolHandlers?: Record<string, (args: any) => any | Promise<any>>; /** 是否使用流式传输,启用后函数返回异步迭代器 */
80
- stream?: boolean; /** 其他额外参数 */
81
- [key: string]: any;
82
- };
83
- /** 调用 chatCompletions 返回的结果,流式/非流式通用 */
84
- type Result = {
85
- /** 模型的最终回复内容(多模态时取所有 text 拼接) */content: string; /** Token 消耗情况 */
86
- usage: Usage; /** 原始响应中的其他字段 */
87
- [key: string]: any;
88
- };
89
- /** 流式响应中的单个 SSE 数据块(OpenAI 原始格式) */
90
- type StreamResponse = {
91
- id: string;
92
- object: "chat.completion.chunk";
93
- created: number;
94
- model: string;
95
- choices: Array<{
96
- index: number;
97
- delta: {
98
- role?: Message["role"];
99
- content?: string | null; /** 字节的思考字段 */
100
- reasoning_content?: string | null; /** OpenRouter的思考字段 */
101
- reasoning?: string | null;
102
- tool_calls?: Array<{
103
- index: number;
104
- id?: string;
105
- type?: "function";
106
- function?: {
107
- name?: string;
108
- arguments?: string;
109
- };
110
- }>;
111
- };
112
- finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
113
- }>;
114
- usage?: Usage;
115
- };
116
- /** 流式调用 chatCompletions 时迭代器产出的数据块 */
117
- type StreamChunk = {
118
- /** 模型流式返回的思考内容增量(仅在生成过程中出现) */reasoningContent?: string; /** 模型流式返回的内容增量(仅在生成过程中出现) */
119
- content?: string; /** Token 消耗情况(仅在最后一帧出现) */
120
- usage?: Usage;
121
- };
122
- }
123
- //#endregion
124
- //#region src/ai/chatCompletions/index.d.ts
125
- /**
126
- * 兼容 OpenAI API 的聊天补全函数
127
- * - 自动处理工具调用
128
- * - 同时支持普通响应和流式响应
129
- *
130
- * @param model 模型配置,包含 model、baseUrl、apiKey
131
- * @param messages OpenAI API 兼容的消息数组
132
- * @param extraBody 可选的额外参数,如 tools、toolHandlers、temperature、stream 等
133
- * @returns 普通模式下返回 `{ content, usage, ... }`;`stream: true` 时返回异步迭代器
134
- *
135
- * @example
136
- * // 最简调用
137
- * // 未填写模型名,会自动使用/v1/models的第一个模型
138
- * const { content, usage } = await chatCompletions(
139
- * { baseUrl: "http://127.0.0.1:11434/v1" },
140
- * [{ role: "user", content: "你好" }],
141
- * );
142
- * console.log(content); // "你好!有什么我可以帮你的吗?"
143
- * console.log(usage); // { prompt_tokens: 13, completion_tokens: 9, total_tokens: 22 }
144
- *
145
- * @example
146
- * // 工具调用
147
- * const { content, usage } = await chatCompletions(
148
- * { baseUrl: "http://127.0.0.1:11434/v1", model: "model.gguf", apiKey: "sk-local-no-need-key" },
149
- * [{ role: "user", content: "查询上海天气" }],
150
- * {
151
- * tools: [{
152
- * type: "function",
153
- * function: {
154
- * name: "getWeather",
155
- * description: "查询城市天气情况",
156
- * parameters: { type: "object", properties: { city: { type: "string" } } },
157
- * },
158
- * }],
159
- * toolHandlers: {
160
- * getWeather: (args) => `${args.city}今日晴转多云,25°C`,
161
- * },
162
- * },
163
- * );
164
- *
165
- * @example
166
- * // 流式传输
167
- * const result = await chatCompletions(
168
- * { baseUrl: "http://127.0.0.1:11434/v1" },
169
- * [{ role: "user", content: "你好" }],
170
- * { stream: true },
171
- * );
172
- * for await (const { content, usage } of result) {
173
- * if (content) {
174
- * console.log("流式传输中:", content);
175
- * } else if (usage) {
176
- * console.log("对话结束,消耗:", usage);
177
- * }
178
- * }
179
- */
180
- declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody: ChatCompletions.ExtraBody & {
181
- stream: true;
182
- }): Promise<AsyncGenerator<ChatCompletions.StreamChunk>>;
183
- declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody?: ChatCompletions.ExtraBody): Promise<ChatCompletions.Result>;
184
- /**
185
- * 辅助定义一个 chatCompletions 支持的模型配置
186
- */
187
- declare const defineModel: (config: ChatCompletions.Model) => ChatCompletions.Model;
188
- //#endregion
189
- //#region src/dom/log.d.ts
190
- /**
191
- * log 配置选项
192
- */
193
- interface LogOptions {
194
- /**
195
- * 是否显示时间
196
- * @default true
197
- */
198
- time?: boolean;
199
- /**
200
- * 是否显示调用者文件名
201
- * @default true
202
- */
203
- fileName?: boolean;
204
- }
205
- /**
206
- * 带额外信息的 console.log
207
- * @param message - 日志消息,支持单条消息或消息数组
208
- * @param options - 配置选项
209
- *
210
- * @example
211
- * log("调试信息"); // "[14:30:00] [index.ts:15] 调试信息"
212
- * log("调试信息", { time: false }); // "[index.ts:15] 调试信息"
213
- * log("调试信息", { fileName: false }); // "[14:30:00] 调试信息"
214
- * log("调试信息", { time: false, fileName: false }); // "调试信息"
215
- * log(["消息1", "消息2"]); // "[14:30:00] [index.ts:15] 消息1 消息2"
216
- */
217
- declare const log: (message: any | any[], options?: LogOptions) => void;
218
- //#endregion
219
- //#region src/function/loop-until.d.ts
220
- /**
221
- * 循环执行函数,直到符合停止条件
222
- *
223
- * @example
224
- * // 循环请求大语言模型,直到其不再调用工具
225
- * loopUntil(
226
- * async () => {
227
- * const completion = await chatCompletions();
228
- * completion.tool_calls?.forEach(chooseAndHandleTool)
229
- * return completion;
230
- * },
231
- * {
232
- * shouldStop: (completion) => !completion.tool_calls,
233
- * },
234
- * ),
235
- *
236
- * @example
237
- * // 不传递 shouldStop,执行 3 次后正常返回最后结果
238
- * loopUntil(
239
- * () => {
240
- * return doSomething();
241
- * },
242
- * {
243
- * maxRetries: 3,
244
- * },
245
- * ),
246
- */
247
- declare const loopUntil: <T>(fn: (count: number) => T | Promise<T>, options?: {
248
- /**
249
- * 最大循环次数
250
- * @default 5
251
- */
252
- maxRetries?: number; /** 停止循环条件。如果未传递,则执行 maxRetries 次后退出并返回最后结果 */
253
- shouldStop?: (result: T) => boolean;
254
- }) => Promise<T>;
255
- //#endregion
256
- //#region src/hoc/with-cache.d.ts
257
- type SetTtl = (seconds: number) => void;
258
- /**
259
- * 创建一个带缓存的高阶函数
260
- *
261
- * @template Args 被包装函数的参数类型数组
262
- * @template Result 被包装函数的返回类型
263
- *
264
- * @param fn 需要被缓存的函数,参数里附带的 setTtl 方法用于根据具体情况改写过期时间
265
- * @param ttlSeconds 以秒为单位的过期时间,-1 表示永不过期,默认 -1,会被回调函数里的 setTtl() 覆盖
266
- *
267
- * @returns 返回包装后的函数,以及缓存相关的额外方法
268
- *
269
- * @example
270
- * // 异步函数示例
271
- * const fetchData = withCache(async function (url: string) {
272
- * const data = await fetch(url).then((res) => res.json());
273
- * this.setTtl(data.expiresIn); // 根据实际情况调整过期时间
274
- * return data;
275
- * });
276
- *
277
- * await fetchData(urlA);
278
- * await fetchData(urlA); // 使用缓存结果
279
- * await fetchData(urlB);
280
- * await fetchData(urlB); // 使用缓存结果
281
- *
282
- * fetchData.clear(); // 清除缓存
283
- * await fetchData(urlA); // 重新请求
284
- * await fetchData(urlB); // 重新请求
285
- *
286
- * // 缓存过期前
287
- * await sleep();
288
- * fetchData.updateTtl(180); // 更新 ttl 并为所有未过期的缓存续期
289
- * await fetchData(urlA); // 使用缓存结果
290
- * await fetchData(urlB); // 使用缓存结果
291
- */
292
- declare const withCache: <Args extends any[], Result>(fn: (this: {
293
- setTtl: SetTtl;
294
- }, ...args: Args) => Result, ttlSeconds?: number) => {
295
- (...args: Args): Result;
296
- clear(): void;
297
- updateTtl(seconds: number): void;
298
- };
299
- //#endregion
300
- //#region src/is/is-nil.d.ts
301
- /**
302
- * 检测传入的值是否为**空值**(null、undefined)
303
- *
304
- * @example
305
- * isNil(null); // true
306
- * isNil(undefined); // true
307
- * isNil(1); // false
308
- */
309
- declare const isNil: (value: any) => value is null | undefined;
310
- //#endregion
311
- //#region src/is/is-object.d.ts
312
- /**
313
- * 检测传入的值是否为**普通对象**
314
- *
315
- * @example
316
- * const obj = { a: 1 };
317
- * isObject(obj); // true
318
- */
319
- declare const isObject: (value: any) => value is Record<string, any>;
320
- //#endregion
321
- //#region src/is/is-primitive.d.ts
322
- type Primitive = number | string | boolean | symbol | bigint | undefined | null;
323
- /**
324
- * 检测传入的值是否为**原始值**(number、string、boolean、symbol、bigint、undefined、null)
325
- *
326
- * @example
327
- * isPrimitive(1); // true
328
- * isPrimitive([]); // false
329
- */
330
- declare const isPrimitive: (value: any) => value is Primitive;
331
- //#endregion
332
- //#region src/network/fetcher.d.ts
333
- type RequestInit = globalThis.RequestInit & {
334
- /**
335
- * searchParams 查询参数对象
336
- */
337
- params?: Record<string, any>;
338
- /**
339
- * 响应解析器,默认的解析方法为 response.json()
340
- */
341
- parser?: (response: Response) => Promise<any>;
342
- };
343
- /**
344
- * 基于 Fetch API 的请求实例
345
- * @param baseUrl 接口前缀
346
- * @param baseOptions 应用于整个实例的请求体,后续请求都会带上
347
- *
348
- * @remarks
349
- * 特性:
350
- * - 支持在创建实例、发出请求时合并相同的请求体(后者覆盖前者)
351
- * - 支持在 GET 的 params 请求体中传递对象
352
- * - 支持在 POST、PUT 的 body 请求体中传递对象
353
- * - 可选 to() 函数转换请求结果为 [Error, Response]
354
- * - 可选 withCache() 函数缓存请求结果
355
- *
356
- * @example
357
- * // 直接发请求
358
- * const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world", {
359
- * params: {
360
- * page: 2,
361
- * pageSize: 10,
362
- * }
363
- * });
364
- *
365
- * // 创建实例,发请求
366
- * const api = fetcher("https://nickyzj.run:3030", {
367
- * headers: {
368
- * Authorization: "Bearer token"
369
- * }
370
- * });
371
- * const res = await api.get<Blog>("/blogs/hello-world");
372
- *
373
- * // 安全返回请求结果,不抛异常
374
- * const [error, data] = await to(api.get<Blog>("/blogs/hello-world"));
375
- * if (error) {
376
- * // ...
377
- * }
378
- * // ...
379
- *
380
- * // 缓存请求结果
381
- * const getBlogs = withCache(api.get);
382
- * await getBlogs("/blogs");
383
- * await getBlogs("/blogs"); // 不发请求,使用缓存
384
- */
385
- declare const fetcher: (baseUrl?: string, baseOptions?: RequestInit) => {
386
- get: <T>(url: string, options?: Omit<RequestInit, "method">) => Promise<T>;
387
- post: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
388
- put: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
389
- delete: <T>(url: string, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
390
- };
391
- //#endregion
392
- //#region src/network/get-real-url.d.ts
393
- /** url 响应头获取真实链接 */
394
- declare const getRealURL: (originURL: string) => Promise<string>;
395
- //#endregion
396
- //#region src/network/image.d.ts
397
- /**
398
- * 图片压缩选项
399
- */
400
- type ImageCompressionOptions = {
401
- /** 压缩比率,默认 0.92 */quality?: number;
402
- /**
403
- * 自定义压缩函数,用于覆盖默认压缩行为
404
- * @param arrayBuffer 图片的 ArrayBuffer 数据
405
- * @param mime 图片的 MIME 类型
406
- * @param quality 压缩质量
407
- * @returns 压缩后的 base64 字符串
408
- */
409
- compressor?: (arrayBuffer: ArrayBuffer, mime: string, quality: number) => Promise<string> | string;
410
- /**
411
- * 自定义 fetch 函数,用于使用自己封装的请求库读取图片
412
- * 必须返回符合 Web 标准的 Response 对象
413
- * @param url 图片地址
414
- * @returns Promise<Response>
415
- */
416
- fetcher?: (url: string) => Promise<Response>;
417
- };
418
- /**
419
- * 图片地址转 base64 数据
420
- *
421
- * @param imageUrl 图片地址
422
- * @param options 可选配置
423
- * @param options.quality 压缩比率,默认 0.92
424
- * @param options.compressor 自定义压缩函数,用于覆盖默认压缩行为
425
- *
426
- * @example
427
- * // 基本用法(浏览器自动使用 Canvas 压缩,Node.js 自动检测并使用 sharp)
428
- * imageUrlToBase64("https://example.com/image.jpg");
429
- *
430
- * @example
431
- * // 使用自定义 fetch 函数(如 axios 封装)
432
- * imageUrlToBase64("https://example.com/image.jpg", {
433
- * fetcher: async (url) => {
434
- * // 使用 axios 或其他请求库,但必须返回 Response 对象
435
- * const response = await axios.get(url, { responseType: 'arraybuffer' });
436
- * return new Response(response.data, {
437
- * status: response.status,
438
- * statusText: response.statusText,
439
- * headers: response.headers
440
- * });
441
- * }
442
- * });
443
- *
444
- * @example
445
- * // 使用自定义压缩函数覆盖默认行为
446
- * imageUrlToBase64("https://example.com/image.jpg", {
447
- * quality: 0.8,
448
- * compressor: async (buffer, mime, quality) => {
449
- * // 自定义压缩逻辑
450
- * return `data:${mime};base64,...`;
451
- * }
452
- * });
453
- */
454
- declare const imageUrlToBase64: (imageUrl: string, options?: ImageCompressionOptions) => Promise<string>;
455
- //#endregion
456
- //#region src/network/to.d.ts
457
- /**
458
- * Go 语言风格的异步处理方式
459
- * @param promise 一个能被 await 的异步函数
460
- * @returns 如果成功,返回 [null, 异步函数结果],否则返回 [Error, undefined]
461
- *
462
- * @example
463
- * const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
464
- */
465
- declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E, undefined]>;
466
- //#endregion
467
- //#region src/number/random-int.d.ts
468
- /**
469
- * 在指定闭区间内生成随机整数
470
- *
471
- * @example
472
- * randomInt(1, 10); // 1 <= x <= 10
473
- */
474
- declare const randomInt: (min: number, max: number) => number;
475
- //#endregion
476
- //#region src/object/map.d.ts
477
- type DeepMapKeys<T> = T extends Array<infer U> ? Array<DeepMapKeys<U>> : T extends object ? {
478
- [key: string]: DeepMapKeys<T[keyof T]>;
479
- } : T;
480
- /**
481
- * 递归处理对象里的 key
482
- *
483
- * @remarks
484
- * 无法完整推导出类型,只能做到有递归,key 全为 string,value 为同层级的所有类型的联合
485
- *
486
- * @template T 要转换的对象
487
- *
488
- * @example
489
- * const obj = { a: { b: 1 } };
490
- * const result = mapKeys(obj, (key) => key.toUpperCase());
491
- * console.log(result); // { A: { B: 1 } }
492
- */
493
- declare const mapKeys: <T>(obj: T, getNewKey: (key: string) => string) => DeepMapKeys<T>;
494
- type DeepMapValues<T, R> = T extends Array<infer U> ? Array<DeepMapValues<U, R>> : T extends object ? { [K in keyof T]: T[K] extends object ? DeepMapValues<T[K], R> : R } : R;
495
- /**
496
- * 递归处理对象里的 value
497
- *
498
- * @remarks
499
- * 无法完整推导出类型,所有 value 最终都会变为 any
500
- *
501
- * @template T 要转换的对象
502
- * @template R 转换后的值类型,为 any,无法进一步推导
503
- *
504
- * @example
505
- * const obj = { a: 1, b: { c: 2 } };
506
- * const result = mapValues(obj, (value, key) => isPrimitive(value) ? value + 1 : value);
507
- * console.log(result); // { a: 2, b: { c: 3 } }
508
- */
509
- declare const mapValues: <T, R = any>(obj: T, getNewValue: (value: any, key: string | number) => R, options?: {
510
- /** 过滤函数,返回 true 表示保留该字段 */filter?: (value: any, key: string | number) => boolean;
511
- }) => DeepMapValues<T, R>;
512
- //#endregion
513
- //#region src/object/merge.d.ts
514
- /**
515
- * 深度合并两个对象,规则如下:
516
- * 1. 原始值覆盖:如果两个值都是原始类型,则用后者覆盖;
517
- * 2. 数组拼接:如果两个值都是数组,则拼接为大数组;
518
- * 3. 对象递归合并:如果两个值都是对象,则进行递归深度合并;
519
- *
520
- * @template T 第一个对象
521
- * @template U 第二个对象
522
- * @param {T} obj1 要合并的第一个对象,相同字段会被 obj2 覆盖
523
- * @param {U} obj2 要合并的第二个对象
524
- */
525
- declare const mergeObjects: <T extends Record<string, any>, U extends Record<string, any>>(obj1: T, obj2: U) => T & U;
526
- //#endregion
527
- //#region src/object/omit.d.ts
528
- /**
529
- * 从对象中排除指定的键,返回不包含这些键的新对象
530
- *
531
- * @typeParam T - 源对象的类型
532
- * @typeParam K - 要排除的键,必须是源对象的键之一
533
- *
534
- * @param obj - 源对象
535
- * @param keys - 要排除的键名数组
536
- * @returns 不包含指定键的新对象
537
- *
538
- * @example
539
- * const user = {
540
- * id: 1,
541
- * name: "Alice",
542
- * age: 25,
543
- * password: "secret"
544
- * };
545
- * // { id: 1, name: "Alice", age: 25 }
546
- * const safeUser = omit(user, ["password"]);
547
- */
548
- declare const omit: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Omit<T, K>;
549
- /**
550
- * 从对象中排除满足条件的键值对,返回不包含这些键的新对象
551
- *
552
- * @typeParam T - 源对象的类型
553
- *
554
- * @param obj - 源对象
555
- * @param shouldOmit - 判断函数,接收键和值,返回 `true` 则排除该键值对
556
- * @returns 不包含满足条件的键值对的新对象
557
- *
558
- * @example
559
- * const user = {
560
- * id: 1,
561
- * name: "Alice",
562
- * age: 25,
563
- * password: "secret"
564
- * };
565
- * // { name: "Alice", password: "secret" }
566
- * const stringFields = omitBy(user, (key, value) => typeof value === "number");
567
- */
568
- declare const omitBy: <T extends Record<string, any>>(obj: T, shouldOmit: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
569
- //#endregion
570
- //#region src/object/pick.d.ts
571
- /**
572
- * 从对象中选取指定的键,返回仅包含这些键的新对象
573
- *
574
- * @typeParam T - 源对象的类型
575
- * @typeParam K - 要选取的键,必须是源对象的键之一
576
- *
577
- * @param obj - 源对象
578
- * @param keys - 要选取的键名数组
579
- * @returns 仅包含指定键的新对象
580
- *
581
- * @example
582
- * const user = {
583
- * id: 1,
584
- * name: "Alice",
585
- * age: 25,
586
- * password: "secret"
587
- * };
588
- * // { id: 1, name: "Alice", age: 25 }
589
- * const safeUser = pick(user, ["id", "name", "age"]);
590
- */
591
- declare const pick: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Pick<T, K>;
592
- /**
593
- * 从对象中选取满足条件的键值对,返回仅包含这些键的新对象
594
- *
595
- * @typeParam T - 源对象的类型
596
- *
597
- * @param obj - 源对象
598
- * @param shouldPick - 判断函数,返回 `true` 时保留该字段
599
- * @returns 仅包含满足条件的键值对的新对象
600
- *
601
- * @example
602
- * const user = {
603
- * id: 1,
604
- * name: "Alice",
605
- * age: 25,
606
- * password: "secret"
607
- * };
608
- * // { id: 1, age: 25 }
609
- * const numericFields = pickBy(user, (key, value) => typeof value === "number");
610
- */
611
- declare const pickBy: <T extends Record<string, any>>(obj: T, shouldPick: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
612
- //#endregion
613
- //#region src/string/case.d.ts
614
- type SnakeToCamel<S extends string> = S extends `${infer Before}_${infer After}` ? After extends `${infer First}${infer Rest}` ? `${Before}${Uppercase<First>}${SnakeToCamel<Rest>}` : Before : S;
615
- /**
616
- * 下划线命名法转为驼峰命名法
617
- *
618
- * @example
619
- * snakeToCamel("user_name") // "userName"
620
- */
621
- declare const snakeToCamel: <S extends string>(str: S) => SnakeToCamel<S>;
622
- type CamelToSnake<S extends string> = S extends `${infer First}${infer Rest}` ? Rest extends Uncapitalize<Rest> ? `${Lowercase<First>}${CamelToSnake<Rest>}` : `${Lowercase<First>}_${CamelToSnake<Rest>}` : Lowercase<S>;
623
- /**
624
- * 驼峰命名法转为下划线命名法
625
- *
626
- * @example
627
- * camelToSnake("shouldComponentUpdate") // "should_component_update"
628
- */
629
- declare const camelToSnake: <S extends string>(str: S) => CamelToSnake<S>;
630
- type Capitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Capitalize<P1> ? S : `${Uppercase<P1>}${Rest}` : S;
631
- /**
632
- * 字符串首字母大写
633
- *
634
- * @example
635
- * capitalize("hello") // "Hello"
636
- */
637
- declare const capitalize: <S extends string>(s: S) => Capitalize<S>;
638
- type Decapitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Lowercase<P1> ? P1 : `${Lowercase<P1>}${Rest}` : S;
639
- /**
640
- * 字符串首字母小写
641
- *
642
- * @example
643
- * decapitalize("Hello") // "hello"
644
- */
645
- declare const decapitalize: <S extends string>(s: S) => Decapitalize<S>;
646
- //#endregion
647
- //#region src/string/compact.d.ts
648
- /**
649
- * 将字符串压缩为单行精简格式
650
- *
651
- * @example
652
- * // "Hello\nworld"
653
- * compactStr(`Hello,
654
- *
655
- * world
656
- *
657
- * !`);
658
- *
659
- * @example
660
- * // "Hello...world"
661
- * compactStr("Hello, beautiful world!", { maxLength: 15 });
662
- */
663
- declare const compactStr: (text?: string, options?: {
664
- /**
665
- * 最大保留长度,超过该长度使用 "..." 替代
666
- @default Infinity
667
- */
668
- maxLength?: number;
669
- /**
670
- * 是否将换行符替换为字面量"\n"
671
- * @default false
672
- */
673
- disableNewLineReplace?: boolean;
674
- /**
675
- * 是否合并连续的换行符/制表符为单个
676
- * @default false
677
- */
678
- disableCollapse?: boolean;
679
- }) => string;
680
- //#endregion
681
- //#region src/string/extract-error-message.d.ts
682
- /** 从任意异常中提取类似 error.message 的可读文字 */
683
- declare const extractErrorMessage: (error: unknown) => string;
684
- //#endregion
685
- //#region src/string/qs.d.ts
686
- /**
687
- * 针对 URL 查询字符串的解析和序列化
688
- * @example
689
- * qs.parse("?a=1&b=2") // { a: 1, b: 2 }
690
- * qs.stringify({ a: 1, b: 2 }, { addQueryPrefix: true }) // "?a=1&b=2"
691
- */
692
- declare const qs: {
693
- /** queryString -> queryParams */parse: (queryString: string) => Record<string, any>;
694
- stringify: (params: Record<string, any>, options?: {
695
- /**
696
- * 是否在结果前添加“?”
697
- * @default false
698
- */
699
- addQueryPrefix: boolean;
700
- }) => string;
701
- };
702
- //#endregion
703
- //#region src/time/debounce.d.ts
704
- /**
705
- * 防抖:在指定时间内只执行最后一次调用
706
- * @param fn 要防抖的函数
707
- * @param delay 延迟时间,默认 300ms
708
- *
709
- * @remarks
710
- * 连续触发时,只有最后一次会执行。适合用于搜索框输入、窗口大小调整等场景。
711
- * 例如:用户输入"hello"过程中,不会触发搜索,只有停下来时才执行。
712
- *
713
- * 防抖 vs 节流:
714
- * - 防抖:等待触发停止后才执行(最后一次)
715
- * - 节流:按固定节奏执行(每隔多久执行一次)
716
- *
717
- * @example
718
- * const search = debounce((keyword: string) => {
719
- * console.log('搜索:', keyword);
720
- * });
721
- * search('hello'); // 300ms 后执行
722
- */
723
- declare const debounce: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (...args: Parameters<T>) => void;
724
- //#endregion
725
- //#region src/time/lock-queue.d.ts
726
- /**
727
- * 排队锁
728
- *
729
- * @remarks
730
- * 使用场景如:同时给大模型发送多条消息,使其依次回复
731
- *
732
- * @example
733
- * const queue = new LockQueue();
734
- * const messages = [];
735
- *
736
- * const chatCompletions = async () => {
737
- * // 等待前一个队列释放
738
- * const release = await queue.waitInQueue();
739
- *
740
- * const message = await requestLLM();
741
- * messages.push(message);
742
- * sendMessage(message);
743
- *
744
- * // 释放队列
745
- * release();
746
- * };
747
- *
748
- * chatCompletions();
749
- * chatCompletions();
750
- * chatCompletions();
751
- */
752
- declare class LockQueue {
753
- queue: Promise<any>;
754
- constructor();
755
- waitInQueue(): Promise<(value?: any) => void>;
756
- }
757
- //#endregion
758
- //#region src/time/sleep.d.ts
759
- /**
760
- * 延迟一段时间再执行后续代码
761
- * @param time 延迟时间,默认 150ms
762
- * @example
763
- * await sleep(1000); // 等待 1 秒执行后续代码
764
- */
765
- declare const sleep: (time?: number) => Promise<unknown>;
766
- //#endregion
767
- //#region src/time/throttle.d.ts
768
- /**
769
- * 节流函数 - 在指定时间间隔内最多执行一次调用
770
- * @param fn 要节流的函数
771
- * @param delay 间隔时间,默认 300ms
772
- *
773
- * @remarks
774
- * 节流:连续触发时,按照固定间隔执行。适合用于滚动、拖拽等高频触发场景。
775
- * 例如:滚动页面时,每300ms最多执行一次回调,而不是每次滚动都执行。
776
- *
777
- * 防抖 vs 节流:
778
- * - 防抖:等待触发停止后才执行(最后一次)
779
- * - 节流:按固定节奏执行(每隔多久执行一次)
780
- *
781
- * @example
782
- * const handleScroll = throttle(() => {
783
- * console.log('滚动位置:', window.scrollY);
784
- * }, 200);
785
- * window.addEventListener('scroll', handleScroll);
786
- */
787
- declare const throttle: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (this: any, ...args: Parameters<T>) => void;
788
- //#endregion
789
- export { CamelToSnake, Capitalize, type ChatCompletions, Decapitalize, DeepMapKeys, DeepMapValues, ImageCompressionOptions, LockQueue, LogOptions, Primitive, RequestInit, SetTtl, SnakeToCamel, camelToSnake, capitalize, chatCompletions, compactStr, debounce, decapitalize, defineModel, extractErrorMessage, fetcher, getRealURL, imageUrlToBase64, isNil, isObject, isPrimitive, log, loopUntil, mapKeys, mapValues, mergeObjects, omit, omitBy, pick, pickBy, qs, randomInt, sleep, snakeToCamel, throttle, to, withCache };
1
+ //#region src/ai/chatCompletions/types.d.ts
2
+ declare namespace ChatCompletions {
3
+ type Model = {
4
+ /** 模型名称(如果不传,会尝试从 /models 读取模型) */model?: string; /** API 基础地址 */
5
+ baseUrl: string; /** API 密钥(本地模型可不传) */
6
+ apiKey?: string;
7
+ };
8
+ type TextContent = {
9
+ type: "text";
10
+ text: string;
11
+ };
12
+ type ImageContent = {
13
+ type: "image_url";
14
+ image_url: {
15
+ url: string;
16
+ };
17
+ };
18
+ type AudioContent = {
19
+ type: "input_audio";
20
+ input_audio: {
21
+ /** 使用公网可访问的音频文件 URL */url?: string; /** 使用 base64 */
22
+ data?: string;
23
+ format: string;
24
+ };
25
+ };
26
+ type VideoContent = {
27
+ type: "video_url";
28
+ video_url: {
29
+ url: string;
30
+ };
31
+ };
32
+ type ContentPart = TextContent | ImageContent | AudioContent | VideoContent;
33
+ type Message = {
34
+ role: "system" | "user" | "assistant" | "tool" | "function"; /** 字节的思考字段 */
35
+ reasoning_content?: string | null; /** OpenRouter的思考字段 */
36
+ reasoning?: string | null;
37
+ content: string | ContentPart[];
38
+ name?: string;
39
+ tool_calls?: ToolCall[];
40
+ tool_call_id?: string;
41
+ };
42
+ type ToolCall = {
43
+ id: string;
44
+ type: "function";
45
+ function: {
46
+ name: string;
47
+ arguments: string;
48
+ };
49
+ };
50
+ type ToolDefinition = {
51
+ type: "function";
52
+ function: {
53
+ name: string;
54
+ description?: string;
55
+ parameters?: Record<string, any>;
56
+ };
57
+ };
58
+ type Usage = {
59
+ prompt_tokens: number;
60
+ completion_tokens: number;
61
+ total_tokens: number;
62
+ };
63
+ /** 请求非流式 /chat/completions 的响应结果 */
64
+ type Response = {
65
+ id: string;
66
+ object: "chat.completion";
67
+ created: number;
68
+ model: string;
69
+ choices: Array<{
70
+ index: number;
71
+ message: Message;
72
+ finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
73
+ }>;
74
+ usage: Usage;
75
+ system_fingerprint?: string;
76
+ };
77
+ type ExtraBody = {
78
+ /** 工具列表 */tools?: ToolDefinition[]; /** 工具调用函数表,key 为工具名,value 为函数 */
79
+ toolHandlers?: Record<string, (args: any) => any | Promise<any>>; /** 是否使用流式传输,启用后函数返回异步迭代器 */
80
+ stream?: boolean; /** 其他额外参数 */
81
+ [key: string]: any;
82
+ };
83
+ /** 调用 chatCompletions 返回的结果,流式/非流式通用 */
84
+ type Result = {
85
+ /** 模型的最终回复内容(多模态时取所有 text 拼接) */content: string; /** Token 消耗情况 */
86
+ usage: Usage; /** 原始响应中的其他字段 */
87
+ [key: string]: any;
88
+ };
89
+ /** 流式响应中的单个 SSE 数据块(OpenAI 原始格式) */
90
+ type StreamResponse = {
91
+ id: string;
92
+ object: "chat.completion.chunk";
93
+ created: number;
94
+ model: string;
95
+ choices: Array<{
96
+ index: number;
97
+ delta: {
98
+ role?: Message["role"];
99
+ content?: string | null; /** 字节的思考字段 */
100
+ reasoning_content?: string | null; /** OpenRouter的思考字段 */
101
+ reasoning?: string | null;
102
+ tool_calls?: Array<{
103
+ index: number;
104
+ id?: string;
105
+ type?: "function";
106
+ function?: {
107
+ name?: string;
108
+ arguments?: string;
109
+ };
110
+ }>;
111
+ };
112
+ finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
113
+ }>;
114
+ usage?: Usage;
115
+ };
116
+ /** 流式调用 chatCompletions 时迭代器产出的数据块 */
117
+ type StreamChunk = {
118
+ /** 模型流式返回的思考内容增量(仅在生成过程中出现) */reasoningContent?: string; /** 模型流式返回的内容增量(仅在生成过程中出现) */
119
+ content?: string; /** Token 消耗情况(仅在最后一帧出现) */
120
+ usage?: Usage;
121
+ };
122
+ }
123
+ //#endregion
124
+ //#region src/ai/chatCompletions/index.d.ts
125
+ /**
126
+ * 兼容 OpenAI API 的聊天补全函数
127
+ * - 自动处理工具调用
128
+ * - 同时支持普通响应和流式响应
129
+ *
130
+ * @param model 模型配置,包含 model、baseUrl、apiKey
131
+ * @param messages OpenAI API 兼容的消息数组
132
+ * @param extraBody 可选的额外参数,如 tools、toolHandlers、temperature、stream 等
133
+ * @returns 普通模式下返回 `{ content, usage, ... }`;`stream: true` 时返回异步迭代器
134
+ *
135
+ * @example
136
+ * // 最简调用
137
+ * // 未填写模型名,会自动使用/v1/models的第一个模型
138
+ * const { content, usage } = await chatCompletions(
139
+ * { baseUrl: "http://127.0.0.1:11434/v1" },
140
+ * [{ role: "user", content: "你好" }],
141
+ * );
142
+ * console.log(content); // "你好!有什么我可以帮你的吗?"
143
+ * console.log(usage); // { prompt_tokens: 13, completion_tokens: 9, total_tokens: 22 }
144
+ *
145
+ * @example
146
+ * // 工具调用
147
+ * const { content, usage } = await chatCompletions(
148
+ * { baseUrl: "http://127.0.0.1:11434/v1", model: "model.gguf", apiKey: "sk-local-no-need-key" },
149
+ * [{ role: "user", content: "查询上海天气" }],
150
+ * {
151
+ * tools: [{
152
+ * type: "function",
153
+ * function: {
154
+ * name: "getWeather",
155
+ * description: "查询城市天气情况",
156
+ * parameters: { type: "object", properties: { city: { type: "string" } } },
157
+ * },
158
+ * }],
159
+ * toolHandlers: {
160
+ * getWeather: (args) => `${args.city}今日晴转多云,25°C`,
161
+ * },
162
+ * },
163
+ * );
164
+ *
165
+ * @example
166
+ * // 流式传输
167
+ * const result = await chatCompletions(
168
+ * { baseUrl: "http://127.0.0.1:11434/v1" },
169
+ * [{ role: "user", content: "你好" }],
170
+ * { stream: true },
171
+ * );
172
+ * for await (const { content, usage } of result) {
173
+ * if (content) {
174
+ * console.log("流式传输中:", content);
175
+ * } else if (usage) {
176
+ * console.log("对话结束,消耗:", usage);
177
+ * }
178
+ * }
179
+ */
180
+ declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody: ChatCompletions.ExtraBody & {
181
+ stream: true;
182
+ }): Promise<AsyncGenerator<ChatCompletions.StreamChunk>>;
183
+ declare function chatCompletions(model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody?: ChatCompletions.ExtraBody): Promise<ChatCompletions.Result>;
184
+ /**
185
+ * 辅助定义一个 chatCompletions 支持的模型配置
186
+ */
187
+ declare const defineModel: (config: ChatCompletions.Model) => ChatCompletions.Model;
188
+ //#endregion
189
+ //#region src/dom/logger.d.ts
190
+ /**
191
+ * logger 配置选项
192
+ */
193
+ interface LoggerOptions {
194
+ /**
195
+ * 是否显示时间
196
+ * @default true
197
+ */
198
+ withTime?: boolean;
199
+ /**
200
+ * 是否显示调用者文件名
201
+ * @default true
202
+ */
203
+ withFileName?: boolean;
204
+ }
205
+ /**
206
+ * 带额外信息的 console.log
207
+ *
208
+ * **直接调用**:使用默认选项打印消息
209
+ * @param messages - 日志消息,支持多条
210
+ *
211
+ * **预配置**:先传入选项返回 logger 函数,再调用打印
212
+ * @param options - 配置选项
213
+ * @returns 配置后的 logger 函数
214
+ *
215
+ * @example
216
+ * // 直接调用(默认显示时间和文件名)
217
+ * logger("调试信息"); // "[14:30:00] [index.ts:15:2] 调试信息"
218
+ * logger("消息1", "消息2"); // "[14:30:00] [index.ts:15:2] 消息1 消息2"
219
+ *
220
+ * // 预配置后调用
221
+ * const myLogger = logger({ withTime: true, withFileName: true });
222
+ * myLogger("一段消息", "另一段消息"); // "[18:59:47] [index.ts:137:2] 一段消息 另一段消息"
223
+ *
224
+ * // 关闭时间或文件名
225
+ * const plainLogger = logger({ withTime: false });
226
+ * plainLogger("纯文件名前缀"); // "[index.ts:15:2] 纯文件名前缀"
227
+ */
228
+ declare function logger(options?: LoggerOptions): (...messages: any[]) => void;
229
+ declare function logger(...messages: any[]): void;
230
+ //#endregion
231
+ //#region src/function/loop-until.d.ts
232
+ /**
233
+ * 循环执行函数,直到符合停止条件
234
+ *
235
+ * @example
236
+ * // 循环请求大语言模型,直到其不再调用工具
237
+ * loopUntil(
238
+ * async () => {
239
+ * const completion = await chatCompletions();
240
+ * completion.tool_calls?.forEach(chooseAndHandleTool)
241
+ * return completion;
242
+ * },
243
+ * {
244
+ * shouldStop: (completion) => !completion.tool_calls,
245
+ * },
246
+ * ),
247
+ *
248
+ * @example
249
+ * // 不传递 shouldStop,执行 3 次后正常返回最后结果
250
+ * loopUntil(
251
+ * () => {
252
+ * return doSomething();
253
+ * },
254
+ * {
255
+ * maxRetries: 3,
256
+ * },
257
+ * ),
258
+ */
259
+ declare const loopUntil: <T>(fn: (count: number) => T | Promise<T>, options?: {
260
+ /**
261
+ * 最大循环次数
262
+ * @default 5
263
+ */
264
+ maxRetries?: number; /** 停止循环条件。如果未传递,则执行 maxRetries 次后退出并返回最后结果 */
265
+ shouldStop?: (result: T) => boolean;
266
+ }) => Promise<T>;
267
+ //#endregion
268
+ //#region src/hoc/with-cache.d.ts
269
+ type SetTtl = (seconds: number) => void;
270
+ /**
271
+ * 创建一个带缓存的高阶函数
272
+ *
273
+ * @template Args 被包装函数的参数类型数组
274
+ * @template Result 被包装函数的返回类型
275
+ *
276
+ * @param fn 需要被缓存的函数,参数里附带的 setTtl 方法用于根据具体情况改写过期时间
277
+ * @param ttlSeconds 以秒为单位的过期时间,-1 表示永不过期,默认 -1,会被回调函数里的 setTtl() 覆盖
278
+ *
279
+ * @returns 返回包装后的函数,以及缓存相关的额外方法
280
+ *
281
+ * @example
282
+ * // 异步函数示例
283
+ * const fetchData = withCache(async function (url: string) {
284
+ * const data = await fetch(url).then((res) => res.json());
285
+ * this.setTtl(data.expiresIn); // 根据实际情况调整过期时间
286
+ * return data;
287
+ * });
288
+ *
289
+ * await fetchData(urlA);
290
+ * await fetchData(urlA); // 使用缓存结果
291
+ * await fetchData(urlB);
292
+ * await fetchData(urlB); // 使用缓存结果
293
+ *
294
+ * fetchData.clear(); // 清除缓存
295
+ * await fetchData(urlA); // 重新请求
296
+ * await fetchData(urlB); // 重新请求
297
+ *
298
+ * // 缓存过期前
299
+ * await sleep();
300
+ * fetchData.updateTtl(180); // 更新 ttl 并为所有未过期的缓存续期
301
+ * await fetchData(urlA); // 使用缓存结果
302
+ * await fetchData(urlB); // 使用缓存结果
303
+ */
304
+ declare const withCache: <Args extends any[], Result>(fn: (this: {
305
+ setTtl: SetTtl;
306
+ }, ...args: Args) => Result, ttlSeconds?: number) => {
307
+ (...args: Args): Result;
308
+ clear(): void;
309
+ updateTtl(seconds: number): void;
310
+ };
311
+ //#endregion
312
+ //#region src/is/is-nil.d.ts
313
+ /**
314
+ * 检测传入的值是否为**空值**(null、undefined)
315
+ *
316
+ * @example
317
+ * isNil(null); // true
318
+ * isNil(undefined); // true
319
+ * isNil(1); // false
320
+ */
321
+ declare const isNil: (value: any) => value is null | undefined;
322
+ //#endregion
323
+ //#region src/is/is-object.d.ts
324
+ /**
325
+ * 检测传入的值是否为**普通对象**
326
+ *
327
+ * @example
328
+ * const obj = { a: 1 };
329
+ * isObject(obj); // true
330
+ */
331
+ declare const isObject: (value: any) => value is Record<string, any>;
332
+ //#endregion
333
+ //#region src/is/is-primitive.d.ts
334
+ type Primitive = number | string | boolean | symbol | bigint | undefined | null;
335
+ /**
336
+ * 检测传入的值是否为**原始值**(number、string、boolean、symbol、bigint、undefined、null)
337
+ *
338
+ * @example
339
+ * isPrimitive(1); // true
340
+ * isPrimitive([]); // false
341
+ */
342
+ declare const isPrimitive: (value: any) => value is Primitive;
343
+ //#endregion
344
+ //#region src/network/fetcher.d.ts
345
+ type RequestInit = globalThis.RequestInit & {
346
+ /**
347
+ * searchParams 查询参数对象
348
+ */
349
+ params?: Record<string, any>;
350
+ /**
351
+ * 响应解析器,默认的解析方法为 response.json()
352
+ */
353
+ parser?: (response: Response) => Promise<any>;
354
+ };
355
+ /**
356
+ * 基于 Fetch API 的请求实例
357
+ * @param baseUrl 接口前缀
358
+ * @param baseOptions 应用于整个实例的请求体,后续请求都会带上
359
+ *
360
+ * @remarks
361
+ * 特性:
362
+ * - 支持在创建实例、发出请求时合并相同的请求体(后者覆盖前者)
363
+ * - 支持在 GET 的 params 请求体中传递对象
364
+ * - 支持在 POST、PUT 的 body 请求体中传递对象
365
+ * - 可选 to() 函数转换请求结果为 [Error, Response]
366
+ * - 可选 withCache() 函数缓存请求结果
367
+ *
368
+ * @example
369
+ * // 直接发请求
370
+ * const res = await fetcher().get<Blog>("https://nickyzj.run:3030/blogs/hello-world", {
371
+ * params: {
372
+ * page: 2,
373
+ * pageSize: 10,
374
+ * }
375
+ * });
376
+ *
377
+ * // 创建实例,发请求
378
+ * const api = fetcher("https://nickyzj.run:3030", {
379
+ * headers: {
380
+ * Authorization: "Bearer token"
381
+ * }
382
+ * });
383
+ * const res = await api.get<Blog>("/blogs/hello-world");
384
+ *
385
+ * // 安全返回请求结果,不抛异常
386
+ * const [error, data] = await to(api.get<Blog>("/blogs/hello-world"));
387
+ * if (error) {
388
+ * // ...
389
+ * }
390
+ * // ...
391
+ *
392
+ * // 缓存请求结果
393
+ * const getBlogs = withCache(api.get);
394
+ * await getBlogs("/blogs");
395
+ * await getBlogs("/blogs"); // 不发请求,使用缓存
396
+ */
397
+ declare const fetcher: (baseUrl?: string, baseOptions?: RequestInit) => {
398
+ get: <T>(url: string, options?: Omit<RequestInit, "method">) => Promise<T>;
399
+ post: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
400
+ put: <T>(url: string, body: any, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
401
+ delete: <T>(url: string, options?: Omit<RequestInit, "method" | "body">) => Promise<T>;
402
+ };
403
+ //#endregion
404
+ //#region src/network/get-real-url.d.ts
405
+ /** url 响应头获取真实链接 */
406
+ declare const getRealURL: (originURL: string) => Promise<string>;
407
+ //#endregion
408
+ //#region src/network/image.d.ts
409
+ /**
410
+ * 图片压缩选项
411
+ */
412
+ type ImageCompressionOptions = {
413
+ /** 压缩比率,默认 0.92 */quality?: number;
414
+ /**
415
+ * 自定义压缩函数,用于覆盖默认压缩行为
416
+ * @param arrayBuffer 图片的 ArrayBuffer 数据
417
+ * @param mime 图片的 MIME 类型
418
+ * @param quality 压缩质量
419
+ * @returns 压缩后的 base64 字符串
420
+ */
421
+ compressor?: (arrayBuffer: ArrayBuffer, mime: string, quality: number) => Promise<string> | string;
422
+ /**
423
+ * 自定义 fetch 函数,用于使用自己封装的请求库读取图片
424
+ * 必须返回符合 Web 标准的 Response 对象
425
+ * @param url 图片地址
426
+ * @returns Promise<Response>
427
+ */
428
+ fetcher?: (url: string) => Promise<Response>;
429
+ };
430
+ /**
431
+ * 图片地址转 base64 数据
432
+ *
433
+ * @param imageUrl 图片地址
434
+ * @param options 可选配置
435
+ * @param options.quality 压缩比率,默认 0.92
436
+ * @param options.compressor 自定义压缩函数,用于覆盖默认压缩行为
437
+ *
438
+ * @example
439
+ * // 基本用法(浏览器自动使用 Canvas 压缩,Node.js 自动检测并使用 sharp)
440
+ * imageUrlToBase64("https://example.com/image.jpg");
441
+ *
442
+ * @example
443
+ * // 使用自定义 fetch 函数(如 axios 封装)
444
+ * imageUrlToBase64("https://example.com/image.jpg", {
445
+ * fetcher: async (url) => {
446
+ * // 使用 axios 或其他请求库,但必须返回 Response 对象
447
+ * const response = await axios.get(url, { responseType: 'arraybuffer' });
448
+ * return new Response(response.data, {
449
+ * status: response.status,
450
+ * statusText: response.statusText,
451
+ * headers: response.headers
452
+ * });
453
+ * }
454
+ * });
455
+ *
456
+ * @example
457
+ * // 使用自定义压缩函数覆盖默认行为
458
+ * imageUrlToBase64("https://example.com/image.jpg", {
459
+ * quality: 0.8,
460
+ * compressor: async (buffer, mime, quality) => {
461
+ * // 自定义压缩逻辑
462
+ * return `data:${mime};base64,...`;
463
+ * }
464
+ * });
465
+ */
466
+ declare const imageUrlToBase64: (imageUrl: string, options?: ImageCompressionOptions) => Promise<string>;
467
+ //#endregion
468
+ //#region src/network/parse-sse.d.ts
469
+ /**
470
+ * 分段解析 SSE 流式响应内容
471
+ * @param response Fetch API 返回的响应对象
472
+ * @returns 可被 `for await () {}` 消费的异步迭代器
473
+ * @example
474
+ * const response = await fetch("/chat/completions", { stream: true });
475
+ * for await (const data of parseSSE(response)) {
476
+ * console.log(data.choices);
477
+ * console.log(data.usage);
478
+ * }
479
+ */
480
+ declare function parseSSE<T = any>(response: Response): AsyncIterableIterator<T>;
481
+ //#endregion
482
+ //#region src/network/to.d.ts
483
+ /**
484
+ * Go 语言风格的异步处理方式
485
+ * @param promise 一个能被 await 的异步函数
486
+ * @returns 如果成功,返回 [null, 异步函数结果],否则返回 [Error, undefined]
487
+ *
488
+ * @example
489
+ * const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
490
+ */
491
+ declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E, undefined]>;
492
+ //#endregion
493
+ //#region src/number/random-int.d.ts
494
+ /**
495
+ * 在指定闭区间内生成随机整数
496
+ *
497
+ * @example
498
+ * randomInt(1, 10); // 1 <= x <= 10
499
+ */
500
+ declare const randomInt: (min: number, max: number) => number;
501
+ //#endregion
502
+ //#region src/object/map.d.ts
503
+ type DeepMapKeys<T> = T extends Array<infer U> ? Array<DeepMapKeys<U>> : T extends object ? {
504
+ [key: string]: DeepMapKeys<T[keyof T]>;
505
+ } : T;
506
+ /**
507
+ * 递归处理对象里的 key
508
+ *
509
+ * @remarks
510
+ * 无法完整推导出类型,只能做到有递归,key 全为 string,value 为同层级的所有类型的联合
511
+ *
512
+ * @template T 要转换的对象
513
+ *
514
+ * @example
515
+ * const obj = { a: { b: 1 } };
516
+ * const result = mapKeys(obj, (key) => key.toUpperCase());
517
+ * console.log(result); // { A: { B: 1 } }
518
+ */
519
+ declare const mapKeys: <T>(obj: T, getNewKey: (key: string) => string) => DeepMapKeys<T>;
520
+ type DeepMapValues<T, R> = T extends Array<infer U> ? Array<DeepMapValues<U, R>> : T extends object ? { [K in keyof T]: T[K] extends object ? DeepMapValues<T[K], R> : R } : R;
521
+ /**
522
+ * 递归处理对象里的 value
523
+ *
524
+ * @remarks
525
+ * 无法完整推导出类型,所有 value 最终都会变为 any
526
+ *
527
+ * @template T 要转换的对象
528
+ * @template R 转换后的值类型,为 any,无法进一步推导
529
+ *
530
+ * @example
531
+ * const obj = { a: 1, b: { c: 2 } };
532
+ * const result = mapValues(obj, (value, key) => isPrimitive(value) ? value + 1 : value);
533
+ * console.log(result); // { a: 2, b: { c: 3 } }
534
+ */
535
+ declare const mapValues: <T, R = any>(obj: T, getNewValue: (value: any, key: string | number) => R, options?: {
536
+ /** 过滤函数,返回 true 表示保留该字段 */filter?: (value: any, key: string | number) => boolean;
537
+ }) => DeepMapValues<T, R>;
538
+ //#endregion
539
+ //#region src/object/merge.d.ts
540
+ /**
541
+ * 深度合并两个对象,规则如下:
542
+ * 1. 原始值覆盖:如果两个值都是原始类型,则用后者覆盖;
543
+ * 2. 数组拼接:如果两个值都是数组,则拼接为大数组;
544
+ * 3. 对象递归合并:如果两个值都是对象,则进行递归深度合并;
545
+ *
546
+ * @template T 第一个对象
547
+ * @template U 第二个对象
548
+ * @param {T} obj1 要合并的第一个对象,相同字段会被 obj2 覆盖
549
+ * @param {U} obj2 要合并的第二个对象
550
+ */
551
+ declare const mergeObjects: <T extends Record<string, any>, U extends Record<string, any>>(obj1: T, obj2: U) => T & U;
552
+ //#endregion
553
+ //#region src/object/omit.d.ts
554
+ /**
555
+ * 从对象中排除指定的键,返回不包含这些键的新对象
556
+ *
557
+ * @typeParam T - 源对象的类型
558
+ * @typeParam K - 要排除的键,必须是源对象的键之一
559
+ *
560
+ * @param obj - 源对象
561
+ * @param keys - 要排除的键名数组
562
+ * @returns 不包含指定键的新对象
563
+ *
564
+ * @example
565
+ * const user = {
566
+ * id: 1,
567
+ * name: "Alice",
568
+ * age: 25,
569
+ * password: "secret"
570
+ * };
571
+ * // { id: 1, name: "Alice", age: 25 }
572
+ * const safeUser = omit(user, ["password"]);
573
+ */
574
+ declare const omit: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Omit<T, K>;
575
+ /**
576
+ * 从对象中排除满足条件的键值对,返回不包含这些键的新对象
577
+ *
578
+ * @typeParam T - 源对象的类型
579
+ *
580
+ * @param obj - 源对象
581
+ * @param shouldOmit - 判断函数,接收键和值,返回 `true` 则排除该键值对
582
+ * @returns 不包含满足条件的键值对的新对象
583
+ *
584
+ * @example
585
+ * const user = {
586
+ * id: 1,
587
+ * name: "Alice",
588
+ * age: 25,
589
+ * password: "secret"
590
+ * };
591
+ * // { name: "Alice", password: "secret" }
592
+ * const stringFields = omitBy(user, (key, value) => typeof value === "number");
593
+ */
594
+ declare const omitBy: <T extends Record<string, any>>(obj: T, shouldOmit: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
595
+ //#endregion
596
+ //#region src/object/pick.d.ts
597
+ /**
598
+ * 从对象中选取指定的键,返回仅包含这些键的新对象
599
+ *
600
+ * @typeParam T - 源对象的类型
601
+ * @typeParam K - 要选取的键,必须是源对象的键之一
602
+ *
603
+ * @param obj - 源对象
604
+ * @param keys - 要选取的键名数组
605
+ * @returns 仅包含指定键的新对象
606
+ *
607
+ * @example
608
+ * const user = {
609
+ * id: 1,
610
+ * name: "Alice",
611
+ * age: 25,
612
+ * password: "secret"
613
+ * };
614
+ * // { id: 1, name: "Alice", age: 25 }
615
+ * const safeUser = pick(user, ["id", "name", "age"]);
616
+ */
617
+ declare const pick: <T extends Record<string, any>, K extends keyof T>(obj: T, keys: readonly K[]) => Pick<T, K>;
618
+ /**
619
+ * 从对象中选取满足条件的键值对,返回仅包含这些键的新对象
620
+ *
621
+ * @typeParam T - 源对象的类型
622
+ *
623
+ * @param obj - 源对象
624
+ * @param shouldPick - 判断函数,返回 `true` 时保留该字段
625
+ * @returns 仅包含满足条件的键值对的新对象
626
+ *
627
+ * @example
628
+ * const user = {
629
+ * id: 1,
630
+ * name: "Alice",
631
+ * age: 25,
632
+ * password: "secret"
633
+ * };
634
+ * // { id: 1, age: 25 }
635
+ * const numericFields = pickBy(user, (key, value) => typeof value === "number");
636
+ */
637
+ declare const pickBy: <T extends Record<string, any>>(obj: T, shouldPick: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
638
+ //#endregion
639
+ //#region src/string/case.d.ts
640
+ type SnakeToCamel<S extends string> = S extends `${infer Before}_${infer After}` ? After extends `${infer First}${infer Rest}` ? `${Before}${Uppercase<First>}${SnakeToCamel<Rest>}` : Before : S;
641
+ /**
642
+ * 下划线命名法转为驼峰命名法
643
+ *
644
+ * @example
645
+ * snakeToCamel("user_name") // "userName"
646
+ */
647
+ declare const snakeToCamel: <S extends string>(str: S) => SnakeToCamel<S>;
648
+ type CamelToSnake<S extends string> = S extends `${infer First}${infer Rest}` ? Rest extends Uncapitalize<Rest> ? `${Lowercase<First>}${CamelToSnake<Rest>}` : `${Lowercase<First>}_${CamelToSnake<Rest>}` : Lowercase<S>;
649
+ /**
650
+ * 驼峰命名法转为下划线命名法
651
+ *
652
+ * @example
653
+ * camelToSnake("shouldComponentUpdate") // "should_component_update"
654
+ */
655
+ declare const camelToSnake: <S extends string>(str: S) => CamelToSnake<S>;
656
+ type Capitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Capitalize<P1> ? S : `${Uppercase<P1>}${Rest}` : S;
657
+ /**
658
+ * 字符串首字母大写
659
+ *
660
+ * @example
661
+ * capitalize("hello") // "Hello"
662
+ */
663
+ declare const capitalize: <S extends string>(s: S) => Capitalize<S>;
664
+ type Decapitalize<S extends string> = S extends `${infer P1}${infer Rest}` ? P1 extends Lowercase<P1> ? P1 : `${Lowercase<P1>}${Rest}` : S;
665
+ /**
666
+ * 字符串首字母小写
667
+ *
668
+ * @example
669
+ * decapitalize("Hello") // "hello"
670
+ */
671
+ declare const decapitalize: <S extends string>(s: S) => Decapitalize<S>;
672
+ //#endregion
673
+ //#region src/string/compact.d.ts
674
+ /**
675
+ * 将字符串压缩为单行精简格式
676
+ *
677
+ * @example
678
+ * // "Hello\nworld"
679
+ * compactStr(`Hello,
680
+ *
681
+ * world
682
+ *
683
+ * !`);
684
+ *
685
+ * @example
686
+ * // "Hello...world"
687
+ * compactStr("Hello, beautiful world!", { maxLength: 15 });
688
+ */
689
+ declare const compactStr: (text?: string, options?: {
690
+ /**
691
+ * 最大保留长度,超过该长度使用 "..." 替代
692
+ @default Infinity
693
+ */
694
+ maxLength?: number;
695
+ /**
696
+ * 是否将换行符替换为字面量"\n"
697
+ * @default false
698
+ */
699
+ disableNewLineReplace?: boolean;
700
+ /**
701
+ * 是否合并连续的换行符/制表符为单个
702
+ * @default false
703
+ */
704
+ disableCollapse?: boolean;
705
+ }) => string;
706
+ //#endregion
707
+ //#region src/string/extract-error-message.d.ts
708
+ /** 从任意异常中提取类似 error.message 的可读文字 */
709
+ declare const extractErrorMessage: (error: unknown) => string;
710
+ //#endregion
711
+ //#region src/string/qs.d.ts
712
+ /**
713
+ * 针对 URL 查询字符串的解析和序列化
714
+ * @example
715
+ * qs.parse("?a=1&b=2") // { a: 1, b: 2 }
716
+ * qs.stringify({ a: 1, b: 2 }, { addQueryPrefix: true }) // "?a=1&b=2"
717
+ */
718
+ declare const qs: {
719
+ /** queryString -> queryParams */parse: (queryString: string) => Record<string, any>;
720
+ stringify: (params: Record<string, any>, options?: {
721
+ /**
722
+ * 是否在结果前添加“?”
723
+ * @default false
724
+ */
725
+ addQueryPrefix: boolean;
726
+ }) => string;
727
+ };
728
+ //#endregion
729
+ //#region src/time/debounce.d.ts
730
+ /**
731
+ * 防抖:在指定时间内只执行最后一次调用
732
+ * @param fn 要防抖的函数
733
+ * @param delay 延迟时间,默认 300ms
734
+ *
735
+ * @remarks
736
+ * 连续触发时,只有最后一次会执行。适合用于搜索框输入、窗口大小调整等场景。
737
+ * 例如:用户输入"hello"过程中,不会触发搜索,只有停下来时才执行。
738
+ *
739
+ * 防抖 vs 节流:
740
+ * - 防抖:等待触发停止后才执行(最后一次)
741
+ * - 节流:按固定节奏执行(每隔多久执行一次)
742
+ *
743
+ * @example
744
+ * const search = debounce((keyword: string) => {
745
+ * console.log('搜索:', keyword);
746
+ * });
747
+ * search('hello'); // 300ms 后执行
748
+ */
749
+ declare const debounce: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (...args: Parameters<T>) => void;
750
+ //#endregion
751
+ //#region src/time/lock-queue.d.ts
752
+ /**
753
+ * 排队锁
754
+ *
755
+ * @remarks
756
+ * 使用场景如:同时给大模型发送多条消息,使其依次回复
757
+ *
758
+ * @example
759
+ * const queue = new LockQueue();
760
+ * const messages = [];
761
+ *
762
+ * const chatCompletions = async () => {
763
+ * // 等待前一个队列释放
764
+ * const release = await queue.waitInQueue();
765
+ *
766
+ * const message = await requestLLM();
767
+ * messages.push(message);
768
+ * sendMessage(message);
769
+ *
770
+ * // 释放队列
771
+ * release();
772
+ * };
773
+ *
774
+ * chatCompletions();
775
+ * chatCompletions();
776
+ * chatCompletions();
777
+ */
778
+ declare class LockQueue {
779
+ queue: Promise<any>;
780
+ constructor();
781
+ waitInQueue(): Promise<(value?: any) => void>;
782
+ }
783
+ //#endregion
784
+ //#region src/time/sleep.d.ts
785
+ /**
786
+ * 延迟一段时间再执行后续代码
787
+ * @param time 延迟时间,默认 150ms
788
+ * @example
789
+ * await sleep(1000); // 等待 1 秒执行后续代码
790
+ */
791
+ declare const sleep: (time?: number) => Promise<unknown>;
792
+ //#endregion
793
+ //#region src/time/throttle.d.ts
794
+ /**
795
+ * 节流函数 - 在指定时间间隔内最多执行一次调用
796
+ * @param fn 要节流的函数
797
+ * @param delay 间隔时间,默认 300ms
798
+ *
799
+ * @remarks
800
+ * 节流:连续触发时,按照固定间隔执行。适合用于滚动、拖拽等高频触发场景。
801
+ * 例如:滚动页面时,每300ms最多执行一次回调,而不是每次滚动都执行。
802
+ *
803
+ * 防抖 vs 节流:
804
+ * - 防抖:等待触发停止后才执行(最后一次)
805
+ * - 节流:按固定节奏执行(每隔多久执行一次)
806
+ *
807
+ * @example
808
+ * const handleScroll = throttle(() => {
809
+ * console.log('滚动位置:', window.scrollY);
810
+ * }, 200);
811
+ * window.addEventListener('scroll', handleScroll);
812
+ */
813
+ declare const throttle: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (this: any, ...args: Parameters<T>) => void;
814
+ //#endregion
815
+ export { CamelToSnake, Capitalize, type ChatCompletions, Decapitalize, DeepMapKeys, DeepMapValues, ImageCompressionOptions, LockQueue, LoggerOptions, Primitive, RequestInit, SetTtl, SnakeToCamel, camelToSnake, capitalize, chatCompletions, compactStr, debounce, decapitalize, defineModel, extractErrorMessage, fetcher, getRealURL, imageUrlToBase64, isNil, isObject, isPrimitive, logger, loopUntil, mapKeys, mapValues, mergeObjects, omit, omitBy, parseSSE, pick, pickBy, qs, randomInt, sleep, snakeToCamel, throttle, to, withCache };