embrix 1.0.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.
@@ -0,0 +1,547 @@
1
+ import { FeatureExtractionPipeline } from '@xenova/transformers';
2
+
3
+ /**
4
+ * @fileoverview Model definitions and metadata for embedding models.
5
+ *
6
+ * This module defines the supported embedding models and their configurations.
7
+ * Each model has a specific HuggingFace path and output dimension.
8
+ *
9
+ * Design Decision: Using string enum for type-safe model selection
10
+ * while allowing easy extension for future models.
11
+ */
12
+ /**
13
+ * Supported embedding models.
14
+ *
15
+ * - MiniLM: Fast, lightweight model optimized for speed
16
+ * - BGE: Beijing Academy of AI model with strong semantic understanding
17
+ */
18
+ declare enum EmbeddingModel {
19
+ /** Xenova/all-MiniLM-L6-v2 - Fast and efficient, 384 dimensions */
20
+ MiniLM = "minilm",
21
+ /** Xenova/bge-small-en-v1.5 - High quality English embeddings, 384 dimensions */
22
+ BGE = "bge"
23
+ }
24
+ /**
25
+ * Configuration for an embedding model.
26
+ */
27
+ interface ModelConfig {
28
+ /** HuggingFace model path for @xenova/transformers */
29
+ readonly hfPath: string;
30
+ /** Output embedding dimension */
31
+ readonly dimension: number;
32
+ /** Human-readable model name */
33
+ readonly name: string;
34
+ /** Model description */
35
+ readonly description: string;
36
+ /** Maximum input sequence length */
37
+ readonly maxLength: number;
38
+ }
39
+ /**
40
+ * Model configurations indexed by EmbeddingModel enum.
41
+ *
42
+ * Design Decision: Using a const object for O(1) lookup
43
+ * and ensuring all models have complete metadata.
44
+ */
45
+ declare const MODEL_CONFIG: Readonly<Record<EmbeddingModel, ModelConfig>>;
46
+ /**
47
+ * Type guard to check if a string is a valid EmbeddingModel.
48
+ */
49
+ declare function isValidModel(model: string): model is EmbeddingModel;
50
+ /**
51
+ * Get model configuration with validation.
52
+ * Throws an error if the model is not found.
53
+ */
54
+ declare function getModelConfig(model: EmbeddingModel): ModelConfig;
55
+ /**
56
+ * Get all supported model names.
57
+ */
58
+ declare function getSupportedModels(): readonly EmbeddingModel[];
59
+
60
+ /**
61
+ * @fileoverview Lazy singleton model loader for embedding pipelines.
62
+ *
63
+ * This module implements a lazy loading pattern with in-memory caching
64
+ * to ensure models are loaded only once during the application lifecycle.
65
+ *
66
+ * Design Decision: Using Map cache instead of class-based singleton
67
+ * for simpler API and better tree-shaking support.
68
+ */
69
+
70
+ /**
71
+ * Load an embedding model pipeline with caching.
72
+ *
73
+ * This function implements lazy loading with singleton pattern:
74
+ * - First call: Downloads and caches the model
75
+ * - Subsequent calls: Returns cached model immediately
76
+ *
77
+ * Thread-safe: Concurrent calls for the same model will share the same
78
+ * loading promise, preventing duplicate downloads.
79
+ *
80
+ * @param model - The embedding model to load
81
+ * @returns Promise resolving to the feature extraction pipeline
82
+ * @throws Error if model fails to load
83
+ *
84
+ * @example
85
+ * ```typescript
86
+ * const pipeline = await loadModel(EmbeddingModel.MiniLM);
87
+ * // Subsequent calls return cached pipeline
88
+ * const samePipeline = await loadModel(EmbeddingModel.MiniLM);
89
+ * ```
90
+ */
91
+ declare function loadModel(model: EmbeddingModel): Promise<FeatureExtractionPipeline>;
92
+ /**
93
+ * Check if a model is already loaded and cached.
94
+ *
95
+ * @param model - The embedding model to check
96
+ * @returns true if model is cached and ready to use
97
+ */
98
+ declare function isModelLoaded(model: EmbeddingModel): boolean;
99
+ /**
100
+ * Clear the model cache.
101
+ *
102
+ * Useful for freeing memory or forcing model reload.
103
+ * Warning: This will require re-downloading models on next use.
104
+ */
105
+ declare function clearModelCache(): void;
106
+ /**
107
+ * Get list of currently loaded models.
108
+ */
109
+ declare function getLoadedModels(): EmbeddingModel[];
110
+ /**
111
+ * Preload a model into cache.
112
+ *
113
+ * Useful for warming up models before first use.
114
+ *
115
+ * @param model - The embedding model to preload
116
+ * @returns Promise that resolves when model is loaded
117
+ *
118
+ * @example
119
+ * ```typescript
120
+ * // Preload model during application startup
121
+ * await preloadModel(EmbeddingModel.MiniLM);
122
+ * ```
123
+ */
124
+ declare function preloadModel(model: EmbeddingModel): Promise<void>;
125
+ /**
126
+ * Preload all supported models.
127
+ *
128
+ * @returns Promise that resolves when all models are loaded
129
+ */
130
+ declare function preloadAllModels(): Promise<void>;
131
+
132
+ /**
133
+ * @fileoverview Core embedding functionality.
134
+ *
135
+ * This module provides the Embedder class for generating text embeddings
136
+ * using the loaded model pipelines.
137
+ *
138
+ * Design Decision: Using a class-based API for better encapsulation
139
+ * and to allow multiple embedder instances with different models.
140
+ */
141
+
142
+ /**
143
+ * Options for embedding generation.
144
+ */
145
+ interface EmbedOptions {
146
+ /** Whether to normalize the output embedding (default: true) */
147
+ normalize?: boolean;
148
+ /** Pooling strategy to use (default: "mean") */
149
+ pooling?: "mean" | "cls";
150
+ }
151
+ /**
152
+ * Result of an embedding operation with metadata.
153
+ */
154
+ interface EmbeddingResult {
155
+ /** The embedding vector */
156
+ embedding: Float32Array;
157
+ /** The model used for embedding */
158
+ model: EmbeddingModel;
159
+ /** Dimension of the embedding */
160
+ dimension: number;
161
+ }
162
+ /**
163
+ * Core class for generating text embeddings.
164
+ *
165
+ * The Embedder class provides a clean API for generating embeddings
166
+ * from text using pre-trained transformer models.
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * const embedder = new Embedder(EmbeddingModel.MiniLM);
171
+ *
172
+ * // Single embedding
173
+ * const vector = await embedder.embed("Hello world");
174
+ *
175
+ * // Batch embedding
176
+ * const vectors = await embedder.embedBatch(["Hello", "World"]);
177
+ * ```
178
+ */
179
+ declare class Embedder {
180
+ private readonly model;
181
+ private readonly config;
182
+ /**
183
+ * Create a new Embedder instance.
184
+ *
185
+ * @param model - The embedding model to use
186
+ * @throws Error if the model is not supported
187
+ */
188
+ constructor(model: EmbeddingModel);
189
+ /**
190
+ * Get the dimension of embeddings produced by this model.
191
+ *
192
+ * @returns The embedding dimension
193
+ */
194
+ get dimension(): number;
195
+ /**
196
+ * Get the model name.
197
+ *
198
+ * @returns The human-readable model name
199
+ */
200
+ get modelName(): string;
201
+ /**
202
+ * Get the model enum value.
203
+ *
204
+ * @returns The EmbeddingModel enum value
205
+ */
206
+ get modelType(): EmbeddingModel;
207
+ /**
208
+ * Generate an embedding for a single text.
209
+ *
210
+ * @param text - The text to embed
211
+ * @param options - Optional embedding configuration
212
+ * @returns Promise resolving to the embedding vector
213
+ * @throws Error if embedding generation fails
214
+ *
215
+ * @example
216
+ * ```typescript
217
+ * const embedder = new Embedder(EmbeddingModel.MiniLM);
218
+ * const vector = await embedder.embed("Hello world");
219
+ * console.log(vector.length); // 384
220
+ * ```
221
+ */
222
+ embed(text: string, options?: EmbedOptions): Promise<Float32Array>;
223
+ /**
224
+ * Generate embeddings for multiple texts.
225
+ *
226
+ * This method is more efficient than calling embed() multiple times
227
+ * as it processes all texts in a single batch.
228
+ *
229
+ * @param texts - Array of texts to embed
230
+ * @param options - Optional embedding configuration
231
+ * @returns Promise resolving to array of embedding vectors
232
+ * @throws Error if embedding generation fails
233
+ *
234
+ * @example
235
+ * ```typescript
236
+ * const embedder = new Embedder(EmbeddingModel.MiniLM);
237
+ * const vectors = await embedder.embedBatch(["Hello", "World"]);
238
+ * console.log(vectors.length); // 2
239
+ * console.log(vectors[0].length); // 384
240
+ * ```
241
+ */
242
+ embedBatch(texts: string[], options?: EmbedOptions): Promise<Float32Array[]>;
243
+ /**
244
+ * Generate an embedding with full result metadata.
245
+ *
246
+ * @param text - The text to embed
247
+ * @param options - Optional embedding configuration
248
+ * @returns Promise resolving to embedding result with metadata
249
+ */
250
+ embedWithMetadata(text: string, options?: EmbedOptions): Promise<EmbeddingResult>;
251
+ /**
252
+ * Check if the model for this embedder is loaded.
253
+ *
254
+ * @returns true if the model is loaded and ready
255
+ */
256
+ isReady(): boolean;
257
+ /**
258
+ * Convert a Tensor to Float32Array.
259
+ *
260
+ * Handles different tensor data types and shapes.
261
+ */
262
+ private tensorToFloat32;
263
+ /**
264
+ * Extract vectors from batch output tensor.
265
+ *
266
+ * Handles the tensor shape from batch processing.
267
+ */
268
+ private extractBatchVectors;
269
+ /**
270
+ * Validate that an embedding has the expected dimension.
271
+ *
272
+ * @param vector - The embedding vector to validate
273
+ * @throws Error if dimension doesn't match expected
274
+ */
275
+ private validateDimension;
276
+ }
277
+ /**
278
+ * Factory function to create an Embedder instance.
279
+ *
280
+ * Convenience function for creating embedders without using new.
281
+ *
282
+ * @param model - The embedding model to use
283
+ * @returns A new Embedder instance
284
+ *
285
+ * @example
286
+ * ```typescript
287
+ * const embedder = createEmbedder(EmbeddingModel.MiniLM);
288
+ * const vector = await embedder.embed("Hello world");
289
+ * ```
290
+ */
291
+ declare function createEmbedder(model: EmbeddingModel): Embedder;
292
+
293
+ /**
294
+ * @fileoverview Vector similarity and distance functions.
295
+ *
296
+ * This module provides efficient implementations of common similarity
297
+ * and distance metrics for comparing embedding vectors.
298
+ *
299
+ * Design Decision: All functions work with Float32Array for consistency
300
+ * with the embedding output and optimal memory usage.
301
+ */
302
+ /**
303
+ * Calculate the dot product of two vectors.
304
+ *
305
+ * The dot product is the sum of element-wise products.
306
+ * For normalized vectors, this equals cosine similarity.
307
+ *
308
+ * @param a - First vector
309
+ * @param b - Second vector
310
+ * @returns The dot product
311
+ * @throws Error if vectors have different lengths
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * const a = new Float32Array([1, 2, 3]);
316
+ * const b = new Float32Array([4, 5, 6]);
317
+ * const product = dotProduct(a, b); // 1*4 + 2*5 + 3*6 = 32
318
+ * ```
319
+ */
320
+ declare function dotProduct(a: Float32Array, b: Float32Array): number;
321
+ /**
322
+ * Calculate the cosine similarity between two vectors.
323
+ *
324
+ * Cosine similarity measures the cosine of the angle between two vectors.
325
+ * Range: [-1, 1] where 1 means identical direction, -1 means opposite.
326
+ *
327
+ * Formula: cos(θ) = (A · B) / (||A|| * ||B||)
328
+ *
329
+ * @param a - First vector
330
+ * @param b - Second vector
331
+ * @returns The cosine similarity (-1 to 1)
332
+ * @throws Error if vectors have different lengths or zero magnitude
333
+ *
334
+ * @example
335
+ * ```typescript
336
+ * const a = new Float32Array([1, 0, 0]);
337
+ * const b = new Float32Array([0, 1, 0]);
338
+ * const similarity = cosineSimilarity(a, b); // 0 (orthogonal)
339
+ * ```
340
+ */
341
+ declare function cosineSimilarity(a: Float32Array, b: Float32Array): number;
342
+ /**
343
+ * Calculate the Euclidean distance between two vectors.
344
+ *
345
+ * Euclidean distance is the straight-line distance between two points
346
+ * in Euclidean space. Lower values indicate more similar vectors.
347
+ *
348
+ * Formula: d(A, B) = sqrt(Σ(Ai - Bi)²)
349
+ *
350
+ * @param a - First vector
351
+ * @param b - Second vector
352
+ * @returns The Euclidean distance (0 to infinity)
353
+ * @throws Error if vectors have different lengths
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * const a = new Float32Array([0, 0, 0]);
358
+ * const b = new Float32Array([1, 1, 1]);
359
+ * const distance = euclideanDistance(a, b); // sqrt(3) ≈ 1.732
360
+ * ```
361
+ */
362
+ declare function euclideanDistance(a: Float32Array, b: Float32Array): number;
363
+ /**
364
+ * Calculate the squared Euclidean distance between two vectors.
365
+ *
366
+ * More efficient than euclideanDistance when only comparing distances
367
+ * (avoids the sqrt operation).
368
+ *
369
+ * @param a - First vector
370
+ * @param b - Second vector
371
+ * @returns The squared Euclidean distance
372
+ * @throws Error if vectors have different lengths
373
+ */
374
+ declare function euclideanDistanceSquared(a: Float32Array, b: Float32Array): number;
375
+ /**
376
+ * Calculate the Manhattan distance between two vectors.
377
+ *
378
+ * Manhattan distance is the sum of absolute differences.
379
+ * Also known as L1 distance or city block distance.
380
+ *
381
+ * Formula: d(A, B) = Σ|Ai - Bi|
382
+ *
383
+ * @param a - First vector
384
+ * @param b - Second vector
385
+ * @returns The Manhattan distance
386
+ * @throws Error if vectors have different lengths
387
+ */
388
+ declare function manhattanDistance(a: Float32Array, b: Float32Array): number;
389
+ /**
390
+ * Calculate the magnitude (L2 norm) of a vector.
391
+ *
392
+ * @param vector - The input vector
393
+ * @returns The magnitude
394
+ */
395
+ declare function magnitude(vector: Float32Array): number;
396
+ /**
397
+ * Normalize a vector to unit length.
398
+ *
399
+ * Returns a new vector with the same direction but magnitude 1.
400
+ *
401
+ * @param vector - The input vector
402
+ * @returns A new normalized vector
403
+ * @throws Error if vector has zero magnitude
404
+ */
405
+ declare function normalize(vector: Float32Array): Float32Array;
406
+ /**
407
+ * Find the most similar vector to a query from a set of candidates.
408
+ *
409
+ * @param query - The query vector
410
+ * @param candidates - Array of candidate vectors
411
+ * @returns Index and similarity score of the most similar candidate
412
+ * @throws Error if candidates array is empty
413
+ *
414
+ * @example
415
+ * ```typescript
416
+ * const query = await embedder.embed("hello");
417
+ * const docs = await embedder.embedBatch(["hi", "goodbye", "greetings"]);
418
+ * const { index, similarity } = findMostSimilar(query, docs);
419
+ * console.log(`Best match at index ${index} with similarity ${similarity}`);
420
+ * ```
421
+ */
422
+ declare function findMostSimilar(query: Float32Array, candidates: Float32Array[]): {
423
+ index: number;
424
+ similarity: number;
425
+ };
426
+ /**
427
+ * Find the k most similar vectors to a query from a set of candidates.
428
+ *
429
+ * @param query - The query vector
430
+ * @param candidates - Array of candidate vectors
431
+ * @param k - Number of results to return
432
+ * @returns Array of indices and similarity scores, sorted by similarity descending
433
+ *
434
+ * @example
435
+ * ```typescript
436
+ * const query = await embedder.embed("hello");
437
+ * const docs = await embedder.embedBatch(["hi", "goodbye", "greetings", "farewell"]);
438
+ * const top2 = findKMostSimilar(query, docs, 2);
439
+ * // Returns top 2 most similar documents
440
+ * ```
441
+ */
442
+ declare function findKMostSimilar(query: Float32Array, candidates: Float32Array[], k: number): Array<{
443
+ index: number;
444
+ similarity: number;
445
+ }>;
446
+
447
+ /**
448
+ * @fileoverview Benchmark utilities for measuring embedding performance.
449
+ *
450
+ * This module provides tools to measure and analyze embedding generation
451
+ * performance, including cold/warm start times and batch throughput.
452
+ *
453
+ * Design Decision: Using process.hrtime.bigint() for nanosecond precision
454
+ * timing without external dependencies.
455
+ */
456
+
457
+ /**
458
+ * Result of a single benchmark measurement.
459
+ */
460
+ interface BenchmarkResult {
461
+ /** Operation name */
462
+ operation: string;
463
+ /** Time taken in milliseconds */
464
+ durationMs: number;
465
+ /** Number of embeddings generated */
466
+ embeddingCount: number;
467
+ /** Average time per embedding in milliseconds */
468
+ avgTimePerEmbeddingMs: number;
469
+ /** Embeddings per second */
470
+ throughput: number;
471
+ }
472
+ /**
473
+ * Complete benchmark suite results.
474
+ */
475
+ interface BenchmarkSuiteResult {
476
+ /** Model used for benchmarking */
477
+ model: EmbeddingModel;
478
+ /** Model name */
479
+ modelName: string;
480
+ /** Embedding dimension */
481
+ dimension: number;
482
+ /** Cold start time (first embed call) */
483
+ coldStart: BenchmarkResult;
484
+ /** Warm start time (second embed call) */
485
+ warmStart: BenchmarkResult;
486
+ /** Batch embedding results */
487
+ batchBenchmark: BenchmarkResult;
488
+ /** Total benchmark duration in milliseconds */
489
+ totalDurationMs: number;
490
+ /** Timestamp of benchmark */
491
+ timestamp: string;
492
+ }
493
+ /**
494
+ * Options for benchmark configuration.
495
+ */
496
+ interface BenchmarkOptions {
497
+ /** Number of texts for batch benchmark (default: 100) */
498
+ batchSize?: number;
499
+ /** Text to use for single embedding benchmarks */
500
+ sampleText?: string;
501
+ /** Whether to log progress to console */
502
+ verbose?: boolean;
503
+ }
504
+ /**
505
+ * Run a complete benchmark suite for an embedding model.
506
+ *
507
+ * Measures:
508
+ * - Cold start time: First embedding call (includes model loading)
509
+ * - Warm start time: Second embedding call (model already loaded)
510
+ * - Batch throughput: Time to embed multiple texts
511
+ *
512
+ * @param model - The embedding model to benchmark
513
+ * @param options - Benchmark configuration options
514
+ * @returns Complete benchmark results
515
+ *
516
+ * @example
517
+ * ```typescript
518
+ * const results = await runBenchmark(EmbeddingModel.MiniLM);
519
+ * console.log(`Cold start: ${results.coldStart.durationMs}ms`);
520
+ * console.log(`Throughput: ${results.batchBenchmark.throughput} embeddings/sec`);
521
+ * ```
522
+ */
523
+ declare function runBenchmark(model: EmbeddingModel, options?: BenchmarkOptions): Promise<BenchmarkSuiteResult>;
524
+ /**
525
+ * Run benchmarks for all supported models.
526
+ *
527
+ * @param options - Benchmark configuration options
528
+ * @returns Array of benchmark results for each model
529
+ */
530
+ declare function runAllBenchmarks(options?: BenchmarkOptions): Promise<BenchmarkSuiteResult[]>;
531
+ /**
532
+ * Format benchmark results as a printable string.
533
+ *
534
+ * @param result - Benchmark suite result
535
+ * @returns Formatted string representation
536
+ */
537
+ declare function formatBenchmarkResult(result: BenchmarkSuiteResult): string;
538
+ /**
539
+ * Compare benchmark results between two models.
540
+ *
541
+ * @param result1 - First model's benchmark results
542
+ * @param result2 - Second model's benchmark results
543
+ * @returns Comparison summary string
544
+ */
545
+ declare function compareBenchmarks(result1: BenchmarkSuiteResult, result2: BenchmarkSuiteResult): string;
546
+
547
+ export { type BenchmarkOptions, type BenchmarkResult, type BenchmarkSuiteResult, type EmbedOptions, Embedder, EmbeddingModel, type EmbeddingResult, MODEL_CONFIG, type ModelConfig, clearModelCache, compareBenchmarks, cosineSimilarity, createEmbedder, dotProduct, euclideanDistance, euclideanDistanceSquared, findKMostSimilar, findMostSimilar, formatBenchmarkResult, getLoadedModels, getModelConfig, getSupportedModels, isModelLoaded, isValidModel, loadModel, magnitude, manhattanDistance, normalize, preloadAllModels, preloadModel, runAllBenchmarks, runBenchmark };