vecbox 0.2.1 → 0.2.3
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 +256 -270
- package/dist/index.cjs +62 -224
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +62 -225
- package/dist/index.js.map +1 -1
- package/dist/{llama_embedding-EC3MWSUZ.node → llama_embedding.node} +0 -0
- package/native/index.js +13 -1
- package/package.json +7 -14
- package/src/providers/llamacpp.ts +63 -199
- package/src/providers/mistral.ts +4 -0
- package/native/README.md +0 -67
- package/native/llama_embedding.cpp +0 -179
package/README.md
CHANGED
|
@@ -1,67 +1,78 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Vecbox
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-
[](https://www.npmjs.
|
|
4
|
+
[](https://www.npmjs.org/package/vecbox)
|
|
5
5
|
[](LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
**One API, multiple providers.** Switch between OpenAI, Gemini, or run locally with Llama.cpp without changing code.
|
|
7
|
+
**One API, multiple providers.** Switch between OpenAI, Gemini, Mistral, or run locally with Llama.cpp using native N-API performance.
|
|
10
8
|
```typescript
|
|
11
|
-
|
|
9
|
+
import { autoEmbed } from 'vecbox';
|
|
10
|
+
|
|
11
|
+
// Works with any provider - auto-detects the best available
|
|
12
12
|
const result = await autoEmbed({ text: 'Hello, world!' });
|
|
13
13
|
console.log(result.embedding); // [0.1, 0.2, ...]
|
|
14
|
+
console.log(result.provider); // 'llamacpp' | 'openai' | 'gemini' | 'mistral'
|
|
14
15
|
```
|
|
15
16
|
|
|
17
|
+
## Why Vecbox?
|
|
18
|
+
|
|
19
|
+
**Universal API** - Write once, run anywhere. Switch providers without changing code.
|
|
20
|
+
|
|
21
|
+
**Local-First** - Runs on your machine with Llama.cpp. No API costs, no data leaving your server, full privacy.
|
|
22
|
+
|
|
23
|
+
**Production Ready** - Cloud APIs (OpenAI, Gemini, Mistral) available when you need scale or specific models.
|
|
24
|
+
|
|
25
|
+
**Native Speed** - C++ bindings via N-API make local embeddings 10x faster than HTTP-based solutions.
|
|
26
|
+
|
|
16
27
|
## Installation
|
|
17
28
|
```bash
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
npm install vecbox
|
|
30
|
+
# or
|
|
31
|
+
pnpm add vecbox
|
|
20
32
|
```
|
|
21
33
|
|
|
22
|
-
|
|
34
|
+
The native module compiles automatically during installation. No manual build steps required.
|
|
23
35
|
|
|
24
36
|
## Quick Start
|
|
25
37
|
|
|
26
|
-
### Auto
|
|
38
|
+
### Auto Mode (Recommended)
|
|
39
|
+
|
|
40
|
+
Let Vecbox choose the best available provider:
|
|
27
41
|
```typescript
|
|
28
42
|
import { autoEmbed } from 'vecbox';
|
|
29
43
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
console.log(result.
|
|
33
|
-
console.log(result.provider); // 'llamacpp' | 'openai' | 'gemini' | 'mistral'
|
|
44
|
+
const result = await autoEmbed({ text: 'Your text here' });
|
|
45
|
+
console.log(result.embedding); // [0.1, 0.2, ...]
|
|
46
|
+
console.log(result.provider); // Shows which provider was used
|
|
34
47
|
```
|
|
35
48
|
|
|
49
|
+
Priority order: Llama.cpp (local) → OpenAI → Gemini → Mistral
|
|
50
|
+
|
|
36
51
|
### Specific Provider
|
|
37
52
|
```typescript
|
|
38
53
|
import { embed } from 'vecbox';
|
|
39
54
|
|
|
55
|
+
// OpenAI
|
|
40
56
|
const result = await embed(
|
|
41
57
|
{ provider: 'openai', apiKey: process.env.OPENAI_API_KEY },
|
|
42
58
|
{ text: 'Your text' }
|
|
43
59
|
);
|
|
44
60
|
```
|
|
45
61
|
|
|
46
|
-
###
|
|
62
|
+
### From Files
|
|
47
63
|
```typescript
|
|
48
|
-
import { embed } from 'vecbox';
|
|
49
|
-
|
|
50
|
-
// Embed text from files
|
|
51
64
|
const result = await embed(
|
|
52
|
-
{ provider: 'gemini', apiKey: process.env.
|
|
65
|
+
{ provider: 'gemini', apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY },
|
|
53
66
|
{ filePath: './document.txt' }
|
|
54
67
|
);
|
|
55
68
|
```
|
|
56
69
|
|
|
57
70
|
### Batch Processing
|
|
58
71
|
```typescript
|
|
59
|
-
import { embed } from 'vecbox';
|
|
60
|
-
|
|
61
72
|
const inputs = [
|
|
62
|
-
{ text: 'First
|
|
63
|
-
{ text: 'Second
|
|
64
|
-
{ text: 'Third
|
|
73
|
+
{ text: 'First document' },
|
|
74
|
+
{ text: 'Second document' },
|
|
75
|
+
{ text: 'Third document' }
|
|
65
76
|
];
|
|
66
77
|
|
|
67
78
|
const result = await embed(
|
|
@@ -74,25 +85,60 @@ console.log(result.embeddings.length); // 3
|
|
|
74
85
|
|
|
75
86
|
## Providers
|
|
76
87
|
|
|
77
|
-
|
|
78
|
-
|
|
88
|
+
### Llama.cpp (Local - Free & Private)
|
|
89
|
+
|
|
90
|
+
**Advantages:**
|
|
91
|
+
- ✅ Zero API costs
|
|
92
|
+
- ✅ Full privacy (data never leaves your machine)
|
|
93
|
+
- ✅ Works offline
|
|
94
|
+
- ✅ Native C++ performance via N-API
|
|
95
|
+
|
|
96
|
+
**Setup:**
|
|
97
|
+
```bash
|
|
98
|
+
# 1. Download a GGUF embedding model
|
|
99
|
+
wget https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/resolve/main/nomic-embed-text-v1.5.Q4_K_M.gguf
|
|
100
|
+
|
|
101
|
+
# 2. Place in your project
|
|
102
|
+
mkdir models
|
|
103
|
+
mv nomic-embed-text-v1.5.Q4_K_M.gguf models/
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**Usage:**
|
|
107
|
+
```typescript
|
|
108
|
+
// Auto-detect (uses local model automatically)
|
|
109
|
+
const result = await autoEmbed({ text: 'Your text' });
|
|
110
|
+
|
|
111
|
+
// Explicit path
|
|
112
|
+
const result = await embed(
|
|
113
|
+
{ provider: 'llamacpp', model: './models/nomic-embed-text-v1.5.Q4_K_M.gguf' },
|
|
114
|
+
{ text: 'Your text' }
|
|
115
|
+
);
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Recommended Models:**
|
|
119
|
+
- `nomic-embed-text-v1.5.Q4_K_M.gguf` (81MB) - Best overall
|
|
120
|
+
- `bge-base-en-v1.5.Q4_K_M.gguf` (133MB) - Higher quality
|
|
121
|
+
- `bge-small-en-v1.5.Q4_0.gguf` (33MB) - Fastest, smaller
|
|
122
|
+
|
|
123
|
+
### OpenAI
|
|
79
124
|
```typescript
|
|
80
125
|
await embed(
|
|
81
126
|
{
|
|
82
127
|
provider: 'openai',
|
|
83
|
-
model: 'text-embedding-3-small', // or text-embedding-3-large
|
|
128
|
+
model: 'text-embedding-3-small', // or 'text-embedding-3-large'
|
|
84
129
|
apiKey: process.env.OPENAI_API_KEY
|
|
85
130
|
},
|
|
86
131
|
{ text: 'Your text' }
|
|
87
132
|
);
|
|
88
133
|
```
|
|
89
134
|
|
|
90
|
-
**Setup:** Get API key at [platform.openai.com](https://platform.openai.com)
|
|
135
|
+
**Setup:** Get API key at [platform.openai.com/api-keys](https://platform.openai.com/api-keys)
|
|
91
136
|
|
|
92
|
-
|
|
137
|
+
**Models:**
|
|
138
|
+
- `text-embedding-3-small` - Fast, cost-effective
|
|
139
|
+
- `text-embedding-3-large` - Highest quality
|
|
93
140
|
|
|
94
|
-
|
|
95
|
-
<summary><b>Google Gemini</b></summary>
|
|
141
|
+
### Google Gemini
|
|
96
142
|
```typescript
|
|
97
143
|
await embed(
|
|
98
144
|
{
|
|
@@ -104,36 +150,9 @@ await embed(
|
|
|
104
150
|
);
|
|
105
151
|
```
|
|
106
152
|
|
|
107
|
-
**Setup:** Get API key at [aistudio.google.com](https://aistudio.google.com)
|
|
108
|
-
|
|
109
|
-
</details>
|
|
110
|
-
|
|
111
|
-
<details>
|
|
112
|
-
<summary><b>Llama.cpp (Local)</b></summary>
|
|
113
|
-
```typescript
|
|
114
|
-
await embed(
|
|
115
|
-
{ provider: 'llamacpp', model: 'nomic-embed-text-v1.5.Q4_K_M.gguf' },
|
|
116
|
-
{ text: 'Your text' }
|
|
117
|
-
);
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
**Setup:**
|
|
121
|
-
```bash
|
|
122
|
-
# 1. Install
|
|
123
|
-
git clone https://github.com/ggerganov/llama.cpp
|
|
124
|
-
cd llama.cpp && make llama-server
|
|
125
|
-
|
|
126
|
-
# 2. Download model
|
|
127
|
-
wget https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/resolve/main/nomic-embed-text-v1.5.Q4_K_M.gguf
|
|
128
|
-
|
|
129
|
-
# 3. Run server
|
|
130
|
-
./llama-server -m nomic-embed-text-v1.5.Q4_K_M.gguf --embedding --port 8080
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
</details>
|
|
153
|
+
**Setup:** Get API key at [aistudio.google.com/apikey](https://aistudio.google.com/apikey)
|
|
134
154
|
|
|
135
|
-
|
|
136
|
-
<summary><b>Mistral</b></summary>
|
|
155
|
+
### Mistral AI
|
|
137
156
|
```typescript
|
|
138
157
|
await embed(
|
|
139
158
|
{
|
|
@@ -145,287 +164,254 @@ await embed(
|
|
|
145
164
|
);
|
|
146
165
|
```
|
|
147
166
|
|
|
148
|
-
**Setup:** Get API key at [mistral.ai](https://mistral.ai)
|
|
167
|
+
**Setup:** Get API key at [console.mistral.ai](https://console.mistral.ai)
|
|
149
168
|
|
|
150
|
-
|
|
169
|
+
## Environment Variables
|
|
151
170
|
|
|
152
|
-
|
|
171
|
+
Create a `.env` file in your project root:
|
|
172
|
+
```bash
|
|
173
|
+
# Optional - only needed for cloud providers
|
|
174
|
+
OPENAI_API_KEY=sk-...
|
|
175
|
+
GOOGLE_GENERATIVE_AI_API_KEY=...
|
|
176
|
+
MISTRAL_API_KEY=...
|
|
177
|
+
```
|
|
153
178
|
|
|
154
|
-
|
|
155
|
-
- **🤖 Auto-Detection** - Automatically picks the best available provider
|
|
156
|
-
- **⚡ Native Performance** - Llama.cpp integration with N-API (10x faster than HTTP)
|
|
157
|
-
- **🔄 Smart Fallbacks** - Never fails, always has a backup provider
|
|
158
|
-
- **📁 File Support** - Embed text from files directly
|
|
159
|
-
- **📦 Batch Processing** - Process multiple texts efficiently
|
|
160
|
-
- **🛡️ Type Safe** - Full TypeScript support
|
|
161
|
-
- **🌍 Zero Dependencies** - No external downloads or setup required
|
|
179
|
+
Vecbox works without any API keys when using Llama.cpp locally.
|
|
162
180
|
|
|
163
|
-
##
|
|
181
|
+
## API Reference
|
|
164
182
|
|
|
165
|
-
|
|
166
|
-
- ✅ **Native Llama.cpp** - Others use HTTP, we use direct C++ integration
|
|
167
|
-
- ✅ **Auto-Detection** - Others require manual provider selection
|
|
168
|
-
- ✅ **Zero Setup** - Others need external downloads and configuration
|
|
169
|
-
- ✅ **Multiple Providers** - Others are limited to one provider
|
|
170
|
-
- ✅ **Smart Fallbacks** - Others fail when a provider is unavailable
|
|
183
|
+
### `autoEmbed(input: Input): Promise<Result>`
|
|
171
184
|
|
|
172
|
-
|
|
173
|
-
- **Llama.cpp Native**: ~50ms per embedding
|
|
174
|
-
- **Cloud Providers**: ~100-300ms per embedding
|
|
175
|
-
- **HTTP Llama.cpp**: ~500ms+ per embedding
|
|
185
|
+
Automatically selects the best available provider.
|
|
176
186
|
|
|
177
|
-
|
|
187
|
+
**Input:**
|
|
188
|
+
```typescript
|
|
189
|
+
{ text: string } | { filePath: string }
|
|
190
|
+
```
|
|
178
191
|
|
|
179
|
-
|
|
192
|
+
**Returns:**
|
|
180
193
|
```typescript
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
194
|
+
{
|
|
195
|
+
embedding: number[]; // The embedding vector
|
|
196
|
+
dimensions: number; // Vector dimensions
|
|
197
|
+
provider: string; // Which provider was used
|
|
198
|
+
model: string; // Model name
|
|
199
|
+
usage?: {
|
|
200
|
+
promptTokens?: number;
|
|
201
|
+
totalTokens?: number;
|
|
202
|
+
}
|
|
187
203
|
}
|
|
204
|
+
```
|
|
188
205
|
|
|
189
|
-
|
|
190
|
-
const docs = await Promise.all(
|
|
191
|
-
documents.map(doc => autoEmbed({ text: doc }))
|
|
192
|
-
);
|
|
206
|
+
### `embed(config: Config, input: Input | Input[]): Promise<Result>`
|
|
193
207
|
|
|
194
|
-
|
|
195
|
-
const scores = docs.map(doc =>
|
|
196
|
-
cosineSimilarity(query.embedding, doc.embedding)
|
|
197
|
-
);
|
|
198
|
-
const mostSimilar = scores.indexOf(Math.max(...scores));
|
|
199
|
-
console.log(`Best match: ${documents[mostSimilar]}`);
|
|
200
|
-
```
|
|
208
|
+
Use a specific provider.
|
|
201
209
|
|
|
202
|
-
|
|
210
|
+
**Config:**
|
|
203
211
|
```typescript
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
{
|
|
213
|
+
provider: 'llamacpp' | 'openai' | 'gemini' | 'mistral';
|
|
214
|
+
model?: string; // Provider-specific model
|
|
215
|
+
apiKey?: string; // Required for cloud providers
|
|
216
|
+
baseUrl?: string; // Custom API endpoint
|
|
217
|
+
timeout?: number; // Request timeout in ms
|
|
218
|
+
maxRetries?: number; // Retry attempts
|
|
209
219
|
}
|
|
220
|
+
```
|
|
210
221
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
]);
|
|
215
|
-
|
|
216
|
-
const similarity = cosineSimilarity(emb1.embedding, emb2.embedding);
|
|
217
|
-
console.log(`Similarity: ${similarity.toFixed(3)}`); // → 0.95 (very similar)
|
|
222
|
+
**Input:**
|
|
223
|
+
```typescript
|
|
224
|
+
{ text: string } | { filePath: string } | Array<{text: string} | {filePath: string}>
|
|
218
225
|
```
|
|
219
226
|
|
|
220
|
-
|
|
227
|
+
**Returns:** Same as `autoEmbed`, but `embeddings: number[][]` for batch inputs.
|
|
228
|
+
|
|
229
|
+
## Examples
|
|
230
|
+
|
|
231
|
+
### Semantic Search
|
|
221
232
|
```typescript
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
233
|
+
import { autoEmbed } from 'vecbox';
|
|
234
|
+
|
|
235
|
+
function cosineSimilarity(a: number[], b: number[]): number {
|
|
236
|
+
const dotProduct = a.reduce((sum, val, i) => sum + val * b[i], 0);
|
|
237
|
+
const magA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0));
|
|
238
|
+
const magB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0));
|
|
239
|
+
return dotProduct / (magA * magB);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Embed query and documents
|
|
243
|
+
const query = await autoEmbed({ text: 'machine learning tutorials' });
|
|
244
|
+
const docs = await Promise.all([
|
|
245
|
+
autoEmbed({ text: 'Introduction to neural networks' }),
|
|
246
|
+
autoEmbed({ text: 'Python web scraping guide' }),
|
|
247
|
+
autoEmbed({ text: 'Deep learning fundamentals' })
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
// Calculate similarity scores
|
|
251
|
+
const similarities = docs.map(doc =>
|
|
252
|
+
cosineSimilarity(query.embedding, doc.embedding)
|
|
229
253
|
);
|
|
230
|
-
// → { embeddings: [[...], [...], [...]], dimensions: 1536 }
|
|
231
254
|
|
|
232
|
-
|
|
233
|
-
|
|
255
|
+
// Find best match
|
|
256
|
+
const bestIdx = similarities.indexOf(Math.max(...similarities));
|
|
257
|
+
console.log(`Best match: Document ${bestIdx + 1} (score: ${similarities[bestIdx].toFixed(3)})`);
|
|
234
258
|
```
|
|
235
259
|
|
|
236
|
-
### File Processing
|
|
260
|
+
### Batch File Processing
|
|
237
261
|
```typescript
|
|
262
|
+
import { embed } from 'vecbox';
|
|
238
263
|
import { readdir } from 'fs/promises';
|
|
239
264
|
import { join } from 'path';
|
|
240
265
|
|
|
241
|
-
async function
|
|
266
|
+
async function embedDirectory(dirPath: string) {
|
|
242
267
|
const files = await readdir(dirPath);
|
|
243
|
-
const textFiles = files.filter(
|
|
244
|
-
|
|
245
|
-
const inputs = textFiles.map(file => ({
|
|
246
|
-
filePath: join(dirPath, file)
|
|
247
|
-
}));
|
|
268
|
+
const textFiles = files.filter(f => f.endsWith('.txt'));
|
|
248
269
|
|
|
249
|
-
|
|
270
|
+
// Process all files in one batch
|
|
271
|
+
const result = await embed(
|
|
250
272
|
{ provider: 'llamacpp' },
|
|
251
|
-
|
|
273
|
+
textFiles.map(file => ({ filePath: join(dirPath, file) }))
|
|
252
274
|
);
|
|
253
275
|
|
|
254
|
-
return textFiles.map((file,
|
|
255
|
-
file,
|
|
256
|
-
embedding:
|
|
276
|
+
return textFiles.map((file, i) => ({
|
|
277
|
+
filename: file,
|
|
278
|
+
embedding: result.embeddings[i]
|
|
257
279
|
}));
|
|
258
280
|
}
|
|
259
281
|
|
|
260
|
-
const
|
|
261
|
-
console.log(`
|
|
282
|
+
const results = await embedDirectory('./documents');
|
|
283
|
+
console.log(`Embedded ${results.length} files`);
|
|
262
284
|
```
|
|
263
285
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
### `autoEmbed(input)`
|
|
267
|
-
|
|
268
|
-
Auto-detects best provider in priority order:
|
|
269
|
-
1. **Llama.cpp** (Local & Free)
|
|
270
|
-
2. **OpenAI** (if API key available)
|
|
271
|
-
3. **Gemini** (if API key available)
|
|
272
|
-
4. **Mistral** (if API key available)
|
|
273
|
-
|
|
286
|
+
### Document Clustering
|
|
274
287
|
```typescript
|
|
275
|
-
|
|
276
|
-
```
|
|
288
|
+
import { autoEmbed } from 'vecbox';
|
|
277
289
|
|
|
278
|
-
|
|
290
|
+
const documents = [
|
|
291
|
+
'The cat sat on the mat',
|
|
292
|
+
'Dogs are loyal pets',
|
|
293
|
+
'Python is a programming language',
|
|
294
|
+
'JavaScript runs in browsers',
|
|
295
|
+
'Birds can fly high'
|
|
296
|
+
];
|
|
279
297
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
{ text: string } | { filePath: string } | Array
|
|
285
|
-
)
|
|
286
|
-
```
|
|
298
|
+
// Get embeddings
|
|
299
|
+
const embeddings = await Promise.all(
|
|
300
|
+
documents.map(doc => autoEmbed({ text: doc }))
|
|
301
|
+
);
|
|
287
302
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
303
|
+
// Simple clustering by similarity threshold
|
|
304
|
+
function findClusters(embeddings: number[][], threshold = 0.7) {
|
|
305
|
+
const clusters: number[][] = [];
|
|
306
|
+
const assigned = new Set<number>();
|
|
307
|
+
|
|
308
|
+
embeddings.forEach((emb, i) => {
|
|
309
|
+
if (assigned.has(i)) return;
|
|
310
|
+
|
|
311
|
+
const cluster = [i];
|
|
312
|
+
assigned.add(i);
|
|
313
|
+
|
|
314
|
+
embeddings.forEach((other, j) => {
|
|
315
|
+
if (i !== j && !assigned.has(j)) {
|
|
316
|
+
const sim = cosineSimilarity(emb, other);
|
|
317
|
+
if (sim > threshold) {
|
|
318
|
+
cluster.push(j);
|
|
319
|
+
assigned.add(j);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
clusters.push(cluster);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
return clusters;
|
|
299
328
|
}
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### `getSupportedProviders()`
|
|
303
|
-
|
|
304
|
-
Returns available providers.
|
|
305
|
-
```typescript
|
|
306
|
-
import { getSupportedProviders } from 'embedbox';
|
|
307
329
|
|
|
308
|
-
const
|
|
309
|
-
|
|
330
|
+
const clusters = findClusters(embeddings.map(e => e.embedding));
|
|
331
|
+
console.log('Clusters:', clusters);
|
|
332
|
+
// Output: [[0, 1, 4], [2, 3]] - animals vs programming
|
|
310
333
|
```
|
|
311
334
|
|
|
312
|
-
|
|
335
|
+
## Troubleshooting
|
|
313
336
|
|
|
314
|
-
|
|
315
|
-
```typescript
|
|
316
|
-
import { createProvider } from 'embedbox';
|
|
337
|
+
### Native Module Issues
|
|
317
338
|
|
|
318
|
-
|
|
319
|
-
provider: 'openai',
|
|
320
|
-
model: 'text-embedding-3-small',
|
|
321
|
-
apiKey: 'your-key'
|
|
322
|
-
});
|
|
339
|
+
**Error: `Cannot find module './build/Release/vecbox.node'`**
|
|
323
340
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
341
|
+
The native module failed to compile. Rebuild it:
|
|
342
|
+
```bash
|
|
343
|
+
npm run build:native
|
|
344
|
+
# or
|
|
345
|
+
node-gyp rebuild
|
|
328
346
|
```
|
|
329
347
|
|
|
330
|
-
|
|
348
|
+
**Error: `binding.createModel is not a function`**
|
|
349
|
+
|
|
350
|
+
Your native module is outdated. Clean and rebuild:
|
|
331
351
|
```bash
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
GOOGLE_GENERATIVE_AI_API_KEY=...
|
|
335
|
-
ANTHROPIC_API_KEY=sk-ant-...
|
|
336
|
-
MISTRAL_API_KEY=...
|
|
352
|
+
rm -rf build/
|
|
353
|
+
npm install
|
|
337
354
|
```
|
|
338
355
|
|
|
339
|
-
|
|
356
|
+
### Model Loading Issues
|
|
340
357
|
|
|
341
|
-
|
|
342
|
-
import { autoEmbed } from 'embedbox';
|
|
343
|
-
|
|
344
|
-
try {
|
|
345
|
-
const result = await autoEmbed({ text: 'Hello' });
|
|
346
|
-
console.log(result.embedding);
|
|
347
|
-
} catch (error) {
|
|
348
|
-
if (error.message.includes('API key')) {
|
|
349
|
-
console.error('Please set up your API keys in .env');
|
|
350
|
-
} else if (error.message.includes('not ready')) {
|
|
351
|
-
console.error('Provider is not available');
|
|
352
|
-
} else if (error.message.includes('network')) {
|
|
353
|
-
console.error('Network connection failed');
|
|
354
|
-
} else {
|
|
355
|
-
console.error('Embedding failed:', error.message);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
```
|
|
358
|
+
**Error: `Model file not found`**
|
|
359
359
|
|
|
360
|
-
|
|
360
|
+
Check that the model path is correct:
|
|
361
|
+
```bash
|
|
362
|
+
ls -la models/ # Verify model exists
|
|
363
|
+
pwd # Check current directory
|
|
364
|
+
```
|
|
361
365
|
|
|
362
|
-
|
|
366
|
+
Use absolute paths if relative paths fail:
|
|
363
367
|
```typescript
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
embed,
|
|
367
|
-
getSupportedProviders,
|
|
368
|
-
createProvider,
|
|
369
|
-
type EmbedConfig,
|
|
370
|
-
type EmbedInput,
|
|
371
|
-
type EmbedResult
|
|
372
|
-
} from 'embedbox';
|
|
373
|
-
|
|
374
|
-
// Full type safety
|
|
375
|
-
const config: EmbedConfig = {
|
|
376
|
-
provider: 'openai',
|
|
377
|
-
model: 'text-embedding-3-small'
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const input: EmbedInput = {
|
|
381
|
-
text: 'Your text here'
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
const result: EmbedResult = await embed(config, input);
|
|
368
|
+
const path = require('path');
|
|
369
|
+
const modelPath = path.join(__dirname, 'models', 'model.gguf');
|
|
385
370
|
```
|
|
386
371
|
|
|
387
|
-
|
|
372
|
+
### Performance
|
|
388
373
|
|
|
389
|
-
|
|
390
|
-
-
|
|
391
|
-
-
|
|
392
|
-
-
|
|
374
|
+
**Embeddings are slow:**
|
|
375
|
+
- Use smaller quantized models (Q4_K_M is recommended)
|
|
376
|
+
- Process texts in batches instead of one-by-one
|
|
377
|
+
- Verify native module is loaded (check `result.provider === 'llamacpp'`)
|
|
393
378
|
|
|
394
|
-
|
|
379
|
+
**High memory usage:**
|
|
380
|
+
- Models stay loaded in memory for performance
|
|
381
|
+
- Use smaller models (bge-small instead of bge-large)
|
|
382
|
+
- Process files in chunks for very large datasets
|
|
395
383
|
|
|
396
|
-
|
|
397
|
-
- Adding new providers
|
|
398
|
-
- Improving performance
|
|
399
|
-
- Bug fixes and features
|
|
400
|
-
- Documentation improvements
|
|
384
|
+
## Features
|
|
401
385
|
|
|
402
|
-
|
|
386
|
+
- **🎯 Provider Agnostic** - One API for all embedding providers
|
|
387
|
+
- **🤖 Smart Auto-Detection** - Automatically uses the best available option
|
|
388
|
+
- **⚡ Native Performance** - C++ via N-API for maximum speed
|
|
389
|
+
- **🔄 Automatic Fallbacks** - Seamlessly switches providers if one fails
|
|
390
|
+
- **📁 File Support** - Read and embed text files directly
|
|
391
|
+
- **📦 Batch Processing** - Efficient multi-document embedding
|
|
392
|
+
- **🛡️ TypeScript First** - Full type safety and IDE autocomplete
|
|
393
|
+
- **🌍 Zero Setup** - Native module compiles automatically on install
|
|
394
|
+
- **🔒 Privacy-First** - Local processing keeps your data private
|
|
403
395
|
|
|
404
|
-
|
|
405
|
-
- Installation problems
|
|
406
|
-
- Runtime errors
|
|
407
|
-
- Performance issues
|
|
408
|
-
- Common solutions
|
|
409
|
-
|
|
410
|
-
## 📄 License
|
|
396
|
+
## License
|
|
411
397
|
|
|
412
398
|
MIT License - see [LICENSE](LICENSE) file for details.
|
|
413
399
|
|
|
414
|
-
##
|
|
400
|
+
## Credits
|
|
401
|
+
|
|
402
|
+
Built on top of excellent open-source projects:
|
|
415
403
|
|
|
416
|
-
- [
|
|
417
|
-
- [OpenAI](https://openai.com/) -
|
|
418
|
-
- [Google Gemini](https://ai.google.dev/) -
|
|
419
|
-
- [Mistral AI](https://mistral.ai/) -
|
|
404
|
+
- [llama.cpp](https://github.com/ggml-org/llama.cpp) - High-performance LLM inference
|
|
405
|
+
- [OpenAI](https://openai.com/) - text-embedding-3 models
|
|
406
|
+
- [Google Gemini](https://ai.google.dev/) - gemini-embedding models
|
|
407
|
+
- [Mistral AI](https://mistral.ai/) - mistral-embed model
|
|
420
408
|
|
|
421
|
-
##
|
|
409
|
+
## Contributing
|
|
422
410
|
|
|
423
|
-
|
|
424
|
-
- **GitHub Discussions**: [Ask questions](https://github.com/box-safe/vecbox/discussions)
|
|
425
|
-
- **Documentation**: [API Reference](./API.md)
|
|
411
|
+
Issues and pull requests welcome at [github.com/box-safe/vecbox](https://github.com/box-safe/vecbox)
|
|
426
412
|
|
|
427
413
|
---
|
|
428
414
|
|
|
429
|
-
**⭐
|
|
415
|
+
**⭐ If Vecbox saves you time, star us on GitHub!**
|
|
430
416
|
|
|
431
|
-
**Made with ❤️
|
|
417
|
+
**Made with ❤️ for developers who value simplicity and performance**
|