vecbox 0.1.1 → 0.2.2
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/CHANGELOG.md +40 -0
- package/README.md +163 -228
- package/dist/index.cjs +189 -332
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -36
- package/dist/index.d.ts +26 -36
- package/dist/index.js +196 -333
- package/dist/index.js.map +1 -1
- package/dist/llama_embedding-EC3MWSUZ.node +0 -0
- package/native/binding.gyp +65 -0
- package/native/index.js +39 -0
- package/native/llama_embedding_simple.cpp +111 -0
- package/native/package-lock.json +1277 -0
- package/native/package.json +26 -0
- package/package.json +11 -19
- package/src/factory/EmbeddingFactory.ts +0 -4
- package/src/providers/gemini.ts +2 -2
- package/src/providers/llamacpp.ts +118 -170
- package/src/types/index.ts +0 -2
- package/src/providers/claude.ts +0 -78
- package/src/providers/deepseek.ts +0 -115
- package/src/types/deepseek.d.ts +0 -15
- package/src/types/index.d.ts +0 -43
- package/src/types/transformers.d.ts +0 -7
package/dist/index.cjs
CHANGED
|
@@ -5,7 +5,12 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
12
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
13
|
+
};
|
|
9
14
|
var __export = (target, all) => {
|
|
10
15
|
for (var name in all)
|
|
11
16
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,7 +32,65 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
32
|
mod
|
|
28
33
|
));
|
|
29
34
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
-
|
|
35
|
+
|
|
36
|
+
// native/build/Release/llama_embedding.node
|
|
37
|
+
var llama_embedding_default;
|
|
38
|
+
var init_llama_embedding = __esm({
|
|
39
|
+
"native/build/Release/llama_embedding.node"() {
|
|
40
|
+
llama_embedding_default = "./llama_embedding-EC3MWSUZ.node";
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// node-file:/home/inky/Development/vecbox/native/build/Release/llama_embedding.node
|
|
45
|
+
var require_llama_embedding = __commonJS({
|
|
46
|
+
"node-file:/home/inky/Development/vecbox/native/build/Release/llama_embedding.node"(exports2, module2) {
|
|
47
|
+
"use strict";
|
|
48
|
+
init_llama_embedding();
|
|
49
|
+
try {
|
|
50
|
+
module2.exports = require(llama_embedding_default);
|
|
51
|
+
} catch {
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// native/index.js
|
|
57
|
+
var require_native = __commonJS({
|
|
58
|
+
"native/index.js"(exports2, module2) {
|
|
59
|
+
"use strict";
|
|
60
|
+
var binding = require_llama_embedding();
|
|
61
|
+
var LlamaEmbedding = class {
|
|
62
|
+
constructor(modelPath) {
|
|
63
|
+
this.modelPtr = binding.createModel(modelPath);
|
|
64
|
+
if (!this.modelPtr) {
|
|
65
|
+
throw new Error("Failed to load model");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
embed(text) {
|
|
69
|
+
if (typeof text !== "string") {
|
|
70
|
+
throw new Error("Text must be a string");
|
|
71
|
+
}
|
|
72
|
+
const embedding = binding.getEmbedding(this.modelPtr, text);
|
|
73
|
+
if (!embedding) {
|
|
74
|
+
throw new Error("Failed to generate embedding");
|
|
75
|
+
}
|
|
76
|
+
return embedding;
|
|
77
|
+
}
|
|
78
|
+
close() {
|
|
79
|
+
if (this.modelPtr) {
|
|
80
|
+
binding.destroyModel(this.modelPtr);
|
|
81
|
+
this.modelPtr = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
function create(modelPath) {
|
|
86
|
+
return new LlamaEmbedding(modelPath);
|
|
87
|
+
}
|
|
88
|
+
module2.exports = {
|
|
89
|
+
create,
|
|
90
|
+
LlamaEmbedding
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
});
|
|
31
94
|
|
|
32
95
|
// index.ts
|
|
33
96
|
var index_exports = {};
|
|
@@ -53,7 +116,6 @@ var import_openai = __toESM(require("openai"), 1);
|
|
|
53
116
|
// src/providers/base/EmbeddingProvider.ts
|
|
54
117
|
var EmbeddingProvider = class {
|
|
55
118
|
constructor(config2) {
|
|
56
|
-
__publicField(this, "config");
|
|
57
119
|
this.config = config2;
|
|
58
120
|
}
|
|
59
121
|
getModel() {
|
|
@@ -64,8 +126,8 @@ var EmbeddingProvider = class {
|
|
|
64
126
|
return input.text;
|
|
65
127
|
}
|
|
66
128
|
if (input.filePath) {
|
|
67
|
-
const
|
|
68
|
-
return await
|
|
129
|
+
const fs2 = await import("fs/promises");
|
|
130
|
+
return await fs2.readFile(input.filePath, "utf-8");
|
|
69
131
|
}
|
|
70
132
|
throw new Error("Either text or filePath must be provided");
|
|
71
133
|
}
|
|
@@ -74,8 +136,6 @@ var EmbeddingProvider = class {
|
|
|
74
136
|
// src/util/logger.ts
|
|
75
137
|
var _Logger = class _Logger {
|
|
76
138
|
constructor(moduleName = "embedbox", level = 1 /* INFO */) {
|
|
77
|
-
__publicField(this, "currentLevel");
|
|
78
|
-
__publicField(this, "moduleName");
|
|
79
139
|
this.moduleName = moduleName;
|
|
80
140
|
this.currentLevel = level;
|
|
81
141
|
}
|
|
@@ -120,29 +180,28 @@ var _Logger = class _Logger {
|
|
|
120
180
|
}
|
|
121
181
|
// Static methods for quick access
|
|
122
182
|
static debug(message, moduleName) {
|
|
123
|
-
const
|
|
124
|
-
|
|
183
|
+
const logger7 = new _Logger(moduleName || "embedbox");
|
|
184
|
+
logger7.debug(message);
|
|
125
185
|
}
|
|
126
186
|
static info(message, moduleName) {
|
|
127
|
-
const
|
|
128
|
-
|
|
187
|
+
const logger7 = new _Logger(moduleName || "embedbox");
|
|
188
|
+
logger7.info(message);
|
|
129
189
|
}
|
|
130
190
|
static warn(message, moduleName) {
|
|
131
|
-
const
|
|
132
|
-
|
|
191
|
+
const logger7 = new _Logger(moduleName || "embedbox");
|
|
192
|
+
logger7.warn(message);
|
|
133
193
|
}
|
|
134
194
|
static error(message, moduleName) {
|
|
135
|
-
const
|
|
136
|
-
|
|
195
|
+
const logger7 = new _Logger(moduleName || "embedbox");
|
|
196
|
+
logger7.error(message);
|
|
137
197
|
}
|
|
138
198
|
// Method to create a logger instance for a specific module
|
|
139
199
|
static createModuleLogger(moduleName, level) {
|
|
140
200
|
return new _Logger(`embedbox:${moduleName}`, level);
|
|
141
201
|
}
|
|
142
202
|
};
|
|
143
|
-
__publicField(_Logger, "instance");
|
|
144
203
|
// ANSI color codes - simplified for better readability
|
|
145
|
-
|
|
204
|
+
_Logger.COLORS = {
|
|
146
205
|
RESET: "\x1B[0m",
|
|
147
206
|
DEBUG: "\x1B[36m",
|
|
148
207
|
// Cyan
|
|
@@ -152,13 +211,13 @@ __publicField(_Logger, "COLORS", {
|
|
|
152
211
|
// Yellow
|
|
153
212
|
ERROR: "\x1B[31m"
|
|
154
213
|
// Red
|
|
155
|
-
}
|
|
156
|
-
|
|
214
|
+
};
|
|
215
|
+
_Logger.LEVEL_NAMES = {
|
|
157
216
|
[0 /* DEBUG */]: "DEBUG",
|
|
158
217
|
[1 /* INFO */]: "INFO",
|
|
159
218
|
[2 /* WARN */]: "WARN",
|
|
160
219
|
[3 /* ERROR */]: "ERROR"
|
|
161
|
-
}
|
|
220
|
+
};
|
|
162
221
|
var Logger = _Logger;
|
|
163
222
|
var logger = Logger.getInstance();
|
|
164
223
|
|
|
@@ -167,7 +226,6 @@ var logger2 = Logger.createModuleLogger("openai");
|
|
|
167
226
|
var OpenAIProvider = class extends EmbeddingProvider {
|
|
168
227
|
constructor(config2) {
|
|
169
228
|
super(config2);
|
|
170
|
-
__publicField(this, "client");
|
|
171
229
|
if (!config2.apiKey) {
|
|
172
230
|
throw new Error("OpenAI API key is required");
|
|
173
231
|
}
|
|
@@ -256,7 +314,6 @@ var logger3 = Logger.createModuleLogger("gemini");
|
|
|
256
314
|
var GeminiProvider = class extends EmbeddingProvider {
|
|
257
315
|
constructor(config2) {
|
|
258
316
|
super(config2);
|
|
259
|
-
__publicField(this, "client");
|
|
260
317
|
if (!config2.apiKey) {
|
|
261
318
|
throw new Error("Google API key is required");
|
|
262
319
|
}
|
|
@@ -307,11 +364,11 @@ var GeminiProvider = class extends EmbeddingProvider {
|
|
|
307
364
|
}
|
|
308
365
|
getDimensions() {
|
|
309
366
|
const model = this.getModel();
|
|
310
|
-
if (model.includes("gemini-embedding-001")) return
|
|
367
|
+
if (model.includes("gemini-embedding-001")) return 3072;
|
|
311
368
|
if (model.includes("text-embedding-004")) return 768;
|
|
312
369
|
if (model.includes("embedding-001")) return 768;
|
|
313
370
|
if (model.includes("multimodalembedding")) return 768;
|
|
314
|
-
return
|
|
371
|
+
return 3072;
|
|
315
372
|
}
|
|
316
373
|
getProviderName() {
|
|
317
374
|
return "Google Gemini";
|
|
@@ -333,71 +390,12 @@ var GeminiProvider = class extends EmbeddingProvider {
|
|
|
333
390
|
}
|
|
334
391
|
};
|
|
335
392
|
|
|
336
|
-
// src/providers/claude.ts
|
|
337
|
-
var import_sdk = __toESM(require("@anthropic-ai/sdk"), 1);
|
|
338
|
-
var logger4 = Logger.createModuleLogger("claude");
|
|
339
|
-
var ClaudeProvider = class extends EmbeddingProvider {
|
|
340
|
-
constructor(config2) {
|
|
341
|
-
super(config2);
|
|
342
|
-
__publicField(this, "client");
|
|
343
|
-
if (!config2.apiKey) {
|
|
344
|
-
throw new Error("Anthropic API key is required");
|
|
345
|
-
}
|
|
346
|
-
this.client = new import_sdk.default({
|
|
347
|
-
apiKey: config2.apiKey,
|
|
348
|
-
baseURL: config2.baseUrl,
|
|
349
|
-
timeout: config2.timeout || 3e4
|
|
350
|
-
});
|
|
351
|
-
logger4.info("Claude provider initialized");
|
|
352
|
-
}
|
|
353
|
-
async embed() {
|
|
354
|
-
try {
|
|
355
|
-
logger4.debug(`Embedding text with model: ${this.getModel()}`);
|
|
356
|
-
throw new Error("Claude embeddings API not yet available. Please use another provider.");
|
|
357
|
-
} catch (error) {
|
|
358
|
-
const errorMessage = error instanceof Error ? error instanceof Error ? error.message : String(error) : "Unknown error";
|
|
359
|
-
logger4.error(`Claude embedding failed: ${errorMessage}`);
|
|
360
|
-
throw error;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
async embedBatch() {
|
|
364
|
-
try {
|
|
365
|
-
throw new Error("Claude embeddings API not yet available. Please use another provider.");
|
|
366
|
-
} catch (error) {
|
|
367
|
-
const errorMessage = error instanceof Error ? error instanceof Error ? error.message : String(error) : "Unknown error";
|
|
368
|
-
logger4.error(`Claude batch embedding failed: ${errorMessage}`);
|
|
369
|
-
throw error;
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
getDimensions() {
|
|
373
|
-
return 0;
|
|
374
|
-
}
|
|
375
|
-
getProviderName() {
|
|
376
|
-
return "Anthropic Claude";
|
|
377
|
-
}
|
|
378
|
-
async isReady() {
|
|
379
|
-
try {
|
|
380
|
-
await this.client.messages.create({
|
|
381
|
-
model: "claude-3-haiku-20240307",
|
|
382
|
-
max_tokens: 10,
|
|
383
|
-
messages: [{ role: "user", content: "test" }]
|
|
384
|
-
});
|
|
385
|
-
return true;
|
|
386
|
-
} catch (error) {
|
|
387
|
-
const errorMessage = error instanceof Error ? error instanceof Error ? error.message : String(error) : "Unknown error";
|
|
388
|
-
logger4.error(`Claude readiness check failed: ${errorMessage}`);
|
|
389
|
-
return false;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
|
|
394
393
|
// src/providers/mistral.ts
|
|
395
394
|
var import_mistralai = require("@mistralai/mistralai");
|
|
396
|
-
var
|
|
395
|
+
var logger4 = Logger.createModuleLogger("mistral");
|
|
397
396
|
var MistralProvider = class extends EmbeddingProvider {
|
|
398
397
|
constructor(config2) {
|
|
399
398
|
super(config2);
|
|
400
|
-
__publicField(this, "client");
|
|
401
399
|
if (!config2.apiKey) {
|
|
402
400
|
throw new Error("Mistral API key is required");
|
|
403
401
|
}
|
|
@@ -406,12 +404,12 @@ var MistralProvider = class extends EmbeddingProvider {
|
|
|
406
404
|
serverURL: config2.baseUrl,
|
|
407
405
|
timeoutMs: config2.timeout || 3e4
|
|
408
406
|
});
|
|
409
|
-
|
|
407
|
+
logger4.info("Mistral provider initialized");
|
|
410
408
|
}
|
|
411
409
|
async embed(input) {
|
|
412
410
|
try {
|
|
413
411
|
const text = await this.readInput(input);
|
|
414
|
-
|
|
412
|
+
logger4.debug(`Embedding text with model: ${this.getModel()}`);
|
|
415
413
|
const response = await this.client.embeddings.create({
|
|
416
414
|
model: this.getModel(),
|
|
417
415
|
inputs: [text]
|
|
@@ -431,14 +429,14 @@ var MistralProvider = class extends EmbeddingProvider {
|
|
|
431
429
|
} : void 0
|
|
432
430
|
};
|
|
433
431
|
} catch (error) {
|
|
434
|
-
|
|
432
|
+
logger4.error(`Mistral embedding failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
435
433
|
throw error;
|
|
436
434
|
}
|
|
437
435
|
}
|
|
438
436
|
async embedBatch(inputs) {
|
|
439
437
|
try {
|
|
440
438
|
const texts = await Promise.all(inputs.map((input) => this.readInput(input)));
|
|
441
|
-
|
|
439
|
+
logger4.debug(`Batch embedding ${texts.length} texts with model: ${this.getModel()}`);
|
|
442
440
|
const response = await this.client.embeddings.create({
|
|
443
441
|
model: this.getModel(),
|
|
444
442
|
inputs: texts
|
|
@@ -458,7 +456,7 @@ var MistralProvider = class extends EmbeddingProvider {
|
|
|
458
456
|
} : void 0
|
|
459
457
|
};
|
|
460
458
|
} catch (error) {
|
|
461
|
-
|
|
459
|
+
logger4.error(`Mistral batch embedding failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
462
460
|
throw error;
|
|
463
461
|
}
|
|
464
462
|
}
|
|
@@ -478,100 +476,7 @@ var MistralProvider = class extends EmbeddingProvider {
|
|
|
478
476
|
});
|
|
479
477
|
return response.data.length > 0;
|
|
480
478
|
} catch (error) {
|
|
481
|
-
|
|
482
|
-
return false;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
};
|
|
486
|
-
|
|
487
|
-
// src/providers/deepseek.ts
|
|
488
|
-
var import_deepseek = require("deepseek");
|
|
489
|
-
var logger6 = Logger.createModuleLogger("deepseek");
|
|
490
|
-
var DeepSeekProvider = class extends EmbeddingProvider {
|
|
491
|
-
constructor(config2) {
|
|
492
|
-
super(config2);
|
|
493
|
-
__publicField(this, "client");
|
|
494
|
-
if (!config2.apiKey) {
|
|
495
|
-
throw new Error("DeepSeek API key is required");
|
|
496
|
-
}
|
|
497
|
-
const clientOptions = {
|
|
498
|
-
apiKey: config2.apiKey,
|
|
499
|
-
timeout: config2.timeout || 3e4
|
|
500
|
-
};
|
|
501
|
-
if (config2.baseUrl) {
|
|
502
|
-
clientOptions.baseURL = config2.baseUrl;
|
|
503
|
-
}
|
|
504
|
-
this.client = new import_deepseek.DeepSeek(clientOptions);
|
|
505
|
-
logger6.info("DeepSeek provider initialized");
|
|
506
|
-
}
|
|
507
|
-
async embed(input) {
|
|
508
|
-
try {
|
|
509
|
-
const text = await this.readInput(input);
|
|
510
|
-
logger6.debug(`Embedding text with model: ${this.getModel()}`);
|
|
511
|
-
const response = await this.client.embeddings.create({
|
|
512
|
-
model: this.getModel(),
|
|
513
|
-
input: text
|
|
514
|
-
});
|
|
515
|
-
const embedding = response.data[0];
|
|
516
|
-
if (!embedding) {
|
|
517
|
-
throw new Error("No embedding returned from DeepSeek API");
|
|
518
|
-
}
|
|
519
|
-
return {
|
|
520
|
-
embedding: embedding.embedding || [],
|
|
521
|
-
dimensions: embedding.embedding?.length || 0,
|
|
522
|
-
model: embedding.model || this.getModel(),
|
|
523
|
-
provider: "deepseek",
|
|
524
|
-
usage: response.usage ? {
|
|
525
|
-
promptTokens: response.usage.prompt_tokens,
|
|
526
|
-
totalTokens: response.usage.total_tokens
|
|
527
|
-
} : void 0
|
|
528
|
-
};
|
|
529
|
-
} catch (error) {
|
|
530
|
-
logger6.error(`DeepSeek embedding failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
531
|
-
throw error;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
async embedBatch(inputs) {
|
|
535
|
-
try {
|
|
536
|
-
const texts = await Promise.all(inputs.map((input) => this.readInput(input)));
|
|
537
|
-
logger6.debug(`Batch embedding ${texts.length} texts with model: ${this.getModel()}`);
|
|
538
|
-
const response = await this.client.embeddings.create({
|
|
539
|
-
model: this.getModel(),
|
|
540
|
-
input: texts
|
|
541
|
-
});
|
|
542
|
-
const embeddings = response.data.map((item) => item.embedding);
|
|
543
|
-
return {
|
|
544
|
-
embeddings,
|
|
545
|
-
dimensions: embeddings[0]?.length || 0,
|
|
546
|
-
model: response.model,
|
|
547
|
-
provider: "deepseek",
|
|
548
|
-
usage: response.usage ? {
|
|
549
|
-
promptTokens: response.usage.prompt_tokens,
|
|
550
|
-
totalTokens: response.usage.total_tokens
|
|
551
|
-
} : void 0
|
|
552
|
-
};
|
|
553
|
-
} catch (error) {
|
|
554
|
-
logger6.error(`DeepSeek batch embedding failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
555
|
-
throw error;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
getDimensions() {
|
|
559
|
-
const model = this.getModel();
|
|
560
|
-
if (model.includes("deepseek-chat")) return 4096;
|
|
561
|
-
return 4096;
|
|
562
|
-
}
|
|
563
|
-
getProviderName() {
|
|
564
|
-
return "DeepSeek";
|
|
565
|
-
}
|
|
566
|
-
async isReady() {
|
|
567
|
-
try {
|
|
568
|
-
await this.client.embeddings.create({
|
|
569
|
-
model: this.getModel(),
|
|
570
|
-
input: "test"
|
|
571
|
-
});
|
|
572
|
-
return true;
|
|
573
|
-
} catch (error) {
|
|
574
|
-
logger6.error(`DeepSeek readiness check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
479
|
+
logger4.error(`Mistral readiness check failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
575
480
|
return false;
|
|
576
481
|
}
|
|
577
482
|
}
|
|
@@ -579,16 +484,31 @@ var DeepSeekProvider = class extends EmbeddingProvider {
|
|
|
579
484
|
|
|
580
485
|
// src/providers/llamacpp.ts
|
|
581
486
|
var import_promises = require("fs/promises");
|
|
582
|
-
var
|
|
583
|
-
|
|
487
|
+
var nativeModule = null;
|
|
488
|
+
try {
|
|
489
|
+
nativeModule = require_native();
|
|
490
|
+
logger.info("Using native Llama.cpp module");
|
|
491
|
+
} catch (error) {
|
|
492
|
+
logger.warn("Native module not available, falling back to HTTP");
|
|
493
|
+
}
|
|
584
494
|
var LlamaCppProvider = class extends EmbeddingProvider {
|
|
585
495
|
constructor(config2) {
|
|
586
496
|
super({ ...config2, provider: "llamacpp" });
|
|
587
|
-
|
|
588
|
-
__publicField(this, "modelPath");
|
|
497
|
+
this.nativeModel = null;
|
|
589
498
|
this.modelPath = config2.model || "nomic-embed-text-v1.5.Q4_K_M.gguf";
|
|
590
499
|
this.llamaPath = config2.llamaPath || "./llama.cpp/build/bin/llama-embedding";
|
|
591
|
-
|
|
500
|
+
this.useNative = !!nativeModule;
|
|
501
|
+
if (this.useNative) {
|
|
502
|
+
try {
|
|
503
|
+
this.nativeModel = nativeModule.create(this.modelPath);
|
|
504
|
+
logger.info(`Llama.cpp provider initialized with native module: ${this.modelPath}`);
|
|
505
|
+
} catch (error) {
|
|
506
|
+
logger.error(`Failed to initialize native module: ${error}`);
|
|
507
|
+
this.useNative = false;
|
|
508
|
+
}
|
|
509
|
+
} else {
|
|
510
|
+
logger.info(`Llama.cpp provider initialized with HTTP fallback: ${this.modelPath}`);
|
|
511
|
+
}
|
|
592
512
|
}
|
|
593
513
|
// Public API methods
|
|
594
514
|
getProviderName() {
|
|
@@ -605,6 +525,9 @@ var LlamaCppProvider = class extends EmbeddingProvider {
|
|
|
605
525
|
}
|
|
606
526
|
async isReady() {
|
|
607
527
|
try {
|
|
528
|
+
if (this.useNative && this.nativeModel) {
|
|
529
|
+
return true;
|
|
530
|
+
}
|
|
608
531
|
await (0, import_promises.access)(this.llamaPath, import_promises.constants.F_OK);
|
|
609
532
|
await (0, import_promises.access)(this.llamaPath, import_promises.constants.X_OK);
|
|
610
533
|
const modelPath = await this.getModelPath();
|
|
@@ -616,6 +539,28 @@ var LlamaCppProvider = class extends EmbeddingProvider {
|
|
|
616
539
|
return false;
|
|
617
540
|
}
|
|
618
541
|
}
|
|
542
|
+
async loadGGUFModel(modelPath) {
|
|
543
|
+
try {
|
|
544
|
+
logger.debug(`Loading GGUF model from: ${modelPath}`);
|
|
545
|
+
const modelBuffer = await fs.readFile(modelPath);
|
|
546
|
+
if (!modelBuffer) {
|
|
547
|
+
throw new Error(`Failed to read model file: ${modelPath}`);
|
|
548
|
+
}
|
|
549
|
+
logger.debug(`Model file loaded, size: ${modelBuffer.length} bytes`);
|
|
550
|
+
return modelBuffer;
|
|
551
|
+
} catch (error) {
|
|
552
|
+
logger.error(`Failed to load GGUF model: ${error instanceof Error ? error.message : String(error)}`);
|
|
553
|
+
throw error;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
generateEmbedding(modelBuffer, text) {
|
|
557
|
+
logger.debug(`Generating embedding with model buffer (${modelBuffer.length} bytes)`);
|
|
558
|
+
const embedding = [];
|
|
559
|
+
for (let i = 0; i < Math.min(text.length, 768); i++) {
|
|
560
|
+
embedding.push(Math.sin(i * 0.1) * (i % 10));
|
|
561
|
+
}
|
|
562
|
+
return embedding;
|
|
563
|
+
}
|
|
619
564
|
async embed(input) {
|
|
620
565
|
try {
|
|
621
566
|
logger.debug(`Embedding text with llama.cpp: ${this.getModel()}`);
|
|
@@ -623,20 +568,16 @@ var LlamaCppProvider = class extends EmbeddingProvider {
|
|
|
623
568
|
if (!text.trim()) {
|
|
624
569
|
throw new Error("Text input cannot be empty");
|
|
625
570
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
dimensions: embedding.length,
|
|
637
|
-
model: this.getModel(),
|
|
638
|
-
provider: "llamacpp"
|
|
639
|
-
};
|
|
571
|
+
if (this.useNative && this.nativeModel) {
|
|
572
|
+
const embedding = this.nativeModel.embed(text);
|
|
573
|
+
return {
|
|
574
|
+
embedding,
|
|
575
|
+
dimensions: embedding.length,
|
|
576
|
+
model: this.getModel(),
|
|
577
|
+
provider: "llamacpp"
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
throw new Error("Direct Llama.cpp core integration not yet implemented. Please use HTTP fallback or wait for next version.");
|
|
640
581
|
} catch (error) {
|
|
641
582
|
logger.error(`Llama.cpp embedding failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
642
583
|
throw error;
|
|
@@ -645,6 +586,25 @@ var LlamaCppProvider = class extends EmbeddingProvider {
|
|
|
645
586
|
async embedBatch(inputs) {
|
|
646
587
|
try {
|
|
647
588
|
logger.debug(`Batch embedding ${inputs.length} texts with llama.cpp`);
|
|
589
|
+
if (this.useNative && this.nativeModel) {
|
|
590
|
+
const embeddings2 = [];
|
|
591
|
+
for (const input of inputs) {
|
|
592
|
+
const text = await this.readInput(input);
|
|
593
|
+
if (text.trim()) {
|
|
594
|
+
const embedding = this.nativeModel.embed(text);
|
|
595
|
+
embeddings2.push(embedding);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (embeddings2.length === 0) {
|
|
599
|
+
throw new Error("No valid texts to embed");
|
|
600
|
+
}
|
|
601
|
+
return {
|
|
602
|
+
embeddings: embeddings2,
|
|
603
|
+
dimensions: embeddings2[0]?.length || 0,
|
|
604
|
+
model: this.getModel(),
|
|
605
|
+
provider: "llamacpp"
|
|
606
|
+
};
|
|
607
|
+
}
|
|
648
608
|
const texts = [];
|
|
649
609
|
for (const input of inputs) {
|
|
650
610
|
const text = await this.readInput(input);
|
|
@@ -656,15 +616,15 @@ var LlamaCppProvider = class extends EmbeddingProvider {
|
|
|
656
616
|
throw new Error("No valid texts to embed");
|
|
657
617
|
}
|
|
658
618
|
const modelPath = await this.getModelPath();
|
|
659
|
-
const requests = inputs.map((input) => ({
|
|
619
|
+
const requests = inputs.map((input, v) => ({
|
|
660
620
|
input: input.text || "",
|
|
661
621
|
model: modelPath,
|
|
662
622
|
pooling: "mean",
|
|
663
623
|
normalize: 2
|
|
664
624
|
}));
|
|
665
625
|
const embeddings = [];
|
|
666
|
-
for (const
|
|
667
|
-
const result = await this.executeLlamaEmbedding([JSON.stringify(
|
|
626
|
+
for (const request of requests) {
|
|
627
|
+
const result = await this.executeLlamaEmbedding([JSON.stringify(request)]);
|
|
668
628
|
const embedding = this.parseRawOutput(result.stdout);
|
|
669
629
|
embeddings.push(embedding);
|
|
670
630
|
}
|
|
@@ -679,127 +639,29 @@ var LlamaCppProvider = class extends EmbeddingProvider {
|
|
|
679
639
|
throw error;
|
|
680
640
|
}
|
|
681
641
|
}
|
|
682
|
-
//
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
686
|
-
// Private helper methods
|
|
687
|
-
async getModelPath() {
|
|
688
|
-
const possiblePaths = [
|
|
689
|
-
this.modelPath,
|
|
690
|
-
// As provided
|
|
691
|
-
(0, import_path.join)("./llama.cpp/models", this.modelPath),
|
|
692
|
-
// In llama.cpp/models
|
|
693
|
-
(0, import_path.join)("./llama.cpp", this.modelPath),
|
|
694
|
-
// In llama.cpp root
|
|
695
|
-
this.modelPath
|
|
696
|
-
// Fallback
|
|
697
|
-
];
|
|
698
|
-
for (const path of possiblePaths) {
|
|
699
|
-
try {
|
|
700
|
-
await (0, import_promises.access)(path, import_promises.constants.F_OK);
|
|
701
|
-
return (0, import_path.resolve)(path);
|
|
702
|
-
} catch {
|
|
703
|
-
continue;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
throw new Error(`Model file not found: ${this.modelPath}`);
|
|
707
|
-
}
|
|
708
|
-
async executeLlamaEmbedding(args) {
|
|
709
|
-
return new Promise((resolve2, reject) => {
|
|
710
|
-
const port = 8080;
|
|
711
|
-
let requestBody;
|
|
642
|
+
// Cleanup method
|
|
643
|
+
async cleanup() {
|
|
644
|
+
if (this.useNative && this.nativeModel) {
|
|
712
645
|
try {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
646
|
+
this.nativeModel.close();
|
|
647
|
+
this.nativeModel = null;
|
|
648
|
+
logger.info("Native Llama.cpp model closed");
|
|
649
|
+
} catch (error) {
|
|
650
|
+
logger.error(`Error closing native model: ${error}`);
|
|
717
651
|
}
|
|
718
|
-
const postData = JSON.stringify(requestBody);
|
|
719
|
-
const options = {
|
|
720
|
-
hostname: "localhost",
|
|
721
|
-
port,
|
|
722
|
-
path: "/embedding",
|
|
723
|
-
method: "POST",
|
|
724
|
-
headers: {
|
|
725
|
-
"Content-Type": "application/json",
|
|
726
|
-
"Content-Length": Buffer.byteLength(postData)
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
const req = http.request(options, (res) => {
|
|
730
|
-
let data = "";
|
|
731
|
-
res.on("data", (chunk) => {
|
|
732
|
-
data += chunk;
|
|
733
|
-
});
|
|
734
|
-
res.on("end", () => {
|
|
735
|
-
if (res.statusCode === 200) {
|
|
736
|
-
resolve2({ stdout: data, stderr: "" });
|
|
737
|
-
} else {
|
|
738
|
-
reject(new Error(`HTTP ${res.statusCode}: ${data}`));
|
|
739
|
-
}
|
|
740
|
-
});
|
|
741
|
-
});
|
|
742
|
-
req.on("error", (error) => {
|
|
743
|
-
reject(new Error(`Failed to connect to llama.cpp server: ${error instanceof Error ? error.message : String(error)}`));
|
|
744
|
-
});
|
|
745
|
-
req.write(postData);
|
|
746
|
-
req.end();
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
parseRawOutput(output) {
|
|
750
|
-
try {
|
|
751
|
-
const response = JSON.parse(output);
|
|
752
|
-
logger.debug(`PARSE DEBUG: Response type: ${typeof response}`);
|
|
753
|
-
logger.debug(`PARSE DEBUG: Is Array: ${Array.isArray(response)}`);
|
|
754
|
-
if (Array.isArray(response) && response.length > 0) {
|
|
755
|
-
const first = response[0];
|
|
756
|
-
if (first && first.embedding && Array.isArray(first.embedding)) {
|
|
757
|
-
const emb = first.embedding;
|
|
758
|
-
if (Array.isArray(emb[0])) {
|
|
759
|
-
const flat = emb[0];
|
|
760
|
-
logger.debug(`Parsed ${flat.length} dimensions (nested)`);
|
|
761
|
-
return flat;
|
|
762
|
-
}
|
|
763
|
-
logger.debug(`Parsed ${emb.length} dimensions (direct)`);
|
|
764
|
-
return emb;
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
if (response.embedding && Array.isArray(response.embedding)) {
|
|
768
|
-
const emb = response.embedding;
|
|
769
|
-
if (Array.isArray(emb[0])) {
|
|
770
|
-
return emb[0];
|
|
771
|
-
}
|
|
772
|
-
return emb;
|
|
773
|
-
}
|
|
774
|
-
if (Array.isArray(response) && typeof response[0] === "number") {
|
|
775
|
-
logger.debug(`Parsed ${response.length} dimensions (flat array)`);
|
|
776
|
-
return response;
|
|
777
|
-
}
|
|
778
|
-
throw new Error(`Unexpected format: ${JSON.stringify(Object.keys(response))}`);
|
|
779
|
-
} catch (error) {
|
|
780
|
-
const errorMessage = error instanceof Error ? error instanceof Error ? error.message : String(error) : "Unknown error";
|
|
781
|
-
throw new Error(`Parse failed: ${errorMessage}`, { cause: error });
|
|
782
652
|
}
|
|
783
653
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
if (matches.length === 0) {
|
|
788
|
-
throw new Error("No array embeddings found in output");
|
|
789
|
-
}
|
|
790
|
-
const embeddings = matches.map((match) => {
|
|
791
|
-
const values = match[1]?.split(",").map((v) => v.trim()) || [];
|
|
792
|
-
return values.map((v) => parseFloat(v)).filter((v) => !isNaN(v));
|
|
793
|
-
}).filter((embedding) => embedding.length > 0);
|
|
794
|
-
return embeddings;
|
|
654
|
+
// Protected methods
|
|
655
|
+
getModel() {
|
|
656
|
+
return this.modelPath;
|
|
795
657
|
}
|
|
796
658
|
};
|
|
797
659
|
|
|
798
660
|
// src/factory/EmbeddingFactory.ts
|
|
799
|
-
var
|
|
661
|
+
var logger5 = Logger.createModuleLogger("factory");
|
|
800
662
|
var EmbeddingFactory = class {
|
|
801
663
|
static create(config2) {
|
|
802
|
-
|
|
664
|
+
logger5.info(`Creating provider: ${config2.provider}`);
|
|
803
665
|
const ProviderClass = this.providers.get(config2.provider);
|
|
804
666
|
if (!ProviderClass) {
|
|
805
667
|
throw new Error(`Unsupported provider: ${config2.provider}`);
|
|
@@ -810,54 +672,51 @@ var EmbeddingFactory = class {
|
|
|
810
672
|
return Array.from(this.providers.keys());
|
|
811
673
|
}
|
|
812
674
|
};
|
|
813
|
-
|
|
675
|
+
EmbeddingFactory.providers = /* @__PURE__ */ new Map([
|
|
814
676
|
["openai", OpenAIProvider],
|
|
815
677
|
["gemini", GeminiProvider],
|
|
816
|
-
["claude", ClaudeProvider],
|
|
817
678
|
["mistral", MistralProvider],
|
|
818
|
-
["deepseek", DeepSeekProvider],
|
|
819
679
|
["llamacpp", LlamaCppProvider]
|
|
820
680
|
// Local embeddings with llama.cpp
|
|
821
|
-
])
|
|
681
|
+
]);
|
|
822
682
|
|
|
823
683
|
// main.ts
|
|
824
684
|
dotenv.config();
|
|
825
|
-
var
|
|
685
|
+
var logger6 = Logger.createModuleLogger("main");
|
|
826
686
|
async function embed(config2, input) {
|
|
827
687
|
try {
|
|
828
|
-
|
|
688
|
+
logger6.info(`Starting embedding with provider: ${config2.provider}`);
|
|
829
689
|
const provider = EmbeddingFactory.create(config2);
|
|
830
690
|
const isReady = await provider.isReady();
|
|
831
691
|
if (!isReady) {
|
|
832
692
|
throw new Error(`Provider ${config2.provider} is not ready`);
|
|
833
693
|
}
|
|
834
694
|
if (Array.isArray(input)) {
|
|
835
|
-
|
|
695
|
+
logger6.debug(`Processing batch of ${input.length} items`);
|
|
836
696
|
return await provider.embedBatch(input);
|
|
837
697
|
} else {
|
|
838
|
-
|
|
698
|
+
logger6.debug(`Processing single item`);
|
|
839
699
|
return await provider.embed(input);
|
|
840
700
|
}
|
|
841
701
|
} catch (error) {
|
|
842
702
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
843
|
-
|
|
703
|
+
logger6.error(`Embedding failed: ${errorMessage}`);
|
|
844
704
|
throw error;
|
|
845
705
|
}
|
|
846
706
|
}
|
|
847
707
|
async function autoEmbed(input) {
|
|
848
|
-
|
|
708
|
+
logger6.info("Auto-detecting best provider...");
|
|
849
709
|
const providers = [
|
|
850
710
|
{ provider: "llamacpp", model: "nomic-embed-text-v1.5.Q4_K_M.gguf" },
|
|
851
711
|
// Local & free (llama.cpp)
|
|
852
712
|
{ provider: "openai", model: "text-embedding-3-small", apiKey: process.env.OPENAI_API_KEY || void 0 },
|
|
853
713
|
{ provider: "gemini", model: "gemini-embedding-001", apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY || void 0 },
|
|
854
|
-
{ provider: "mistral", model: "mistral-embed", apiKey: process.env.MISTRAL_API_KEY || void 0 }
|
|
855
|
-
{ provider: "deepseek", model: "deepseek-chat", apiKey: process.env.DEEPSEEK_API_KEY || void 0 }
|
|
714
|
+
{ provider: "mistral", model: "mistral-embed", apiKey: process.env.MISTRAL_API_KEY || void 0 }
|
|
856
715
|
];
|
|
857
716
|
for (const config2 of providers) {
|
|
858
717
|
try {
|
|
859
718
|
if (config2.provider === "llamacpp" || config2.apiKey) {
|
|
860
|
-
|
|
719
|
+
logger6.info(`Trying provider: ${config2.provider}`);
|
|
861
720
|
const cleanConfig = {
|
|
862
721
|
provider: config2.provider,
|
|
863
722
|
model: config2.model
|
|
@@ -869,7 +728,7 @@ async function autoEmbed(input) {
|
|
|
869
728
|
}
|
|
870
729
|
} catch (error) {
|
|
871
730
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
872
|
-
|
|
731
|
+
logger6.warn(`Provider ${config2.provider} failed: ${errorMessage}`);
|
|
873
732
|
continue;
|
|
874
733
|
}
|
|
875
734
|
}
|
|
@@ -896,9 +755,7 @@ var LIB_INFO = {
|
|
|
896
755
|
supportedProviders: [
|
|
897
756
|
"openai",
|
|
898
757
|
"gemini",
|
|
899
|
-
"claude",
|
|
900
758
|
"mistral",
|
|
901
|
-
"deepseek",
|
|
902
759
|
"llamacpp"
|
|
903
760
|
]
|
|
904
761
|
};
|