@nickyzj2023/utils 1.0.63 → 1.0.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- 男生自用全新前端工具库
1
+ 男生自用全新前端工具库,0依赖
2
2
 
3
3
  安装到你的前端项目里:
4
4
 
@@ -29,5 +29,3 @@ if (error) {
29
29
 
30
30
  console.log(data);
31
31
  ```
32
-
33
-
@@ -0,0 +1 @@
1
+ var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r};export{t};
package/dist/index.d.mts CHANGED
@@ -1,3 +1,120 @@
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 ContentPart = TextContent | ImageContent;
19
+ type Message = {
20
+ role: "system" | "user" | "assistant" | "tool" | "function";
21
+ content: string | ContentPart[];
22
+ name?: string;
23
+ tool_calls?: ToolCall[];
24
+ tool_call_id?: string;
25
+ };
26
+ type ToolCall = {
27
+ id: string;
28
+ type: "function";
29
+ function: {
30
+ name: string;
31
+ arguments: string;
32
+ };
33
+ };
34
+ type ToolDefinition = {
35
+ type: "function";
36
+ function: {
37
+ name: string;
38
+ description?: string;
39
+ parameters?: Record<string, any>;
40
+ };
41
+ };
42
+ type Usage = {
43
+ prompt_tokens: number;
44
+ completion_tokens: number;
45
+ total_tokens: number;
46
+ };
47
+ type Response = {
48
+ id: string;
49
+ object: "chat.completion";
50
+ created: number;
51
+ model: string;
52
+ choices: Array<{
53
+ index: number;
54
+ message: Message;
55
+ finish_reason: "stop" | "length" | "tool_calls" | "content_filter" | null;
56
+ }>;
57
+ usage: Usage;
58
+ system_fingerprint?: string;
59
+ };
60
+ type ExtraBody = {
61
+ /** 工具列表 */tools?: ToolDefinition[]; /** 工具调用函数表,key 为工具名,value 为函数 */
62
+ toolHandlers?: Record<string, (args: any) => any | Promise<any>>; /** 其他额外参数 */
63
+ [key: string]: any;
64
+ };
65
+ type Result = {
66
+ /** 模型的最终回复内容(多模态时取所有 text 拼接) */content: string; /** Token 消耗情况 */
67
+ usage: Usage; /** 原始响应中的其他字段 */
68
+ [key: string]: any;
69
+ };
70
+ }
71
+ //#endregion
72
+ //#region src/ai/chatCompletions/index.d.ts
73
+ /**
74
+ * 兼容 OpenAI API 的聊天补全函数
75
+ * - 自动处理工具调用
76
+ * - 返回最终回复内容和 token 消耗情况
77
+ *
78
+ * @param model 模型配置,包含 model、baseURL、apiKey
79
+ * @param messages OpenAI API 兼容的消息数组
80
+ * @param extraBody 可选的额外参数,如 tools、toolHandlers、temperature 等
81
+ * @returns 包含 content、usage 和其他原始字段的对象
82
+ *
83
+ * @example
84
+ * // 最简调用
85
+ * // 未填写模型名,会自动使用/v1/models的第一个模型
86
+ * const { content, usage } = await chatCompletions(
87
+ * { baseURL: "http://127.0.0.1:11434/v1" },
88
+ * [{ role: "user", content: "你好" }],
89
+ * );
90
+ * console.log(content); // "你好!有什么我可以帮你的吗?"
91
+ * console.log(usage); // { prompt_tokens: 13, completion_tokens: 9, total_tokens: 22 }
92
+ *
93
+ * @example
94
+ * // 工具调用
95
+ * const { content, usage } = await chatCompletions(
96
+ * { baseURL: "http://127.0.0.1:11434/v1", model: "model.gguf", apiKey: "sk-local-no-need-key" },
97
+ * [{ role: "user", content: "查询上海天气" }],
98
+ * {
99
+ * tools: [{
100
+ * type: "function",
101
+ * function: {
102
+ * name: "getWeather",
103
+ * description: "查询城市天气情况",
104
+ * parameters: { type: "object", properties: { city: { type: "string" } } },
105
+ * },
106
+ * }],
107
+ * toolHandlers: {
108
+ * getWeather: (args) => `${args.city}今日晴转多云,25°C`,
109
+ * },
110
+ * },
111
+ * );
112
+ */
113
+ declare const chatCompletions: (model: ChatCompletions.Model, messages: ChatCompletions.Message[], extraBody?: ChatCompletions.ExtraBody) => Promise<ChatCompletions.Result>;
114
+ declare namespace index_d_exports {
115
+ export { chatCompletions };
116
+ }
117
+ //#endregion
1
118
  //#region src/dom/log.d.ts
2
119
  /**
3
120
  * log 配置选项
@@ -27,6 +144,9 @@ interface LogOptions {
27
144
  * log(["消息1", "消息2"]); // "[14:30:00] [index.ts:15] 消息1 消息2"
28
145
  */
29
146
  declare const log: (message: any | any[], options?: LogOptions) => void;
147
+ declare namespace index_d_exports$1 {
148
+ export { LogOptions, log };
149
+ }
30
150
  //#endregion
31
151
  //#region src/function/loop-until.d.ts
32
152
  /**
@@ -64,6 +184,9 @@ declare const loopUntil: <T>(fn: (count: number) => T | Promise<T>, options?: {
64
184
  maxRetries?: number; /** 停止循环条件。如果未传递,则执行 maxRetries 次后退出并返回最后结果 */
65
185
  shouldStop?: (result: T) => boolean;
66
186
  }) => Promise<T>;
187
+ declare namespace index_d_exports$2 {
188
+ export { loopUntil };
189
+ }
67
190
  //#endregion
68
191
  //#region src/hoc/with-cache.d.ts
69
192
  type SetTtl = (seconds: number) => void;
@@ -108,17 +231,9 @@ declare const withCache: <Args extends any[], Result>(fn: (this: {
108
231
  clear(): void;
109
232
  updateTtl(seconds: number): void;
110
233
  };
111
- //#endregion
112
- //#region src/is/is-falsy.d.ts
113
- type Falsy = false | 0 | -0 | 0n | "" | null | undefined;
114
- /**
115
- * 检测传入的值是否为**假值**(false、0、''、null、undefined、NaN等)
116
- *
117
- * @example
118
- * isFalsy(""); // true
119
- * isFalsy(1); // false
120
- */
121
- declare const isFalsy: (value: any) => value is Falsy;
234
+ declare namespace index_d_exports$3 {
235
+ export { SetTtl, withCache };
236
+ }
122
237
  //#endregion
123
238
  //#region src/is/is-nil.d.ts
124
239
  /**
@@ -151,6 +266,9 @@ type Primitive = number | string | boolean | symbol | bigint | undefined | null;
151
266
  * isPrimitive([]); // false
152
267
  */
153
268
  declare const isPrimitive: (value: any) => value is Primitive;
269
+ declare namespace index_d_exports$4 {
270
+ export { Primitive, isNil, isObject, isPrimitive };
271
+ }
154
272
  //#endregion
155
273
  //#region src/network/fetcher.d.ts
156
274
  type RequestInit = globalThis.RequestInit & {
@@ -286,6 +404,9 @@ declare const imageUrlToBase64: (imageUrl: string, options?: ImageCompressionOpt
286
404
  * const [error, response] = await to(fetcher().get<Blog>("/blogs/hello-world"));
287
405
  */
288
406
  declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E, undefined]>;
407
+ declare namespace index_d_exports$5 {
408
+ export { ImageCompressionOptions, RequestInit, fetcher, getRealURL, imageUrlToBase64, to };
409
+ }
289
410
  //#endregion
290
411
  //#region src/number/random-int.d.ts
291
412
  /**
@@ -295,6 +416,9 @@ declare const to: <T, E = Error>(promise: Promise<T>) => Promise<[null, T] | [E,
295
416
  * randomInt(1, 10); // 1 <= x <= 10
296
417
  */
297
418
  declare const randomInt: (min: number, max: number) => number;
419
+ declare namespace index_d_exports$6 {
420
+ export { randomInt };
421
+ }
298
422
  //#endregion
299
423
  //#region src/object/map.d.ts
300
424
  type DeepMapKeys<T> = T extends Array<infer U> ? Array<DeepMapKeys<U>> : T extends object ? {
@@ -432,6 +556,9 @@ declare const pick: <T extends Record<string, any>, K extends keyof T>(obj: T, k
432
556
  * const numericFields = pickBy(user, (key, value) => typeof value === "number");
433
557
  */
434
558
  declare const pickBy: <T extends Record<string, any>>(obj: T, shouldPick: (key: keyof T, value: T[keyof T]) => boolean) => Partial<T>;
559
+ declare namespace index_d_exports$7 {
560
+ export { DeepMapKeys, DeepMapValues, mapKeys, mapValues, mergeObjects, omit, omitBy, pick, pickBy };
561
+ }
435
562
  //#endregion
436
563
  //#region src/string/case.d.ts
437
564
  type SnakeToCamel<S extends string> = S extends `${infer Before}_${infer After}` ? After extends `${infer First}${infer Rest}` ? `${Before}${Uppercase<First>}${SnakeToCamel<Rest>}` : Before : S;
@@ -480,7 +607,7 @@ declare const decapitalize: <S extends string>(s: S) => Decapitalize<S>;
480
607
  * !`);
481
608
  *
482
609
  * @example
483
- * // "Hello...world" (maxLength: 15)
610
+ * // "Hello...world"
484
611
  * compactStr("Hello, beautiful world!", { maxLength: 15 });
485
612
  */
486
613
  declare const compactStr: (text?: string, options?: {
@@ -501,6 +628,10 @@ declare const compactStr: (text?: string, options?: {
501
628
  disableCollapse?: boolean;
502
629
  }) => string;
503
630
  //#endregion
631
+ //#region src/string/extract-error-message.d.ts
632
+ /** 从任意异常中提取类似 error.message 的可读文字 */
633
+ declare const extractErrorMessage: (error: unknown) => string;
634
+ //#endregion
504
635
  //#region src/string/qs.d.ts
505
636
  /**
506
637
  * 针对 URL 查询字符串的解析和序列化
@@ -518,6 +649,9 @@ declare const qs: {
518
649
  addQueryPrefix: boolean;
519
650
  }) => string;
520
651
  };
652
+ declare namespace index_d_exports$8 {
653
+ export { CamelToSnake, Capitalize, Decapitalize, SnakeToCamel, camelToSnake, capitalize, compactStr, decapitalize, extractErrorMessage, qs, snakeToCamel };
654
+ }
521
655
  //#endregion
522
656
  //#region src/time/debounce.d.ts
523
657
  /**
@@ -604,5 +738,8 @@ declare const sleep: (time?: number) => Promise<unknown>;
604
738
  * window.addEventListener('scroll', handleScroll);
605
739
  */
606
740
  declare const throttle: <T extends (...args: any[]) => any>(fn: T, delay?: number) => (this: any, ...args: Parameters<T>) => void;
741
+ declare namespace index_d_exports$9 {
742
+ export { LockQueue, debounce, sleep, throttle };
743
+ }
607
744
  //#endregion
608
- export { CamelToSnake, Capitalize, Decapitalize, DeepMapKeys, DeepMapValues, Falsy, ImageCompressionOptions, LockQueue, LogOptions, Primitive, RequestInit, SetTtl, SnakeToCamel, camelToSnake, capitalize, compactStr, debounce, decapitalize, fetcher, getRealURL, imageUrlToBase64, isFalsy, isNil, isObject, isPrimitive, log, loopUntil, mapKeys, mapValues, mergeObjects, omit, omitBy, pick, pickBy, qs, randomInt, sleep, snakeToCamel, throttle, to, withCache };
745
+ export { index_d_exports as ai, index_d_exports$1 as dom, index_d_exports$2 as function, index_d_exports$3 as hoc, index_d_exports$4 as is, index_d_exports$5 as network, index_d_exports$6 as number, index_d_exports$7 as object, index_d_exports$8 as string, index_d_exports$9 as time };
package/dist/index.mjs CHANGED
@@ -1,3 +1,4 @@
1
- const e=(e,t)=>{let{time:n=!0,fileName:r=!0}=t??{},i=[];if(n&&i.push(`[${new Date().toLocaleTimeString()}]`),r){let{stack:e}=Error(),t=(e?.split(`
2
- `)[2]?.trim())?.match(/at\s+(.*):(\d+)/);if(t?.[1]){let e=t[1].split(/[/\\]/).pop();i.push(`[${e}:${t[2]}]`)}}Array.isArray(e)?i.push(...e):i.push(e),console.log(...i)},t=async(e,t)=>{let{maxRetries:n=5,shouldStop:r}=t??{},i;for(let t=0;t<n;t++)if(i=await e(t),r?.(i)===!0)return i;if(!r)return i;throw Error(`超过了最大循环次数(${n})且未满足停止执行条件`)},n=(e,t=-1)=>{let n=new Map,r=(...r)=>{let i=JSON.stringify(r),a=Date.now(),o=n.get(i);if(o&&a<o.expiresAt)return o.value;let s=t===-1?1/0:a+t*1e3,c=e.apply({setTtl:e=>{s=a+e*1e3}},r);if(c instanceof Promise){let e=c.then(e=>(n.set(i,{value:e,expiresAt:s}),e));return n.set(i,{value:e,expiresAt:s}),e}return n.set(i,{value:c,expiresAt:s}),c};return r.clear=()=>n.clear(),r.updateTtl=e=>{t=e;let r=Date.now(),i=r+e*1e3;for(let[e,t]of n.entries())t.expiresAt>r&&(t.expiresAt=i,n.set(e,t))},r},r=e=>!e,i=e=>e==null,a=e=>e?.constructor===Object,o=e=>e==null||typeof e!=`object`&&typeof e!=`function`,s=(e,t)=>Array.isArray(e)?e.map(e=>s(e,t)):a(e)?Object.keys(e).reduce((n,r)=>{let i=t(r),a=e[r];return n[i]=s(a,t),n},{}):e,c=(e,t,n)=>{let{filter:r}=n??{};if(Array.isArray(e)){let i=e.map((e,r)=>a(e)?c(e,t,n):t(e,r));return r?i.filter((e,t)=>r(e,t)):i}return a(e)?Object.keys(e).reduce((i,o)=>{let s=e[o],l;return l=a(s)||Array.isArray(s)?c(s,t,n):t(s,o),(!r||r(l,o))&&(i[o]=l),i},{}):e},l=(e,t)=>{let n={...e};for(let e of Object.keys(t)){let r=n[e],i=t[e];if(o(r)&&o(i)){n[e]=i;continue}if(Array.isArray(r)&&Array.isArray(i)){n[e]=r.concat(i);continue}if(a(r)&&a(i)){n[e]=l(r,i);continue}n[e]=i}return n},u=(e,t)=>{let n={...e};for(let e of t)delete n[e];return n},d=(e,t)=>{let n={};for(let[r,i]of Object.entries(e))t(r,i)||(n[r]=i);return n},f=(e,t)=>t.reduce((t,n)=>(Object.hasOwn(e,n)&&(t[n]=e[n]),t),{}),p=(e,t)=>{let n={};for(let[r,i]of Object.entries(e))t(r,i)&&(n[r]=i);return n},m=(e=``,t={})=>{let n=async(n,r={})=>{let o=new URL(e?`${e}${n}`:n),{params:s,parser:c,...u}=l(t,r);a(s)&&Object.entries(s).forEach(([e,t])=>{i(t)||o.searchParams.append(e,t.toString())}),(a(u.body)||Array.isArray(u.body))&&(u.body=JSON.stringify(u.body),u.headers={...u.headers,"Content-Type":`application/json`});let d=await fetch(o,u);if(!d.ok)throw d.headers.get(`Content-Type`)?.startsWith(`application/json`)?await d.json():Error(d.statusText);return await(c?.(d)??d.json())};return{get:(e,t)=>n(e,{...t,method:`GET`}),post:(e,t,r)=>n(e,{...r,method:`POST`,body:t}),put:(e,t,r)=>n(e,{...r,method:`PUT`,body:t}),delete:(e,t)=>n(e,{...t,method:`DELETE`})}},h=async e=>{try{return[null,await e]}catch(e){return[e,void 0]}},g=async e=>{let[t,n]=await h(fetch(e,{method:`HEAD`,redirect:`manual`}));return t?e:n.headers.get(`location`)||e},_=e=>{let t=new Uint8Array(e),n=``;for(let e=0;e<t.byteLength;e++)n+=String.fromCharCode(t[e]);return btoa(n)},v=async()=>{try{let e=await Function(`modulePath`,`return import(modulePath)`)(`sharp`);return e.default||e}catch{return null}},y=async(e,t,n,r)=>{let i=e(Buffer.from(t));if(n===`image/jpeg`)i=i.jpeg({quality:Math.round(r*100)});else if(n===`image/png`){let e=Math.round((1-r)*9);i=i.png({compressionLevel:e})}return`data:${n};base64,${(await i.toBuffer()).toString(`base64`)}`},b=async(e,t={})=>{let{quality:n=.92,compressor:r,fetcher:i=fetch}=t;if(!e.startsWith(`http`))throw Error(`图片地址必须以http或https开头`);let a=await i(e);if(!a.ok)throw Error(`获取图片失败: ${a.statusText}`);let o=a.headers.get(`Content-Type`)||`image/jpeg`,s=await a.arrayBuffer();if(o!==`image/jpeg`&&o!==`image/png`)return`data:${o};base64,${_(s)}`;if(r)return await r(s,o,n);if(typeof OffscreenCanvas<`u`){let e=null;try{let t=new Blob([s],{type:o});e=await createImageBitmap(t);let r=new OffscreenCanvas(e.width,e.height),i=r.getContext(`2d`);if(!i)throw Error(`无法获取 OffscreenCanvas context`);return i.drawImage(e,0,0),e.close(),e=null,`data:${o};base64,${_(await(await r.convertToBlob({type:o,quality:n})).arrayBuffer())}`}catch{return e?.close(),`data:${o};base64,${_(s)}`}}let c=await v();if(c)try{return await y(c,s,o,n)}catch{return`data:${o};base64,${_(s)}`}return`data:${o};base64,${_(s)}`},x=(e,t)=>Math.floor(Math.random()*(t-e+1))+e,S=e=>e.replace(/_([a-zA-Z])/g,(e,t)=>t.toUpperCase()),C=e=>e.replace(/([A-Z])/g,(e,t)=>`_${t.toLowerCase()}`),w=e=>e.charAt(0).toUpperCase()+e.slice(1),T=e=>e.charAt(0).toLowerCase()+e.slice(1),E=(e=``,t)=>{if(!e)return``;let{maxLength:n=1/0,disableNewLineReplace:r=!1,disableCollapse:i=!1}=t??{},a=e;return i||(a=a.replace(/[\n\t]+/g,`
3
- `)),a=r?a.replace(/\r?\n/g,` `):a.replace(/\r?\n/g,`\\n`),a=a.replace(/\s+/g,` `).trim(),n>0&&a.length>n?`${a.slice(0,n)}...`:a},D={parse:e=>{let t=new URLSearchParams(e),n={};for(let[e,r]of t)Number.isNaN(Number(r))?n[e]=r:n[e]=Number(r);return n},stringify:(e,t)=>{let{addQueryPrefix:n=!1}=t??{},r=new URLSearchParams(e).toString();return r?n?`?${r}`:r:``}},O=(e,t=300)=>{let n=null;return(...r)=>{n&&clearTimeout(n),n=setTimeout(()=>{e(...r)},t)}};var k=class{queue;constructor(){this.queue=Promise.resolve()}waitInQueue(){let e,t=new Promise(t=>{e=t}),n=this.queue.then(()=>e);return this.queue=t,n}};const A=async(e=150)=>new Promise(t=>{setTimeout(t,e)}),j=(e,t=300)=>{let n=null;return function(...r){n||=setTimeout(()=>{n=null,e.apply(this,r)},t)}};export{k as LockQueue,C as camelToSnake,w as capitalize,E as compactStr,O as debounce,T as decapitalize,m as fetcher,g as getRealURL,b as imageUrlToBase64,r as isFalsy,i as isNil,a as isObject,o as isPrimitive,e as log,t as loopUntil,s as mapKeys,c as mapValues,l as mergeObjects,u as omit,d as omitBy,f as pick,p as pickBy,D as qs,x as randomInt,A as sleep,S as snakeToCamel,j as throttle,h as to,n as withCache};
1
+ import{t as e}from"./chunk-0Lt9GpW0.mjs";const t=e=>e==null,n=e=>e?.constructor===Object,r=e=>e==null||typeof e!=`object`&&typeof e!=`function`;var i=e({isNil:()=>t,isObject:()=>n,isPrimitive:()=>r});const a=(e,t)=>Array.isArray(e)?e.map(e=>a(e,t)):n(e)?Object.keys(e).reduce((n,r)=>{let i=t(r),o=e[r];return n[i]=a(o,t),n},{}):e,o=(e,t,r)=>{let{filter:i}=r??{};if(Array.isArray(e)){let a=e.map((e,i)=>n(e)?o(e,t,r):t(e,i));return i?a.filter((e,t)=>i(e,t)):a}return n(e)?Object.keys(e).reduce((a,s)=>{let c=e[s],l;return l=n(c)||Array.isArray(c)?o(c,t,r):t(c,s),(!i||i(l,s))&&(a[s]=l),a},{}):e},s=(e,t)=>{let i={...e};for(let e of Object.keys(t)){let a=i[e],o=t[e];if(r(a)&&r(o)){i[e]=o;continue}if(Array.isArray(a)&&Array.isArray(o)){i[e]=a.concat(o);continue}if(n(a)&&n(o)){i[e]=s(a,o);continue}i[e]=o}return i},c=(e,t)=>{let n={...e};for(let e of t)delete n[e];return n},l=(e,t)=>{let n={};for(let[r,i]of Object.entries(e))t(r,i)||(n[r]=i);return n},u=(e,t)=>t.reduce((t,n)=>(Object.hasOwn(e,n)&&(t[n]=e[n]),t),{}),d=(e,t)=>{let n={};for(let[r,i]of Object.entries(e))t(r,i)&&(n[r]=i);return n};var f=e({mapKeys:()=>a,mapValues:()=>o,mergeObjects:()=>s,omit:()=>c,omitBy:()=>l,pick:()=>u,pickBy:()=>d});const p=(e=``,r={})=>{let i=async(i,a={})=>{let o=new URL(e?`${e}${i}`:i),{params:c,parser:l,...u}=s(r,a);n(c)&&Object.entries(c).forEach(([e,n])=>{t(n)||o.searchParams.append(e,n.toString())}),(n(u.body)||Array.isArray(u.body))&&(u.body=JSON.stringify(u.body),u.headers={...u.headers,"Content-Type":`application/json`});let d=await fetch(o,u);if(!d.ok){if(d.headers.get(`Content-Type`)?.startsWith(`application/json`)){let e=await d.json(),t=Error(e.error?.message||d.statusText);throw t.data=e,t}throw Error(d.statusText)}return await(l?.(d)??d.json())};return{get:(e,t)=>i(e,{...t,method:`GET`}),post:(e,t,n)=>i(e,{...n,method:`POST`,body:t}),put:(e,t,n)=>i(e,{...n,method:`PUT`,body:t}),delete:(e,t)=>i(e,{...t,method:`DELETE`})}},m=async e=>{try{return[null,await e]}catch(e){return[e,void 0]}},h=async e=>{let[t,n]=await m(fetch(e,{method:`HEAD`,redirect:`manual`}));return t?e:n.headers.get(`location`)||e},g=e=>{let t=new Uint8Array(e),n=``;for(let e=0;e<t.byteLength;e++)n+=String.fromCharCode(t[e]);return btoa(n)},_=async(e,t={})=>{let{quality:n=.92,compressor:r,fetcher:i=fetch}=t;if(!e.startsWith(`http`))throw Error(`图片地址必须以http或https开头`);let a=await i(e);if(!a.ok)throw Error(`获取图片失败: ${a.statusText}`);let o=a.headers.get(`Content-Type`)||`image/jpeg`,s=await a.arrayBuffer();if(o!==`image/jpeg`&&o!==`image/png`)return`data:${o};base64,${g(s)}`;if(r)return await r(s,o,n);if(typeof OffscreenCanvas<`u`){let e=null;try{let t=new Blob([s],{type:o});e=await createImageBitmap(t);let r=new OffscreenCanvas(e.width,e.height),i=r.getContext(`2d`);if(!i)throw Error(`无法获取 OffscreenCanvas context`);return i.drawImage(e,0,0),e.close(),e=null,`data:${o};base64,${g(await(await r.convertToBlob({type:o,quality:n})).arrayBuffer())}`}catch{return e?.close(),`data:${o};base64,${g(s)}`}}return`data:${o};base64,${g(s)}`};var v=e({fetcher:()=>p,getRealURL:()=>h,imageUrlToBase64:()=>_,to:()=>m});const y=e=>e.replace(/_([a-zA-Z])/g,(e,t)=>t.toUpperCase()),b=e=>e.replace(/([A-Z])/g,(e,t)=>`_${t.toLowerCase()}`),x=e=>e.charAt(0).toUpperCase()+e.slice(1),S=e=>e.charAt(0).toLowerCase()+e.slice(1),C=(e=``,t)=>{if(!e)return``;let{maxLength:n=1/0,disableNewLineReplace:r=!1,disableCollapse:i=!1}=t??{},a=e;return i||(a=a.replace(/[\n\t]+/g,`
2
+ `)),a=r?a.replace(/\r?\n/g,` `):a.replace(/\r?\n/g,`\\n`),a=a.replace(/\s+/g,` `).trim(),n>0&&a.length>n?`${a.slice(0,n)}...`:a},w=e=>{if(e instanceof Error)return e.message;if(typeof e==`string`)return e;if(n(e)){let t=e.message||e.msg;if(t)return t;for(let t of Object.values(e)){let e=w(t);if(e)return e}}return JSON.stringify(e,null,2)},T={parse:e=>{let t=new URLSearchParams(e),n={};for(let[e,r]of t)Number.isNaN(Number(r))?n[e]=r:n[e]=Number(r);return n},stringify:(e,t)=>{let{addQueryPrefix:n=!1}=t??{},r=new URLSearchParams(e).toString();return r?n?`?${r}`:r:``}};var E=e({camelToSnake:()=>b,capitalize:()=>x,compactStr:()=>C,decapitalize:()=>S,extractErrorMessage:()=>w,qs:()=>T,snakeToCamel:()=>y});const D=async e=>{let t=(await e.get(`/models`)).data[0]?.id;if(!t)throw Error(`无法从 /models 获取模型名称`);return t},O=async(e,t,n={})=>{let{model:r,baseURL:i,apiKey:a=``}=e,o=p(i,{headers:{Authorization:`Bearer ${a}`}}),s={model:r??await D(o),messages:t,...n};return o.post(`/chat/completions`,s)},k=async(e,t)=>{let n=t[e.function.name];if(!n)return`没有找到工具“${e.function.name}”的处理函数`;try{let t=await n(JSON.parse(e.function.arguments));return typeof t==`string`?t:JSON.stringify(t)}catch(t){return`工具“${e.function.name}”处理失败:${w(t)}`}},A=e=>typeof e==`string`?e:e.filter(e=>e.type===`text`).map(e=>e.text).join(`
3
+ `),j=async(e,t,n={})=>{let{toolHandlers:r={},...i}=n;for(;;){let{choices:n,usage:a,...o}=await O(e,t,i),{message:s}=n[0]??{};if(!s)throw Error(`模型没有回复任何内容`);let{content:c=``,tool_calls:l=[],...u}=s;if(t.push(s),l.length>0&&Object.keys(r).length>0){for(let e of l){let n=await k(e,r);t.push({role:`tool`,content:n,tool_call_id:e.id})}continue}return{content:A(c),usage:a,...o,...u}}};var M=e({chatCompletions:()=>j});const N=(e,t)=>{let{time:n=!0,fileName:r=!0}=t??{},i=[];if(n&&i.push(`[${new Date().toLocaleTimeString()}]`),r){let{stack:e}=Error(),t=(e?.split(`
4
+ `)[2]?.trim())?.match(/at\s+(.*):(\d+)/);if(t?.[1]){let e=t[1].split(/[/\\]/).pop();i.push(`[${e}:${t[2]}]`)}}Array.isArray(e)?i.push(...e):i.push(e),console.log(...i)};var P=e({log:()=>N});const F=async(e,t)=>{let{maxRetries:n=5,shouldStop:r}=t??{},i;for(let t=0;t<n;t++)if(i=await e(t),r?.(i)===!0)return i;if(!r)return i;throw Error(`超过了最大循环次数(${n})且未满足停止执行条件`)};var I=e({loopUntil:()=>F});const L=(e,t=-1)=>{let n=new Map,r=(...r)=>{let i=JSON.stringify(r),a=Date.now(),o=n.get(i);if(o&&a<o.expiresAt)return o.value;let s=t===-1?1/0:a+t*1e3,c=e.apply({setTtl:e=>{s=a+e*1e3}},r);if(c instanceof Promise){let e=c.then(e=>(n.set(i,{value:e,expiresAt:s}),e));return n.set(i,{value:e,expiresAt:s}),e}return n.set(i,{value:c,expiresAt:s}),c};return r.clear=()=>n.clear(),r.updateTtl=e=>{t=e;let r=Date.now(),i=r+e*1e3;for(let[e,t]of n.entries())t.expiresAt>r&&(t.expiresAt=i,n.set(e,t))},r};var R=e({withCache:()=>L});const z=(e,t)=>Math.floor(Math.random()*(t-e+1))+e;var B=e({randomInt:()=>z});const V=(e,t=300)=>{let n=null;return(...r)=>{n&&clearTimeout(n),n=setTimeout(()=>{e(...r)},t)}};var H=class{queue;constructor(){this.queue=Promise.resolve()}waitInQueue(){let e,t=new Promise(t=>{e=t}),n=this.queue.then(()=>e);return this.queue=t,n}};const U=async(e=150)=>new Promise(t=>{setTimeout(t,e)}),W=(e,t=300)=>{let n=null;return function(...r){n||=setTimeout(()=>{n=null,e.apply(this,r)},t)}};var G=e({LockQueue:()=>H,debounce:()=>V,sleep:()=>U,throttle:()=>W});export{M as ai,P as dom,I as function,R as hoc,i as is,v as network,B as number,f as object,E as string,G as time};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nickyzj2023/utils",
3
- "version": "1.0.63",
3
+ "version": "1.0.65",
4
4
  "type": "module",
5
5
  "main": "dist/index.mjs",
6
6
  "module": "dist/index.mjs",
@@ -17,18 +17,17 @@
17
17
  "scripts": {
18
18
  "build": "tsdown",
19
19
  "docs": "typedoc src/index.ts --plugin typedoc-material-theme",
20
- "check": "biome check --write src/"
20
+ "check": "biome check --diagnostic-level=error --write src/"
21
21
  },
22
22
  "repository": {
23
23
  "type": "git",
24
24
  "url": "https://github.com/Nickyzj628/utils.git"
25
25
  },
26
26
  "devDependencies": {
27
- "@biomejs/biome": "^2.4.11",
28
27
  "@types/node": "^25.6.0",
29
- "tsdown": "^0.21.7",
28
+ "tsdown": "^0.21.10",
30
29
  "typedoc": "^0.28.19",
31
30
  "typedoc-material-theme": "^1.4.1",
32
- "typescript": "^6.0.2"
31
+ "typescript": "^6.0.3"
33
32
  }
34
33
  }