@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/index.mjs CHANGED
@@ -1,18 +1,19 @@
1
- import { createWorker as j } from "tesseract.js";
2
- import { deepCopy as T, objectMap as b, JSONAttemptParse as _, findByProp as k, JSONSanitize as y, Http as q, consoleInterceptor as v, fn as P, ASet as A } from "@ztimson/utils";
3
- import { Anthropic as E } from "@anthropic-ai/sdk";
4
- import { Ollama as M } from "ollama";
5
- import { OpenAI as O } from "openai";
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 * as w from "@tensorflow/tfjs";
9
- import { spawn as $ } from "node:child_process";
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 D extends x {
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 E({ apiKey: e });
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 = T(i);
49
- e.compress && (i = await this.ai.llm.compress(i, e.compress.max, e.compress.min, e));
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((o) => ({
56
- name: o.name,
57
- description: o.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: o.args ? b(o.args, (r, u) => ({ ...u, required: void 0 })) : {},
61
- required: o.args ? Object.entries(o.args).filter((r) => r[1].required).map((r) => r[0]) : []
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 s, p = !0;
69
+ let o, d = !0;
69
70
  do {
70
- if (s = await this.client.messages.create(m), e.stream) {
71
- p ? p = !1 : e.stream({ text: `
71
+ if (o = await this.client.messages.create(m), e.stream) {
72
+ d ? d = !1 : e.stream({ text: `
72
73
 
73
- ` }), s.content = [];
74
- for await (const r of s) {
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" ? s.content.push({ type: "text", text: "" }) : r.content_block.type === "tool_use" && s.content.push({ type: "tool_use", id: r.content_block.id, name: r.content_block.name, input: "" });
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
- s.content.at(-1).text += u, e.stream({ text: u });
82
- } else r.delta.type === "input_json_delta" && (s.content.at(-1).input += r.delta.partial_json);
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 = s.content.at(-1);
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 o = s.content.filter((r) => r.type === "tool_use");
91
- if (o.length && !n.signal.aborted) {
92
- i.push({ role: "assistant", content: s.content }), l.push({ role: "assistant", content: s.content });
93
- const r = await Promise.all(o.map(async (u) => {
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 && s.content.some((o) => o.type === "tool_use"));
106
- e.stream && e.stream({ done: !0 }), c(this.toStandard([...i, { role: "assistant", content: s.content.filter((o) => o.type == "text").map((o) => o.text).join(`
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 I extends x {
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 M({ host: e });
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.llm.compress(l, e.compress.max, e.compress.min)), e.system && l.unshift({ role: "system", content: i });
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((o) => ({
150
+ tools: (e.tools || this.ai.options.tools || []).map((s) => ({
150
151
  type: "function",
151
152
  function: {
152
- name: o.name,
153
- description: o.description,
153
+ name: s.name,
154
+ description: s.description,
154
155
  parameters: {
155
156
  type: "object",
156
- properties: o.args ? b(o.args, (r, u) => ({ ...u, required: void 0 })) : {},
157
- required: o.args ? Object.entries(o.args).filter((r) => r[1].required).map((r) => r[0]) : []
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 s, p = !0;
163
+ let o, d = !0;
163
164
  do {
164
- if (s = await this.client.chat(m), e.stream) {
165
- p ? p = !1 : e.stream({ text: `
165
+ if (o = await this.client.chat(m), e.stream) {
166
+ d ? d = !1 : e.stream({ text: `
166
167
 
167
- ` }), s.message = { role: "assistant", content: "", tool_calls: [] };
168
- for await (const o of s)
169
- if (n.signal.aborted || (o.message?.content && (s.message.content += o.message.content, e.stream({ text: o.message.content })), o.message?.tool_calls && (s.message.tool_calls = o.message.tool_calls), o.done)) break;
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 (s.message?.tool_calls?.length && !n.signal.aborted) {
172
- l.push(s.message);
173
- const o = await Promise.all(s.message.tool_calls.map(async (r) => {
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(...o), m.messages = l;
185
+ l.push(...s), m.messages = l;
185
186
  }
186
- } while (!n.signal.aborted && s.message?.tool_calls?.length);
187
- e.stream && e.stream({ done: !0 }), c(this.toStandard([...l, { role: "assistant", content: s.message?.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 J extends x {
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 O({ apiKey: e });
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.llm.compress(i, e.compress.max, e.compress.min, e));
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((p) => ({
249
+ tools: (e.tools || this.ai.options.tools || []).map((d) => ({
249
250
  type: "function",
250
251
  function: {
251
- name: p.name,
252
- description: p.description,
252
+ name: d.name,
253
+ description: d.description,
253
254
  parameters: {
254
255
  type: "object",
255
- properties: p.args ? b(p.args, (o, r) => ({ ...r, required: void 0 })) : {},
256
- required: p.args ? Object.entries(p.args).filter((o) => o[1].required).map((o) => o[0]) : []
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, s = !0;
262
+ let m, o = !0;
262
263
  do {
263
264
  if (m = await this.client.chat.completions.create(l), e.stream) {
264
- s ? s = !1 : e.stream({ text: `
265
+ o ? o = !1 : e.stream({ text: `
265
266
 
266
267
  ` }), m.choices = [{ message: { content: "", tool_calls: [] } }];
267
- for await (const o of m) {
268
+ for await (const s of m) {
268
269
  if (n.signal.aborted) break;
269
- o.choices[0].delta.content && (m.choices[0].message.content += o.choices[0].delta.content, e.stream({ text: o.choices[0].delta.content })), o.choices[0].delta.tool_calls && (m.choices[0].message.tool_calls = o.choices[0].delta.tool_calls);
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 p = m.choices[0].message.tool_calls || [];
273
- if (p.length && !n.signal.aborted) {
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 o = await Promise.all(p.map(async (r) => {
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(...o), l.messages = i;
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 W {
294
- constructor(t, e) {
295
- this.ai = t, this.options = e, e.anthropic?.token && (this.providers.anthropic = new D(this.ai, e.anthropic.token, e.anthropic.model)), e.ollama?.host && (this.providers.ollama = new I(this.ai, e.ollama.host, e.ollama.model)), e.openAi?.token && (this.providers.openAi = new J(this.ai, e.openAi.token, e.openAi.model));
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 compress(t, e, n, a) {
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 s of t.toReversed())
321
- if (f += this.estimateTokens(s.content), f < n) c++;
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((s) => s.role === "assistant" || s.role === "user");
325
- return [{ role: "assistant", content: `Conversation Summary: ${await this.summarize(l.map((s) => `${s.role}: ${s.content}`).join(`
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 Z {
411
+ class J {
363
412
  constructor(t) {
364
- this.options = t, this.llm = new W(this, t), this.options.whisper?.binary && (this.whisperModel = this.options.whisper?.model.endsWith(".bin") ? this.options.whisper?.model : this.options.whisper?.model + ".bin", this.downloadAsrModel());
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 = $(this.options.whisper?.binary, ["-nt", "-np", "-m", i, "-f", t], { stdio: ["ignore", "pipe", "ignore"] });
384
- n = () => m.kill("SIGTERM"), m.on("error", (s) => f(s)), m.stdout.on("data", (s) => l += s.toString()), m.on("close", (s) => {
385
- s === 0 ? c(l.trim() || null) : f(new Error(`Exit code ${s}`));
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 j("eng");
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
- * Compare the difference between two strings using tensor math
422
- * @param target Text that will checked
423
- * @param {string} searchTerms Multiple search terms to check against target
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 N = {
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: (d) => L`${d.command}`
441
- }, ee = {
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
- }, te = {
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 (d, t) => {
503
+ fn: async (p, t) => {
454
504
  try {
455
- switch (d.type) {
505
+ switch (p.type) {
456
506
  case "bash":
457
- return await N.fn({ command: d.code }, t);
507
+ return await G.fn({ command: p.code }, t);
458
508
  case "node":
459
- return await z.fn({ code: d.code }, t);
509
+ return await F.fn({ code: p.code }, t);
460
510
  case "python":
461
- return await G.fn({ code: d.code }, t);
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
- }, ne = {
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: (d) => new q({ url: d.url, headers: d.headers }).request({ method: d.method || "GET", body: d.body })
477
- }, z = {
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 (d) => {
484
- const t = v(null), e = await P({ console: t }, d.code, !0).catch((n) => t.output.error.push(n));
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
- }, G = {
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 (d) => ({ result: R`python -c "${d.code}"` })
494
- }, se = {
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 (d) => {
502
- const t = await fetch(`https://html.duckduckgo.com/html/?q=${encodeURIComponent(d.query)}`, {
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 A();
556
+ const a = new v();
507
557
  for (; (e = n.exec(t)) !== null; ) {
508
558
  let c = /uddg=(.+)&amp?/.exec(decodeURIComponent(e[1]))?.[1];
509
- if (c && (c = decodeURIComponent(c)), c && a.add(c), a.size >= (d.length || 5)) break;
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
- Z as Ai,
516
- D as Anthropic,
517
- N as CliTool,
518
- ee as DateTimeTool,
519
- te as ExecTool,
520
- ne as FetchTool,
521
- z as JSTool,
522
- W as LLM,
523
- G as PythonTool,
524
- se as SearchTool
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