@soulcraft/brainy 6.5.0 → 6.6.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/assets/models/all-MiniLM-L6-v2-q8/config.json +25 -0
- package/assets/models/all-MiniLM-L6-v2-q8/model.onnx +0 -0
- package/assets/models/all-MiniLM-L6-v2-q8/tokenizer.json +30686 -0
- package/assets/models/all-MiniLM-L6-v2-q8/vocab.json +1 -0
- package/dist/critical/model-guardian.d.ts +5 -22
- package/dist/critical/model-guardian.js +38 -210
- package/dist/embeddings/EmbeddingManager.d.ts +7 -17
- package/dist/embeddings/EmbeddingManager.js +28 -136
- package/dist/embeddings/wasm/AssetLoader.d.ts +67 -0
- package/dist/embeddings/wasm/AssetLoader.js +238 -0
- package/dist/embeddings/wasm/EmbeddingPostProcessor.d.ts +60 -0
- package/dist/embeddings/wasm/EmbeddingPostProcessor.js +123 -0
- package/dist/embeddings/wasm/ONNXInferenceEngine.d.ts +55 -0
- package/dist/embeddings/wasm/ONNXInferenceEngine.js +154 -0
- package/dist/embeddings/wasm/WASMEmbeddingEngine.d.ts +82 -0
- package/dist/embeddings/wasm/WASMEmbeddingEngine.js +231 -0
- package/dist/embeddings/wasm/WordPieceTokenizer.d.ts +71 -0
- package/dist/embeddings/wasm/WordPieceTokenizer.js +264 -0
- package/dist/embeddings/wasm/index.d.ts +13 -0
- package/dist/embeddings/wasm/index.js +15 -0
- package/dist/embeddings/wasm/types.d.ts +114 -0
- package/dist/embeddings/wasm/types.js +25 -0
- package/dist/setup.d.ts +11 -11
- package/dist/setup.js +17 -31
- package/dist/utils/embedding.d.ts +45 -62
- package/dist/utils/embedding.js +61 -440
- package/package.json +10 -3
- package/scripts/download-model.cjs +175 -0
|
@@ -5,15 +5,14 @@
|
|
|
5
5
|
* Without the exact model, users CANNOT access their data
|
|
6
6
|
*
|
|
7
7
|
* Requirements:
|
|
8
|
-
* 1. Model MUST be
|
|
9
|
-
* 2. Model MUST be available at runtime
|
|
8
|
+
* 1. Model MUST be all-MiniLM-L6-v2-q8 (bundled in package)
|
|
9
|
+
* 2. Model MUST be available at runtime (embedded in npm package)
|
|
10
10
|
* 3. Model MUST produce consistent 384-dim embeddings
|
|
11
11
|
* 4. System MUST fail fast if model unavailable in production
|
|
12
12
|
*/
|
|
13
13
|
export declare class ModelGuardian {
|
|
14
14
|
private static instance;
|
|
15
15
|
private isVerified;
|
|
16
|
-
private modelPath;
|
|
17
16
|
private lastVerification;
|
|
18
17
|
private constructor();
|
|
19
18
|
static getInstance(): ModelGuardian;
|
|
@@ -23,34 +22,18 @@ export declare class ModelGuardian {
|
|
|
23
22
|
*/
|
|
24
23
|
ensureCriticalModel(): Promise<void>;
|
|
25
24
|
/**
|
|
26
|
-
* Verify the
|
|
25
|
+
* Verify the bundled WASM model works correctly
|
|
27
26
|
*/
|
|
28
|
-
private
|
|
29
|
-
/**
|
|
30
|
-
* Compute SHA256 hash of a file
|
|
31
|
-
*/
|
|
32
|
-
private computeFileHash;
|
|
33
|
-
/**
|
|
34
|
-
* Download model from a fallback source
|
|
35
|
-
*/
|
|
36
|
-
private downloadFromSource;
|
|
37
|
-
/**
|
|
38
|
-
* Configure transformers.js to use verified local model
|
|
39
|
-
*/
|
|
40
|
-
private configureTransformers;
|
|
41
|
-
/**
|
|
42
|
-
* Detect where models should be stored
|
|
43
|
-
*/
|
|
44
|
-
private detectModelPath;
|
|
27
|
+
private verifyBundledModel;
|
|
45
28
|
/**
|
|
46
29
|
* Get model status for diagnostics
|
|
47
30
|
*/
|
|
48
31
|
getStatus(): Promise<{
|
|
49
32
|
verified: boolean;
|
|
50
|
-
path: string;
|
|
51
33
|
lastVerification: Date | null;
|
|
52
34
|
modelName: string;
|
|
53
35
|
dimensions: number;
|
|
36
|
+
bundled: boolean;
|
|
54
37
|
}>;
|
|
55
38
|
/**
|
|
56
39
|
* Force re-verification (for testing)
|
|
@@ -5,51 +5,24 @@
|
|
|
5
5
|
* Without the exact model, users CANNOT access their data
|
|
6
6
|
*
|
|
7
7
|
* Requirements:
|
|
8
|
-
* 1. Model MUST be
|
|
9
|
-
* 2. Model MUST be available at runtime
|
|
8
|
+
* 1. Model MUST be all-MiniLM-L6-v2-q8 (bundled in package)
|
|
9
|
+
* 2. Model MUST be available at runtime (embedded in npm package)
|
|
10
10
|
* 3. Model MUST produce consistent 384-dim embeddings
|
|
11
11
|
* 4. System MUST fail fast if model unavailable in production
|
|
12
12
|
*/
|
|
13
|
-
import {
|
|
13
|
+
import { WASMEmbeddingEngine } from '../embeddings/wasm/index.js';
|
|
14
14
|
// CRITICAL: These values MUST NEVER CHANGE
|
|
15
15
|
const CRITICAL_MODEL_CONFIG = {
|
|
16
|
-
modelName: '
|
|
17
|
-
modelHash: {
|
|
18
|
-
// SHA256 of model.onnx - computed from actual model
|
|
19
|
-
'onnx/model.onnx': 'add_actual_hash_here',
|
|
20
|
-
'tokenizer.json': 'add_actual_hash_here'
|
|
21
|
-
},
|
|
22
|
-
modelSize: {
|
|
23
|
-
'onnx/model.onnx': 90387606, // Exact size in bytes (updated to match actual file)
|
|
24
|
-
'tokenizer.json': 711661
|
|
25
|
-
},
|
|
16
|
+
modelName: 'all-MiniLM-L6-v2-q8',
|
|
26
17
|
embeddingDimensions: 384,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
{
|
|
30
|
-
name: 'Soulcraft CDN (Primary)',
|
|
31
|
-
url: 'https://models.soulcraft.com/models/all-MiniLM-L6-v2.tar.gz',
|
|
32
|
-
type: 'tarball'
|
|
33
|
-
},
|
|
34
|
-
// Secondary: GitHub releases backup
|
|
35
|
-
{
|
|
36
|
-
name: 'GitHub Backup',
|
|
37
|
-
url: 'https://github.com/soulcraftlabs/brainy-models/releases/download/v1.0.0/all-MiniLM-L6-v2.tar.gz',
|
|
38
|
-
type: 'tarball'
|
|
39
|
-
},
|
|
40
|
-
// Tertiary: Hugging Face (original source)
|
|
41
|
-
{
|
|
42
|
-
name: 'Hugging Face',
|
|
43
|
-
url: 'huggingface',
|
|
44
|
-
type: 'transformers'
|
|
45
|
-
}
|
|
46
|
-
]
|
|
18
|
+
// Model is bundled in package - no external downloads needed
|
|
19
|
+
bundled: true
|
|
47
20
|
};
|
|
48
21
|
export class ModelGuardian {
|
|
49
22
|
constructor() {
|
|
50
23
|
this.isVerified = false;
|
|
51
24
|
this.lastVerification = null;
|
|
52
|
-
|
|
25
|
+
// Model is bundled - no path detection needed
|
|
53
26
|
}
|
|
54
27
|
static getInstance() {
|
|
55
28
|
if (!ModelGuardian.instance) {
|
|
@@ -62,200 +35,55 @@ export class ModelGuardian {
|
|
|
62
35
|
* This MUST be called before any embedding operations
|
|
63
36
|
*/
|
|
64
37
|
async ensureCriticalModel() {
|
|
65
|
-
console.log('DEBUG: ensureCriticalModel called');
|
|
66
|
-
console.log('🛡️ MODEL GUARDIAN: Verifying critical model availability...');
|
|
67
|
-
console.log(`🚀 Debug: Model path: ${this.modelPath}`);
|
|
68
|
-
console.log(`🚀 Debug: Already verified: ${this.isVerified}`);
|
|
69
38
|
// Check if already verified in this session
|
|
70
39
|
if (this.isVerified && this.lastVerification) {
|
|
71
40
|
const hoursSinceVerification = (Date.now() - this.lastVerification.getTime()) / (1000 * 60 * 60);
|
|
72
41
|
if (hoursSinceVerification < 24) {
|
|
73
|
-
console.log('✅ Model previously verified in this session');
|
|
74
42
|
return;
|
|
75
43
|
}
|
|
76
44
|
}
|
|
77
|
-
//
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (modelExists) {
|
|
81
|
-
console.log('✅ Critical model verified locally');
|
|
45
|
+
// Verify the bundled WASM model works
|
|
46
|
+
const modelWorks = await this.verifyBundledModel();
|
|
47
|
+
if (modelWorks) {
|
|
82
48
|
this.isVerified = true;
|
|
83
49
|
this.lastVerification = new Date();
|
|
84
|
-
this.configureTransformers();
|
|
85
50
|
return;
|
|
86
51
|
}
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
'Solution: Run "npm run download-models" during build stage.');
|
|
93
|
-
}
|
|
94
|
-
// Step 3: Attempt to download from fallback sources
|
|
95
|
-
console.warn('⚠️ Model not found locally, attempting download...');
|
|
96
|
-
for (const source of CRITICAL_MODEL_CONFIG.fallbackSources) {
|
|
97
|
-
try {
|
|
98
|
-
console.log(`📥 Trying ${source.name}...`);
|
|
99
|
-
await this.downloadFromSource(source);
|
|
100
|
-
// Verify the download
|
|
101
|
-
if (await this.verifyLocalModel()) {
|
|
102
|
-
console.log(`✅ Successfully downloaded from ${source.name}`);
|
|
103
|
-
this.isVerified = true;
|
|
104
|
-
this.lastVerification = new Date();
|
|
105
|
-
this.configureTransformers();
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
console.warn(`❌ ${source.name} failed:`, error.message);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
// Step 4: CRITICAL FAILURE
|
|
114
|
-
throw new Error('🚨 CRITICAL FAILURE: Cannot obtain transformer model!\n' +
|
|
115
|
-
'Tried all fallback sources.\n' +
|
|
116
|
-
'Brainy CANNOT function without the model.\n' +
|
|
117
|
-
'Users CANNOT access their data.\n' +
|
|
118
|
-
'Please check network connectivity or pre-download models.');
|
|
52
|
+
// CRITICAL FAILURE
|
|
53
|
+
throw new Error('🚨 CRITICAL FAILURE: Bundled transformer model not working!\n' +
|
|
54
|
+
'The model is REQUIRED for Brainy to function.\n' +
|
|
55
|
+
'Users CANNOT access their data without it.\n' +
|
|
56
|
+
'This indicates a package installation issue.');
|
|
119
57
|
}
|
|
120
58
|
/**
|
|
121
|
-
* Verify the
|
|
59
|
+
* Verify the bundled WASM model works correctly
|
|
122
60
|
*/
|
|
123
|
-
async
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
console.log(`🔍 Debug: Model path components: ${this.modelPath} + ${CRITICAL_MODEL_CONFIG.modelName.split('/')}`);
|
|
136
|
-
// Check critical files
|
|
137
|
-
const criticalFiles = [
|
|
138
|
-
'onnx/model.onnx',
|
|
139
|
-
'tokenizer.json',
|
|
140
|
-
'config.json'
|
|
141
|
-
];
|
|
142
|
-
for (const file of criticalFiles) {
|
|
143
|
-
const filePath = path.join(modelBasePath, file);
|
|
144
|
-
console.log(`🔍 Debug: Checking file: ${filePath}`);
|
|
145
|
-
if (!fs.existsSync(filePath)) {
|
|
146
|
-
console.log(`❌ Missing critical file: ${file} at ${filePath}`);
|
|
61
|
+
async verifyBundledModel() {
|
|
62
|
+
try {
|
|
63
|
+
const engine = WASMEmbeddingEngine.getInstance();
|
|
64
|
+
// Initialize the engine (loads bundled model)
|
|
65
|
+
await engine.initialize();
|
|
66
|
+
// Test embedding generation
|
|
67
|
+
const testEmbedding = await engine.embed('test verification');
|
|
68
|
+
// Verify dimensions
|
|
69
|
+
if (testEmbedding.length !== CRITICAL_MODEL_CONFIG.embeddingDimensions) {
|
|
70
|
+
console.error(`❌ CRITICAL: Model dimension mismatch!\n` +
|
|
71
|
+
`Expected: ${CRITICAL_MODEL_CONFIG.embeddingDimensions}\n` +
|
|
72
|
+
`Got: ${testEmbedding.length}`);
|
|
147
73
|
return false;
|
|
148
74
|
}
|
|
149
|
-
// Verify
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
console.error(`❌ CRITICAL: Model file size mismatch!\n` +
|
|
155
|
-
`File: ${file}\n` +
|
|
156
|
-
`Expected: ${expectedSize} bytes\n` +
|
|
157
|
-
`Actual: ${stats.size} bytes\n` +
|
|
158
|
-
`This indicates model corruption or version mismatch!`);
|
|
159
|
-
return false;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
// SHA256 verification for ultimate security
|
|
163
|
-
if (CRITICAL_MODEL_CONFIG.modelHash && CRITICAL_MODEL_CONFIG.modelHash[file]) {
|
|
164
|
-
const hash = await this.computeFileHash(filePath);
|
|
165
|
-
if (hash !== CRITICAL_MODEL_CONFIG.modelHash[file]) {
|
|
166
|
-
console.error(`❌ CRITICAL: Model hash mismatch for ${file}!\n` +
|
|
167
|
-
`Expected: ${CRITICAL_MODEL_CONFIG.modelHash[file]}\n` +
|
|
168
|
-
`Got: ${hash}\n` +
|
|
169
|
-
`This indicates model tampering or corruption!`);
|
|
170
|
-
return false;
|
|
171
|
-
}
|
|
75
|
+
// Verify normalization (should be unit length)
|
|
76
|
+
const norm = Math.sqrt(testEmbedding.reduce((sum, v) => sum + v * v, 0));
|
|
77
|
+
if (Math.abs(norm - 1.0) > 0.01) {
|
|
78
|
+
console.error(`❌ CRITICAL: Embeddings not normalized! Norm: ${norm}`);
|
|
79
|
+
return false;
|
|
172
80
|
}
|
|
173
|
-
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Compute SHA256 hash of a file
|
|
178
|
-
*/
|
|
179
|
-
async computeFileHash(filePath) {
|
|
180
|
-
try {
|
|
181
|
-
const { readFile } = await import('node:fs/promises');
|
|
182
|
-
const { createHash } = await import('node:crypto');
|
|
183
|
-
const fileBuffer = await readFile(filePath);
|
|
184
|
-
const hash = createHash('sha256').update(fileBuffer).digest('hex');
|
|
185
|
-
return hash;
|
|
81
|
+
return true;
|
|
186
82
|
}
|
|
187
83
|
catch (error) {
|
|
188
|
-
console.error(
|
|
189
|
-
return
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* Download model from a fallback source
|
|
194
|
-
*/
|
|
195
|
-
async downloadFromSource(source) {
|
|
196
|
-
if (source.type === 'transformers') {
|
|
197
|
-
// Use transformers.js native download
|
|
198
|
-
const { pipeline } = await import('@huggingface/transformers');
|
|
199
|
-
env.cacheDir = this.modelPath;
|
|
200
|
-
env.allowRemoteModels = true;
|
|
201
|
-
const extractor = await pipeline('feature-extraction', CRITICAL_MODEL_CONFIG.modelName);
|
|
202
|
-
// Test the model
|
|
203
|
-
const test = await extractor('test', { pooling: 'mean', normalize: true });
|
|
204
|
-
if (test.data.length !== CRITICAL_MODEL_CONFIG.embeddingDimensions) {
|
|
205
|
-
throw new Error(`CRITICAL: Model dimension mismatch! ` +
|
|
206
|
-
`Expected ${CRITICAL_MODEL_CONFIG.embeddingDimensions}, ` +
|
|
207
|
-
`got ${test.data.length}`);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
else if (source.type === 'tarball') {
|
|
211
|
-
// Tarball extraction would require additional dependencies
|
|
212
|
-
// Skip this source and try next fallback
|
|
213
|
-
console.warn(`⚠️ Tarball extraction not available for ${source.name}. Trying next source...`);
|
|
214
|
-
return; // Will continue to next source in the loop
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
/**
|
|
218
|
-
* Configure transformers.js to use verified local model
|
|
219
|
-
*/
|
|
220
|
-
configureTransformers() {
|
|
221
|
-
env.localModelPath = this.modelPath;
|
|
222
|
-
env.allowRemoteModels = false; // Force local only after verification
|
|
223
|
-
console.log('🔒 Transformers configured to use verified local model');
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Detect where models should be stored
|
|
227
|
-
*/
|
|
228
|
-
detectModelPath() {
|
|
229
|
-
// Browser always uses default path
|
|
230
|
-
if (typeof window !== 'undefined') {
|
|
231
|
-
return './models';
|
|
232
|
-
}
|
|
233
|
-
// Use require for synchronous access in Node.js
|
|
234
|
-
try {
|
|
235
|
-
const fs = require('node:fs');
|
|
236
|
-
const path = require('node:path');
|
|
237
|
-
const candidates = [
|
|
238
|
-
process.env.BRAINY_MODELS_PATH,
|
|
239
|
-
'./models',
|
|
240
|
-
path.join(process.cwd(), 'models'),
|
|
241
|
-
path.join(process.env.HOME || '', '.brainy', 'models'),
|
|
242
|
-
'/opt/models', // Lambda/container path
|
|
243
|
-
env.cacheDir
|
|
244
|
-
];
|
|
245
|
-
for (const candidatePath of candidates) {
|
|
246
|
-
if (candidatePath && fs.existsSync(candidatePath)) {
|
|
247
|
-
const modelPath = path.join(candidatePath, ...CRITICAL_MODEL_CONFIG.modelName.split('/'));
|
|
248
|
-
if (fs.existsSync(path.join(modelPath, 'onnx', 'model.onnx'))) {
|
|
249
|
-
return candidatePath; // Return the models directory, not its parent
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
catch (e) {
|
|
255
|
-
// If Node.js modules not available, return default
|
|
84
|
+
console.error('❌ Model verification failed:', error);
|
|
85
|
+
return false;
|
|
256
86
|
}
|
|
257
|
-
// Default
|
|
258
|
-
return './models';
|
|
259
87
|
}
|
|
260
88
|
/**
|
|
261
89
|
* Get model status for diagnostics
|
|
@@ -263,10 +91,10 @@ export class ModelGuardian {
|
|
|
263
91
|
async getStatus() {
|
|
264
92
|
return {
|
|
265
93
|
verified: this.isVerified,
|
|
266
|
-
path: this.modelPath,
|
|
267
94
|
lastVerification: this.lastVerification,
|
|
268
95
|
modelName: CRITICAL_MODEL_CONFIG.modelName,
|
|
269
|
-
dimensions: CRITICAL_MODEL_CONFIG.embeddingDimensions
|
|
96
|
+
dimensions: CRITICAL_MODEL_CONFIG.embeddingDimensions,
|
|
97
|
+
bundled: CRITICAL_MODEL_CONFIG.bundled
|
|
270
98
|
};
|
|
271
99
|
}
|
|
272
100
|
/**
|
|
@@ -2,18 +2,14 @@
|
|
|
2
2
|
* Unified Embedding Manager
|
|
3
3
|
*
|
|
4
4
|
* THE single source of truth for all embedding operations in Brainy.
|
|
5
|
-
*
|
|
6
|
-
* into one clean, maintainable class.
|
|
5
|
+
* Uses direct ONNX WASM inference for universal compatibility.
|
|
7
6
|
*
|
|
8
7
|
* Features:
|
|
9
8
|
* - Singleton pattern ensures ONE model instance
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* -
|
|
9
|
+
* - Direct ONNX WASM (no transformers.js dependency)
|
|
10
|
+
* - Bundled model (no runtime downloads)
|
|
11
|
+
* - Works everywhere: Node.js, Bun, Bun --compile, browsers
|
|
13
12
|
* - Memory monitoring
|
|
14
|
-
*
|
|
15
|
-
* This replaces: SingletonModelManager, TransformerEmbedding, ModelPrecisionManager,
|
|
16
|
-
* hybridModelManager, universalMemoryManager, and more.
|
|
17
13
|
*/
|
|
18
14
|
import { Vector, EmbeddingFunction } from '../coreTypes.js';
|
|
19
15
|
export type ModelPrecision = 'q8' | 'fp32';
|
|
@@ -27,9 +23,11 @@ interface EmbeddingStats {
|
|
|
27
23
|
}
|
|
28
24
|
/**
|
|
29
25
|
* Unified Embedding Manager - Clean, simple, reliable
|
|
26
|
+
*
|
|
27
|
+
* Now powered by direct ONNX WASM for universal compatibility.
|
|
30
28
|
*/
|
|
31
29
|
export declare class EmbeddingManager {
|
|
32
|
-
private
|
|
30
|
+
private engine;
|
|
33
31
|
private precision;
|
|
34
32
|
private modelName;
|
|
35
33
|
private initialized;
|
|
@@ -61,14 +59,6 @@ export declare class EmbeddingManager {
|
|
|
61
59
|
* Get embedding function for compatibility
|
|
62
60
|
*/
|
|
63
61
|
getEmbeddingFunction(): EmbeddingFunction;
|
|
64
|
-
/**
|
|
65
|
-
* Get models directory path
|
|
66
|
-
* Note: In browser environments, returns a simple default path
|
|
67
|
-
* In Node.js, checks multiple locations for the models directory
|
|
68
|
-
*/
|
|
69
|
-
private getModelsPath;
|
|
70
|
-
private modelsPathCache;
|
|
71
|
-
private resolveModelsPathSync;
|
|
72
62
|
/**
|
|
73
63
|
* Get memory usage in MB
|
|
74
64
|
*/
|