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