@ztimson/ai-utils 0.1.22 → 0.2.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.
- package/dist/ai.d.ts +8 -39
- package/dist/audio.d.ts +24 -0
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +219 -166
- package/dist/index.mjs.map +1 -1
- package/dist/llm.d.ts +21 -3
- package/dist/vision.d.ts +14 -0
- package/package.json +2 -1
package/dist/index.mjs
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { deepCopy as T, objectMap as
|
|
3
|
-
import { Anthropic as
|
|
4
|
-
import { Ollama as
|
|
5
|
-
import { OpenAI as
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
1
|
+
import { pipeline as S } from "@xenova/transformers";
|
|
2
|
+
import { deepCopy as T, objectMap as y, JSONAttemptParse as w, findByProp as b, JSONSanitize as _, Http as j, consoleInterceptor as M, fn as q, ASet as A } from "@ztimson/utils";
|
|
3
|
+
import { Anthropic as P } from "@anthropic-ai/sdk";
|
|
4
|
+
import { Ollama as E } from "ollama";
|
|
5
|
+
import { OpenAI as $ } from "openai";
|
|
6
|
+
import { spawn as v } from "node:child_process";
|
|
7
|
+
import x from "node:fs/promises";
|
|
8
|
+
import O from "node:path";
|
|
9
|
+
import { createWorker as U } from "tesseract.js";
|
|
10
10
|
import { $ as L, $Sync as R } from "@ztimson/node-utils";
|
|
11
|
-
class
|
|
11
|
+
class k {
|
|
12
12
|
}
|
|
13
|
-
class D extends
|
|
13
|
+
class D extends k {
|
|
14
14
|
constructor(t, e, n) {
|
|
15
|
-
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new
|
|
15
|
+
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new P({ apiKey: e });
|
|
16
16
|
}
|
|
17
17
|
client;
|
|
18
18
|
toStandard(t) {
|
|
@@ -45,74 +45,74 @@ class D extends x {
|
|
|
45
45
|
ask(t, e = {}) {
|
|
46
46
|
const n = new AbortController(), a = new Promise(async (c, f) => {
|
|
47
47
|
let i = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
48
|
-
const
|
|
49
|
-
e.compress && (i = await this.ai.
|
|
50
|
-
const
|
|
48
|
+
const p = T(i);
|
|
49
|
+
e.compress && (i = await this.ai.language.compressHistory(i, e.compress.max, e.compress.min, e));
|
|
50
|
+
const l = {
|
|
51
51
|
model: e.model || this.model,
|
|
52
52
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
53
53
|
system: e.system || this.ai.options.system || "",
|
|
54
54
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
55
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
56
|
-
name:
|
|
57
|
-
description:
|
|
55
|
+
tools: (e.tools || this.ai.options.tools || []).map((s) => ({
|
|
56
|
+
name: s.name,
|
|
57
|
+
description: s.description,
|
|
58
58
|
input_schema: {
|
|
59
59
|
type: "object",
|
|
60
|
-
properties:
|
|
61
|
-
required:
|
|
60
|
+
properties: s.args ? y(s.args, (r, d) => ({ ...d, required: void 0 })) : {},
|
|
61
|
+
required: s.args ? Object.entries(s.args).filter((r) => r[1].required).map((r) => r[0]) : []
|
|
62
62
|
},
|
|
63
63
|
fn: void 0
|
|
64
64
|
})),
|
|
65
65
|
messages: i,
|
|
66
66
|
stream: !!e.stream
|
|
67
67
|
};
|
|
68
|
-
let
|
|
68
|
+
let o, m = !0;
|
|
69
69
|
do {
|
|
70
|
-
if (
|
|
71
|
-
|
|
70
|
+
if (o = await this.client.messages.create(l), e.stream) {
|
|
71
|
+
m ? m = !1 : e.stream({ text: `
|
|
72
72
|
|
|
73
|
-
` }),
|
|
74
|
-
for await (const r of
|
|
73
|
+
` }), o.content = [];
|
|
74
|
+
for await (const r of o) {
|
|
75
75
|
if (n.signal.aborted) break;
|
|
76
76
|
if (r.type === "content_block_start")
|
|
77
|
-
r.content_block.type === "text" ?
|
|
77
|
+
r.content_block.type === "text" ? o.content.push({ type: "text", text: "" }) : r.content_block.type === "tool_use" && o.content.push({ type: "tool_use", id: r.content_block.id, name: r.content_block.name, input: "" });
|
|
78
78
|
else if (r.type === "content_block_delta")
|
|
79
79
|
if (r.delta.type === "text_delta") {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
} else r.delta.type === "input_json_delta" && (
|
|
80
|
+
const d = r.delta.text;
|
|
81
|
+
o.content.at(-1).text += d, e.stream({ text: d });
|
|
82
|
+
} else r.delta.type === "input_json_delta" && (o.content.at(-1).input += r.delta.partial_json);
|
|
83
83
|
else if (r.type === "content_block_stop") {
|
|
84
|
-
const
|
|
85
|
-
|
|
84
|
+
const d = o.content.at(-1);
|
|
85
|
+
d.input != null && (d.input = d.input ? w(d.input, {}) : {});
|
|
86
86
|
} else if (r.type === "message_stop")
|
|
87
87
|
break;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
const
|
|
91
|
-
if (
|
|
92
|
-
i.push({ role: "assistant", content:
|
|
93
|
-
const r = await Promise.all(
|
|
94
|
-
const h = e.tools?.find(
|
|
95
|
-
if (!h) return { tool_use_id:
|
|
90
|
+
const s = o.content.filter((r) => r.type === "tool_use");
|
|
91
|
+
if (s.length && !n.signal.aborted) {
|
|
92
|
+
i.push({ role: "assistant", content: o.content }), p.push({ role: "assistant", content: o.content });
|
|
93
|
+
const r = await Promise.all(s.map(async (d) => {
|
|
94
|
+
const h = e.tools?.find(b("name", d.name));
|
|
95
|
+
if (!h) return { tool_use_id: d.id, is_error: !0, content: "Tool not found" };
|
|
96
96
|
try {
|
|
97
|
-
const g = await h.fn(
|
|
98
|
-
return { type: "tool_result", tool_use_id:
|
|
97
|
+
const g = await h.fn(d.input, this.ai);
|
|
98
|
+
return { type: "tool_result", tool_use_id: d.id, content: _(g) };
|
|
99
99
|
} catch (g) {
|
|
100
|
-
return { type: "tool_result", tool_use_id:
|
|
100
|
+
return { type: "tool_result", tool_use_id: d.id, is_error: !0, content: g?.message || g?.toString() || "Unknown" };
|
|
101
101
|
}
|
|
102
102
|
}));
|
|
103
|
-
i.push({ role: "user", content: r }),
|
|
103
|
+
i.push({ role: "user", content: r }), l.messages = i;
|
|
104
104
|
}
|
|
105
|
-
} while (!n.signal.aborted &&
|
|
106
|
-
e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content:
|
|
105
|
+
} while (!n.signal.aborted && o.content.some((s) => s.type === "tool_use"));
|
|
106
|
+
e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content: o.content.filter((s) => s.type == "text").map((s) => s.text).join(`
|
|
107
107
|
|
|
108
108
|
`) }]));
|
|
109
109
|
});
|
|
110
110
|
return Object.assign(a, { abort: () => n.abort() });
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
|
-
class
|
|
113
|
+
class z extends k {
|
|
114
114
|
constructor(t, e, n) {
|
|
115
|
-
super(), this.ai = t, this.host = e, this.model = n, this.client = new
|
|
115
|
+
super(), this.ai = t, this.host = e, this.model = n, this.client = new E({ host: e });
|
|
116
116
|
}
|
|
117
117
|
client;
|
|
118
118
|
toStandard(t) {
|
|
@@ -135,63 +135,63 @@ class I extends x {
|
|
|
135
135
|
}
|
|
136
136
|
ask(t, e = {}) {
|
|
137
137
|
const n = new AbortController(), a = new Promise(async (c, f) => {
|
|
138
|
-
let i = e.system || this.ai.options.system,
|
|
139
|
-
|
|
140
|
-
const
|
|
138
|
+
let i = e.system || this.ai.options.system, p = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
139
|
+
p[0].roll == "system" && (i ? p.shift() : i = p.shift()), e.compress && (p = await this.ai.language.compressHistory(p, e.compress.max, e.compress.min)), e.system && p.unshift({ role: "system", content: i });
|
|
140
|
+
const l = {
|
|
141
141
|
model: e.model || this.model,
|
|
142
|
-
messages:
|
|
142
|
+
messages: p,
|
|
143
143
|
stream: !!e.stream,
|
|
144
144
|
signal: n.signal,
|
|
145
145
|
options: {
|
|
146
146
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
147
147
|
num_predict: e.max_tokens || this.ai.options.max_tokens || 4096
|
|
148
148
|
},
|
|
149
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
149
|
+
tools: (e.tools || this.ai.options.tools || []).map((s) => ({
|
|
150
150
|
type: "function",
|
|
151
151
|
function: {
|
|
152
|
-
name:
|
|
153
|
-
description:
|
|
152
|
+
name: s.name,
|
|
153
|
+
description: s.description,
|
|
154
154
|
parameters: {
|
|
155
155
|
type: "object",
|
|
156
|
-
properties:
|
|
157
|
-
required:
|
|
156
|
+
properties: s.args ? y(s.args, (r, d) => ({ ...d, required: void 0 })) : {},
|
|
157
|
+
required: s.args ? Object.entries(s.args).filter((r) => r[1].required).map((r) => r[0]) : []
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
160
|
}))
|
|
161
161
|
};
|
|
162
|
-
let
|
|
162
|
+
let o, m = !0;
|
|
163
163
|
do {
|
|
164
|
-
if (
|
|
165
|
-
|
|
164
|
+
if (o = await this.client.chat(l), e.stream) {
|
|
165
|
+
m ? m = !1 : e.stream({ text: `
|
|
166
166
|
|
|
167
|
-
` }),
|
|
168
|
-
for await (const
|
|
169
|
-
if (n.signal.aborted || (
|
|
167
|
+
` }), o.message = { role: "assistant", content: "", tool_calls: [] };
|
|
168
|
+
for await (const s of o)
|
|
169
|
+
if (n.signal.aborted || (s.message?.content && (o.message.content += s.message.content, e.stream({ text: s.message.content })), s.message?.tool_calls && (o.message.tool_calls = s.message.tool_calls), s.done)) break;
|
|
170
170
|
}
|
|
171
|
-
if (
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
const
|
|
175
|
-
if (!
|
|
176
|
-
const h = typeof r.function.arguments == "string" ?
|
|
171
|
+
if (o.message?.tool_calls?.length && !n.signal.aborted) {
|
|
172
|
+
p.push(o.message);
|
|
173
|
+
const s = await Promise.all(o.message.tool_calls.map(async (r) => {
|
|
174
|
+
const d = (e.tools || this.ai.options.tools)?.find(b("name", r.function.name));
|
|
175
|
+
if (!d) return { role: "tool", tool_name: r.function.name, content: '{"error": "Tool not found"}' };
|
|
176
|
+
const h = typeof r.function.arguments == "string" ? w(r.function.arguments, {}) : r.function.arguments;
|
|
177
177
|
try {
|
|
178
|
-
const g = await
|
|
179
|
-
return { role: "tool", tool_name: r.function.name, args: h, content:
|
|
178
|
+
const g = await d.fn(h, this.ai);
|
|
179
|
+
return { role: "tool", tool_name: r.function.name, args: h, content: _(g) };
|
|
180
180
|
} catch (g) {
|
|
181
|
-
return { role: "tool", tool_name: r.function.name, args: h, content:
|
|
181
|
+
return { role: "tool", tool_name: r.function.name, args: h, content: _({ error: g?.message || g?.toString() || "Unknown" }) };
|
|
182
182
|
}
|
|
183
183
|
}));
|
|
184
|
-
|
|
184
|
+
p.push(...s), l.messages = p;
|
|
185
185
|
}
|
|
186
|
-
} while (!n.signal.aborted &&
|
|
187
|
-
e.stream && e.stream({ done: !0 }), c(this.toStandard([...
|
|
186
|
+
} while (!n.signal.aborted && o.message?.tool_calls?.length);
|
|
187
|
+
e.stream && e.stream({ done: !0 }), c(this.toStandard([...p, { role: "assistant", content: o.message?.content }]));
|
|
188
188
|
});
|
|
189
189
|
return Object.assign(a, { abort: () => n.abort() });
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
-
class
|
|
192
|
+
class H extends k {
|
|
193
193
|
constructor(t, e, n) {
|
|
194
|
-
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new
|
|
194
|
+
super(), this.ai = t, this.apiToken = e, this.model = n, this.client = new $({ apiKey: e });
|
|
195
195
|
}
|
|
196
196
|
client;
|
|
197
197
|
toStandard(t) {
|
|
@@ -202,7 +202,7 @@ class J extends x {
|
|
|
202
202
|
role: "tool",
|
|
203
203
|
id: c.id,
|
|
204
204
|
name: c.function.name,
|
|
205
|
-
args:
|
|
205
|
+
args: w(c.function.arguments, {}),
|
|
206
206
|
timestamp: n.timestamp
|
|
207
207
|
}));
|
|
208
208
|
t.splice(e, 1, ...a), e += a.length - 1;
|
|
@@ -238,62 +238,63 @@ class J extends x {
|
|
|
238
238
|
ask(t, e = {}) {
|
|
239
239
|
const n = new AbortController(), a = new Promise(async (c, f) => {
|
|
240
240
|
let i = this.fromStandard([...e.history || [], { role: "user", content: t, timestamp: Date.now() }]);
|
|
241
|
-
e.compress && (i = await this.ai.
|
|
242
|
-
const
|
|
241
|
+
e.compress && (i = await this.ai.language.compressHistory(i, e.compress.max, e.compress.min, e));
|
|
242
|
+
const p = {
|
|
243
243
|
model: e.model || this.model,
|
|
244
244
|
messages: i,
|
|
245
245
|
stream: !!e.stream,
|
|
246
246
|
max_tokens: e.max_tokens || this.ai.options.max_tokens || 4096,
|
|
247
247
|
temperature: e.temperature || this.ai.options.temperature || 0.7,
|
|
248
|
-
tools: (e.tools || this.ai.options.tools || []).map((
|
|
248
|
+
tools: (e.tools || this.ai.options.tools || []).map((m) => ({
|
|
249
249
|
type: "function",
|
|
250
250
|
function: {
|
|
251
|
-
name:
|
|
252
|
-
description:
|
|
251
|
+
name: m.name,
|
|
252
|
+
description: m.description,
|
|
253
253
|
parameters: {
|
|
254
254
|
type: "object",
|
|
255
|
-
properties:
|
|
256
|
-
required:
|
|
255
|
+
properties: m.args ? y(m.args, (s, r) => ({ ...r, required: void 0 })) : {},
|
|
256
|
+
required: m.args ? Object.entries(m.args).filter((s) => s[1].required).map((s) => s[0]) : []
|
|
257
257
|
}
|
|
258
258
|
}
|
|
259
259
|
}))
|
|
260
260
|
};
|
|
261
|
-
let
|
|
261
|
+
let l, o = !0;
|
|
262
262
|
do {
|
|
263
|
-
if (
|
|
264
|
-
|
|
263
|
+
if (l = await this.client.chat.completions.create(p), e.stream) {
|
|
264
|
+
o ? o = !1 : e.stream({ text: `
|
|
265
265
|
|
|
266
|
-
` }),
|
|
267
|
-
for await (const
|
|
266
|
+
` }), l.choices = [{ message: { content: "", tool_calls: [] } }];
|
|
267
|
+
for await (const s of l) {
|
|
268
268
|
if (n.signal.aborted) break;
|
|
269
|
-
|
|
269
|
+
s.choices[0].delta.content && (l.choices[0].message.content += s.choices[0].delta.content, e.stream({ text: s.choices[0].delta.content })), s.choices[0].delta.tool_calls && (l.choices[0].message.tool_calls = s.choices[0].delta.tool_calls);
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
|
-
const
|
|
273
|
-
if (
|
|
274
|
-
i.push(
|
|
275
|
-
const
|
|
276
|
-
const
|
|
277
|
-
if (!
|
|
272
|
+
const m = l.choices[0].message.tool_calls || [];
|
|
273
|
+
if (m.length && !n.signal.aborted) {
|
|
274
|
+
i.push(l.choices[0].message);
|
|
275
|
+
const s = await Promise.all(m.map(async (r) => {
|
|
276
|
+
const d = e.tools?.find(b("name", r.function.name));
|
|
277
|
+
if (!d) return { role: "tool", tool_call_id: r.id, content: '{"error": "Tool not found"}' };
|
|
278
278
|
try {
|
|
279
|
-
const h =
|
|
280
|
-
return { role: "tool", tool_call_id: r.id, content:
|
|
279
|
+
const h = w(r.function.arguments, {}), g = await d.fn(h, this.ai);
|
|
280
|
+
return { role: "tool", tool_call_id: r.id, content: _(g) };
|
|
281
281
|
} catch (h) {
|
|
282
|
-
return { role: "tool", tool_call_id: r.id, content:
|
|
282
|
+
return { role: "tool", tool_call_id: r.id, content: _({ error: h?.message || h?.toString() || "Unknown" }) };
|
|
283
283
|
}
|
|
284
284
|
}));
|
|
285
|
-
i.push(...
|
|
285
|
+
i.push(...s), p.messages = i;
|
|
286
286
|
}
|
|
287
|
-
} while (!n.signal.aborted &&
|
|
288
|
-
e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content:
|
|
287
|
+
} while (!n.signal.aborted && l.choices?.[0]?.message?.tool_calls?.length);
|
|
288
|
+
e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content: l.choices[0].message.content || "" }]));
|
|
289
289
|
});
|
|
290
290
|
return Object.assign(a, { abort: () => n.abort() });
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
|
-
class
|
|
294
|
-
constructor(t
|
|
295
|
-
this.ai = t, this.
|
|
293
|
+
class N {
|
|
294
|
+
constructor(t) {
|
|
295
|
+
this.ai = t, this.embedModel = S("feature-extraction", "Xenova/all-MiniLM-L6-v2"), t.options.anthropic?.token && (this.providers.anthropic = new D(this.ai, t.options.anthropic.token, t.options.anthropic.model)), t.options.ollama?.host && (this.providers.ollama = new z(this.ai, t.options.ollama.host, t.options.ollama.model)), t.options.openAi?.token && (this.providers.openAi = new H(this.ai, t.options.openAi.token, t.options.openAi.model));
|
|
296
296
|
}
|
|
297
|
+
embedModel;
|
|
297
298
|
providers = {};
|
|
298
299
|
/**
|
|
299
300
|
* Chat with LLM
|
|
@@ -303,7 +304,7 @@ class W {
|
|
|
303
304
|
*/
|
|
304
305
|
ask(t, e = {}) {
|
|
305
306
|
let n = [null, null];
|
|
306
|
-
if (e.model && (typeof e.model == "object" ? n = e.model : n = [e.model, this.options[e.model]?.model]), (!e.model || n[1] == null) && (typeof this.options.model == "object" ? n = this.options.model : n = [this.options.model, this.options[this.options.model]?.model]), !n[0] || !n[1]) throw new Error(`Unknown LLM provider or model: ${n[0]} / ${n[1]}`);
|
|
307
|
+
if (e.model && (typeof e.model == "object" ? n = e.model : n = [e.model, this.ai.options[e.model]?.model]), (!e.model || n[1] == null) && (typeof this.ai.options.model == "object" ? n = this.ai.options.model : n = [this.ai.options.model, this.ai.options[this.ai.options.model]?.model]), !n[0] || !n[1]) throw new Error(`Unknown LLM provider or model: ${n[0]} / ${n[1]}`);
|
|
307
308
|
return this.providers[n[0]].ask(t, { ...e, model: n[1] });
|
|
308
309
|
}
|
|
309
310
|
/**
|
|
@@ -314,18 +315,58 @@ class W {
|
|
|
314
315
|
* @param {LLMRequest} options LLM options
|
|
315
316
|
* @returns {Promise<LLMMessage[]>} New chat history will summary at index 0
|
|
316
317
|
*/
|
|
317
|
-
async
|
|
318
|
+
async compressHistory(t, e, n, a) {
|
|
318
319
|
if (this.estimateTokens(t) < e) return t;
|
|
319
320
|
let c = 0, f = 0;
|
|
320
|
-
for (let
|
|
321
|
-
if (f += this.estimateTokens(
|
|
321
|
+
for (let o of t.toReversed())
|
|
322
|
+
if (f += this.estimateTokens(o.content), f < n) c++;
|
|
322
323
|
else break;
|
|
323
324
|
if (t.length <= c) return t;
|
|
324
|
-
const i = c == 0 ? [] : t.slice(-c),
|
|
325
|
-
return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(
|
|
325
|
+
const i = c == 0 ? [] : t.slice(-c), p = (c == 0 ? t : t.slice(0, -c)).filter((o) => o.role === "assistant" || o.role === "user");
|
|
326
|
+
return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(p.map((o) => `${o.role}: ${o.content}`).join(`
|
|
326
327
|
|
|
327
328
|
`), 250, a)}`, timestamp: Date.now() }, ...i];
|
|
328
329
|
}
|
|
330
|
+
cosineSimilarity(t, e) {
|
|
331
|
+
if (t.length !== e.length) throw new Error("Vectors must be same length");
|
|
332
|
+
let n = 0, a = 0, c = 0;
|
|
333
|
+
for (let i = 0; i < t.length; i++)
|
|
334
|
+
n += t[i] * e[i], a += t[i] * t[i], c += e[i] * e[i];
|
|
335
|
+
const f = Math.sqrt(a) * Math.sqrt(c);
|
|
336
|
+
return f === 0 ? 0 : n / f;
|
|
337
|
+
}
|
|
338
|
+
embedding(t, e = 500, n = 50) {
|
|
339
|
+
const a = (o, m = "") => o == null ? [] : Object.entries(o).flatMap(([s, r]) => {
|
|
340
|
+
const d = m ? `${m}${isNaN(+s) ? `.${s}` : `[${s}]`}` : s;
|
|
341
|
+
if (typeof r == "object" && r !== null && !Array.isArray(r)) return a(r, d);
|
|
342
|
+
const h = Array.isArray(r) ? r.join(", ") : String(r);
|
|
343
|
+
return `${d}: ${h}`;
|
|
344
|
+
}), c = async (o) => {
|
|
345
|
+
const s = await (await this.embedModel)(o, { pooling: "mean", normalize: !0 });
|
|
346
|
+
return Array.from(s.data);
|
|
347
|
+
}, i = (typeof t == "object" ? a(t) : t.split(`
|
|
348
|
+
`)).flatMap((o) => [...o.split(/\s+/).filter((m) => m.trim()), `
|
|
349
|
+
`]), p = [];
|
|
350
|
+
let l = 0;
|
|
351
|
+
for (; l < i.length; ) {
|
|
352
|
+
let o = l, m = "";
|
|
353
|
+
for (; o < i.length; ) {
|
|
354
|
+
const r = i[o], d = m + (m ? " " : "") + r;
|
|
355
|
+
if (this.estimateTokens(d.replace(/\s*\n\s*/g, `
|
|
356
|
+
`)) > e && m) break;
|
|
357
|
+
m = d, o++;
|
|
358
|
+
}
|
|
359
|
+
const s = m.replace(/\s*\n\s*/g, `
|
|
360
|
+
`).trim();
|
|
361
|
+
s && p.push(s), l = o - n, l <= o - i.length + o && (l = o);
|
|
362
|
+
}
|
|
363
|
+
return Promise.all(p.map(async (o, m) => ({
|
|
364
|
+
index: m,
|
|
365
|
+
embedding: await c(o),
|
|
366
|
+
text: o,
|
|
367
|
+
tokens: this.estimateTokens(o)
|
|
368
|
+
})));
|
|
369
|
+
}
|
|
329
370
|
/**
|
|
330
371
|
* Estimate variable as tokens
|
|
331
372
|
* @param history Object to size
|
|
@@ -335,6 +376,17 @@ class W {
|
|
|
335
376
|
const e = JSON.stringify(t);
|
|
336
377
|
return Math.ceil(e.length / 4 * 1.2);
|
|
337
378
|
}
|
|
379
|
+
/**
|
|
380
|
+
* Compare the difference between two strings using tensor math
|
|
381
|
+
* @param target Text that will checked
|
|
382
|
+
* @param {string} searchTerms Multiple search terms to check against target
|
|
383
|
+
* @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical
|
|
384
|
+
*/
|
|
385
|
+
fuzzyMatch(t, ...e) {
|
|
386
|
+
if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
|
|
387
|
+
const n = (f, i = 10) => f.toLowerCase().split("").map((p, l) => p.charCodeAt(0) * (l + 1) % i / i).slice(0, i), a = n(t), c = e.map((f) => n(f)).map((f) => this.cosineSimilarity(a, f));
|
|
388
|
+
return { avg: c.reduce((f, i) => f + i, 0) / c.length, max: Math.max(...c), similarities: c };
|
|
389
|
+
}
|
|
338
390
|
/**
|
|
339
391
|
* Ask a question with JSON response
|
|
340
392
|
* @param {string} message Question
|
|
@@ -346,7 +398,7 @@ class W {
|
|
|
346
398
|
system: "Respond using a JSON blob",
|
|
347
399
|
...e
|
|
348
400
|
});
|
|
349
|
-
return n?.[0]?.content ?
|
|
401
|
+
return n?.[0]?.content ? w(new RegExp("{[sS]*}").exec(n[0].content), {}) : {};
|
|
350
402
|
}
|
|
351
403
|
/**
|
|
352
404
|
* Create a summary of some text
|
|
@@ -359,14 +411,12 @@ class W {
|
|
|
359
411
|
return this.ask(t, { system: `Generate a brief summary <= ${e} tokens. Output nothing else`, temperature: 0.3, ...n }).then((a) => a.pop()?.content || null);
|
|
360
412
|
}
|
|
361
413
|
}
|
|
362
|
-
class
|
|
414
|
+
class I {
|
|
363
415
|
constructor(t) {
|
|
364
|
-
this.
|
|
416
|
+
this.ai = t, t.options.whisper?.binary && (this.whisperModel = t.options.whisper?.model.endsWith(".bin") ? t.options.whisper?.model : t.options.whisper?.model + ".bin", this.downloadAsrModel());
|
|
365
417
|
}
|
|
366
418
|
downloads = {};
|
|
367
419
|
whisperModel;
|
|
368
|
-
/** Large Language Models */
|
|
369
|
-
llm;
|
|
370
420
|
/**
|
|
371
421
|
* Convert audio to text using Auditory Speech Recognition
|
|
372
422
|
* @param {string} path Path to audio
|
|
@@ -374,15 +424,15 @@ class Z {
|
|
|
374
424
|
* @returns {Promise<any>} Extracted text
|
|
375
425
|
*/
|
|
376
426
|
asr(t, e = this.whisperModel) {
|
|
377
|
-
if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
427
|
+
if (!this.ai.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
378
428
|
let n = () => {
|
|
379
429
|
};
|
|
380
430
|
return { response: new Promise((c, f) => {
|
|
381
431
|
this.downloadAsrModel(e).then((i) => {
|
|
382
|
-
let
|
|
383
|
-
const
|
|
384
|
-
n = () =>
|
|
385
|
-
|
|
432
|
+
let p = "";
|
|
433
|
+
const l = v(this.ai.options.whisper?.binary, ["-nt", "-np", "-m", i, "-f", t], { stdio: ["ignore", "pipe", "ignore"] });
|
|
434
|
+
n = () => l.kill("SIGTERM"), l.on("error", (o) => f(o)), l.stdout.on("data", (o) => p += o.toString()), l.on("close", (o) => {
|
|
435
|
+
o === 0 ? c(p.trim() || null) : f(new Error(`Exit code ${o}`));
|
|
386
436
|
});
|
|
387
437
|
});
|
|
388
438
|
}), abort: n };
|
|
@@ -394,10 +444,15 @@ class Z {
|
|
|
394
444
|
* @return {Promise<string>} Absolute path to model file, resolves once downloaded
|
|
395
445
|
*/
|
|
396
446
|
async downloadAsrModel(t = this.whisperModel) {
|
|
397
|
-
if (!this.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
447
|
+
if (!this.ai.options.whisper?.binary) throw new Error("Whisper not configured");
|
|
398
448
|
t.endsWith(".bin") || (t += ".bin");
|
|
399
|
-
const e =
|
|
400
|
-
return await
|
|
449
|
+
const e = O.join(this.ai.options.whisper.path, t);
|
|
450
|
+
return await x.stat(e).then(() => !0).catch(() => !1) ? e : this.downloads[t] ? this.downloads[t] : (this.downloads[t] = fetch(`https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${t}`).then((n) => n.arrayBuffer()).then((n) => Buffer.from(n)).then(async (n) => (await x.writeFile(e, n), delete this.downloads[t], e)), this.downloads[t]);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
class J {
|
|
454
|
+
constructor(t) {
|
|
455
|
+
this.ai = t;
|
|
401
456
|
}
|
|
402
457
|
/**
|
|
403
458
|
* Convert image to text using Optical Character Recognition
|
|
@@ -411,60 +466,58 @@ class Z {
|
|
|
411
466
|
e?.terminate();
|
|
412
467
|
},
|
|
413
468
|
response: new Promise(async (n) => {
|
|
414
|
-
e = await
|
|
469
|
+
e = await U("eng");
|
|
415
470
|
const { data: a } = await e.recognize(t);
|
|
416
471
|
await e.terminate(), n(a.text.trim() || null);
|
|
417
472
|
})
|
|
418
473
|
};
|
|
419
474
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
* @returns {{avg: number, max: number, similarities: number[]}} Similarity values 0-1: 0 = unique, 1 = identical
|
|
425
|
-
*/
|
|
426
|
-
semanticSimilarity(t, ...e) {
|
|
427
|
-
if (e.length < 2) throw new Error("Requires at least 2 strings to compare");
|
|
428
|
-
const n = (i, l = 10) => i.toLowerCase().split("").map((m, s) => m.charCodeAt(0) * (s + 1) % l / l).slice(0, l), a = (i, l) => {
|
|
429
|
-
if (i.length !== l.length) throw new Error("Vectors must be same length");
|
|
430
|
-
const m = w.tensor1d(i), s = w.tensor1d(l), p = w.dot(m, s), o = w.norm(m), r = w.norm(s);
|
|
431
|
-
return o.dataSync()[0] === 0 || r.dataSync()[0] === 0 ? 0 : p.dataSync()[0] / (o.dataSync()[0] * r.dataSync()[0]);
|
|
432
|
-
}, c = n(t), f = e.map((i) => n(i)).map((i) => a(c, i));
|
|
433
|
-
return { avg: f.reduce((i, l) => i + l, 0) / f.length, max: Math.max(...f), similarities: f };
|
|
475
|
+
}
|
|
476
|
+
class ne {
|
|
477
|
+
constructor(t) {
|
|
478
|
+
this.options = t, this.audio = new I(this), this.language = new N(this), this.vision = new J(this);
|
|
434
479
|
}
|
|
480
|
+
downloads = {};
|
|
481
|
+
whisperModel;
|
|
482
|
+
/** Audio processing AI */
|
|
483
|
+
audio;
|
|
484
|
+
/** Language processing AI */
|
|
485
|
+
language;
|
|
486
|
+
/** Vision processing AI */
|
|
487
|
+
vision;
|
|
435
488
|
}
|
|
436
|
-
const
|
|
489
|
+
const W = {
|
|
437
490
|
name: "cli",
|
|
438
491
|
description: "Use the command line interface, returns any output",
|
|
439
492
|
args: { command: { type: "string", description: "Command to run", required: !0 } },
|
|
440
|
-
fn: (
|
|
441
|
-
},
|
|
493
|
+
fn: (u) => L`${u.command}`
|
|
494
|
+
}, oe = {
|
|
442
495
|
name: "get_datetime",
|
|
443
496
|
description: "Get current date and time",
|
|
444
497
|
args: {},
|
|
445
498
|
fn: async () => (/* @__PURE__ */ new Date()).toISOString()
|
|
446
|
-
},
|
|
499
|
+
}, se = {
|
|
447
500
|
name: "exec",
|
|
448
501
|
description: "Run code/scripts",
|
|
449
502
|
args: {
|
|
450
503
|
language: { type: "string", description: "Execution language", enum: ["cli", "node", "python"], required: !0 },
|
|
451
504
|
code: { type: "string", description: "Code to execute", required: !0 }
|
|
452
505
|
},
|
|
453
|
-
fn: async (
|
|
506
|
+
fn: async (u, t) => {
|
|
454
507
|
try {
|
|
455
|
-
switch (
|
|
508
|
+
switch (u.type) {
|
|
456
509
|
case "bash":
|
|
457
|
-
return await
|
|
510
|
+
return await W.fn({ command: u.code }, t);
|
|
458
511
|
case "node":
|
|
459
|
-
return await
|
|
512
|
+
return await G.fn({ code: u.code }, t);
|
|
460
513
|
case "python":
|
|
461
|
-
return await
|
|
514
|
+
return await F.fn({ code: u.code }, t);
|
|
462
515
|
}
|
|
463
516
|
} catch (e) {
|
|
464
517
|
return { error: e?.message || e.toString() };
|
|
465
518
|
}
|
|
466
519
|
}
|
|
467
|
-
},
|
|
520
|
+
}, re = {
|
|
468
521
|
name: "fetch",
|
|
469
522
|
description: "Make HTTP request to URL",
|
|
470
523
|
args: {
|
|
@@ -473,54 +526,54 @@ const N = {
|
|
|
473
526
|
headers: { type: "object", description: "HTTP headers to send", default: {} },
|
|
474
527
|
body: { type: "object", description: "HTTP body to send" }
|
|
475
528
|
},
|
|
476
|
-
fn: (
|
|
477
|
-
},
|
|
529
|
+
fn: (u) => new j({ url: u.url, headers: u.headers }).request({ method: u.method || "GET", body: u.body })
|
|
530
|
+
}, G = {
|
|
478
531
|
name: "exec_javascript",
|
|
479
532
|
description: "Execute commonjs javascript",
|
|
480
533
|
args: {
|
|
481
534
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
482
535
|
},
|
|
483
|
-
fn: async (
|
|
484
|
-
const t =
|
|
536
|
+
fn: async (u) => {
|
|
537
|
+
const t = M(null), e = await q({ console: t }, u.code, !0).catch((n) => t.output.error.push(n));
|
|
485
538
|
return { ...t.output, return: e, stdout: void 0, stderr: void 0 };
|
|
486
539
|
}
|
|
487
|
-
},
|
|
540
|
+
}, F = {
|
|
488
541
|
name: "exec_javascript",
|
|
489
542
|
description: "Execute commonjs javascript",
|
|
490
543
|
args: {
|
|
491
544
|
code: { type: "string", description: "CommonJS javascript", required: !0 }
|
|
492
545
|
},
|
|
493
|
-
fn: async (
|
|
494
|
-
},
|
|
546
|
+
fn: async (u) => ({ result: R`python -c "${u.code}"` })
|
|
547
|
+
}, ae = {
|
|
495
548
|
name: "search",
|
|
496
549
|
description: "Use a search engine to find relevant URLs, should be changed with fetch to scrape sources",
|
|
497
550
|
args: {
|
|
498
551
|
query: { type: "string", description: "Search string", required: !0 },
|
|
499
552
|
length: { type: "string", description: "Number of results to return", default: 5 }
|
|
500
553
|
},
|
|
501
|
-
fn: async (
|
|
502
|
-
const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(
|
|
554
|
+
fn: async (u) => {
|
|
555
|
+
const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(u.query)}`, {
|
|
503
556
|
headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "Accept-Language": "en-US,en;q=0.9" }
|
|
504
557
|
}).then((c) => c.text());
|
|
505
558
|
let e, n = /<a .*?href="(.+?)".+?<\/a>/g;
|
|
506
559
|
const a = new A();
|
|
507
560
|
for (; (e = n.exec(t)) !== null; ) {
|
|
508
561
|
let c = /uddg=(.+)&?/.exec(decodeURIComponent(e[1]))?.[1];
|
|
509
|
-
if (c && (c = decodeURIComponent(c)), c && a.add(c), a.size >= (
|
|
562
|
+
if (c && (c = decodeURIComponent(c)), c && a.add(c), a.size >= (u.length || 5)) break;
|
|
510
563
|
}
|
|
511
564
|
return a;
|
|
512
565
|
}
|
|
513
566
|
};
|
|
514
567
|
export {
|
|
515
|
-
|
|
568
|
+
ne as Ai,
|
|
516
569
|
D as Anthropic,
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
570
|
+
W as CliTool,
|
|
571
|
+
oe as DateTimeTool,
|
|
572
|
+
se as ExecTool,
|
|
573
|
+
re as FetchTool,
|
|
574
|
+
G as JSTool,
|
|
575
|
+
N as LLM,
|
|
576
|
+
F as PythonTool,
|
|
577
|
+
ae as SearchTool
|
|
525
578
|
};
|
|
526
579
|
//# sourceMappingURL=index.mjs.map
|