@camstack/addon-post-analysis 1.1.4 → 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{dist-B2FbCLNx.mjs → dist-BpGP9ago.mjs} +41 -5
- package/dist/{dist-B6aOcq5T.js → dist-n-zJ0Uox.js} +46 -4
- package/dist/embedding-encoder/index.js +272 -93
- package/dist/embedding-encoder/index.mjs +270 -91
- package/dist/enrichment-engine/index.js +2 -2
- package/dist/enrichment-engine/index.mjs +1 -1
- package/dist/pipeline-analytics/_stub.js +1 -1
- package/dist/pipeline-analytics/{_virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-Bcn1PmOA.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_pipeline_analytics_widgets-DplNAc3T.mjs} +3 -3
- package/dist/pipeline-analytics/{_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-BFIbMkkd.mjs → _virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DBkzwlqD.mjs} +1 -1
- package/dist/pipeline-analytics/{hostInit-gu9R5ABc.mjs → hostInit-Di_TVCXX.mjs} +3 -3
- package/dist/pipeline-analytics/index.js +316 -2
- package/dist/pipeline-analytics/index.mjs +315 -1
- package/dist/pipeline-analytics/remoteEntry.js +1 -1
- package/dist/{resolve-frame-B6a1wzQb.js → resolve-frame-DB2NdMu2.js} +1 -1
- package/package.json +2 -1
- package/python/raw_tensor_inference.py +73 -0
- package/python/requirements-embedding.txt +8 -0
- package/python/tensor_frames.py +70 -0
- package/python/test_text_encoder.py +48 -0
- package/python/text_encoder_inference.py +76 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as BaseAddon, i as embeddingEncoderCapability, o as hfModelUrl } from "../dist-BpGP9ago.mjs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import * as path$1 from "node:path";
|
|
4
3
|
import * as fs from "node:fs";
|
|
4
|
+
import * as path$1 from "node:path";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
//#region \0rolldown/runtime.js
|
|
7
7
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
@@ -257,98 +257,164 @@ var ModelDownloadService = class {
|
|
|
257
257
|
};
|
|
258
258
|
//#endregion
|
|
259
259
|
//#region src/embedding-encoder/catalogs/embedding-models.ts
|
|
260
|
+
var HF_REPO = "camstack/camstack-models";
|
|
261
|
+
var hf = (path) => hfModelUrl(HF_REPO, path);
|
|
262
|
+
/**
|
|
263
|
+
* The CLIP BPE tokenizer (HF `tokenizers` format: vocab 49408 + 48894 merges).
|
|
264
|
+
* Hosted next to every text-encoder onnx (`.../onnx/tokenizer.json`) and fetched
|
|
265
|
+
* as a sibling file so it lands beside the model in the shared models dir.
|
|
266
|
+
*/
|
|
267
|
+
var TOKENIZER_FILE = "tokenizer.json";
|
|
268
|
+
var ovFormat = (url, sizeMB) => {
|
|
269
|
+
const base = url.split("/").pop() ?? "";
|
|
270
|
+
const files = base.endsWith(".xml") ? [base.replace(/\.xml$/, ".bin")] : void 0;
|
|
271
|
+
return {
|
|
272
|
+
url,
|
|
273
|
+
sizeMB,
|
|
274
|
+
runtimes: ["python"],
|
|
275
|
+
...files ? { files } : {}
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* Files inside an .mlpackage directory bundle.
|
|
280
|
+
* Must be fetched alongside the package root when isDirectory is true.
|
|
281
|
+
*/
|
|
282
|
+
var MLPACKAGE_FILES = [
|
|
283
|
+
"Manifest.json",
|
|
284
|
+
"Data/com.apple.CoreML/model.mlmodel",
|
|
285
|
+
"Data/com.apple.CoreML/weights/weight.bin"
|
|
286
|
+
];
|
|
260
287
|
var CLIP_IMAGE_MODELS = [
|
|
261
288
|
{
|
|
262
|
-
id: "
|
|
263
|
-
name: "
|
|
264
|
-
description: "
|
|
289
|
+
id: "mobileclip-s0",
|
|
290
|
+
name: "MobileCLIP S0",
|
|
291
|
+
description: "Apple MobileCLIP S0 — fast vision encoder, 512-dim, 256×256 (40 MB ONNX)",
|
|
265
292
|
inputSize: {
|
|
266
|
-
width:
|
|
267
|
-
height:
|
|
293
|
+
width: 256,
|
|
294
|
+
height: 256
|
|
268
295
|
},
|
|
269
296
|
labels: [],
|
|
270
|
-
inputLayout: "nchw",
|
|
271
297
|
inputNormalization: "none",
|
|
272
|
-
formats: {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
298
|
+
formats: {
|
|
299
|
+
onnx: {
|
|
300
|
+
url: hf("clip/mobileclip-s0/onnx/camstack-mobileclip-s0-vision.onnx"),
|
|
301
|
+
sizeMB: 40
|
|
302
|
+
},
|
|
303
|
+
openvino: ovFormat(hf("clip/mobileclip-s0/openvino/camstack-mobileclip-s0-vision.xml"), 25),
|
|
304
|
+
coreml: {
|
|
305
|
+
url: hf("clip/mobileclip-s0/coreml/camstack-mobileclip-s0-vision.mlpackage"),
|
|
306
|
+
sizeMB: 30,
|
|
307
|
+
isDirectory: true,
|
|
308
|
+
files: [...MLPACKAGE_FILES],
|
|
309
|
+
runtimes: ["python"]
|
|
310
|
+
}
|
|
311
|
+
}
|
|
276
312
|
},
|
|
277
313
|
{
|
|
278
|
-
id: "
|
|
279
|
-
name: "
|
|
280
|
-
description: "
|
|
314
|
+
id: "mobileclip-s1",
|
|
315
|
+
name: "MobileCLIP S1",
|
|
316
|
+
description: "Apple MobileCLIP S1 — balanced vision encoder, 512-dim, 256×256 (90 MB ONNX)",
|
|
281
317
|
inputSize: {
|
|
282
|
-
width:
|
|
283
|
-
height:
|
|
318
|
+
width: 256,
|
|
319
|
+
height: 256
|
|
284
320
|
},
|
|
285
321
|
labels: [],
|
|
286
|
-
inputLayout: "nchw",
|
|
287
322
|
inputNormalization: "none",
|
|
288
|
-
formats: {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
323
|
+
formats: {
|
|
324
|
+
onnx: {
|
|
325
|
+
url: hf("clip/mobileclip-s1/onnx/camstack-mobileclip-s1-vision.onnx"),
|
|
326
|
+
sizeMB: 90
|
|
327
|
+
},
|
|
328
|
+
openvino: ovFormat(hf("clip/mobileclip-s1/openvino/camstack-mobileclip-s1-vision.xml"), 55),
|
|
329
|
+
coreml: {
|
|
330
|
+
url: hf("clip/mobileclip-s1/coreml/camstack-mobileclip-s1-vision.mlpackage"),
|
|
331
|
+
sizeMB: 65,
|
|
332
|
+
isDirectory: true,
|
|
333
|
+
files: [...MLPACKAGE_FILES],
|
|
334
|
+
runtimes: ["python"]
|
|
335
|
+
}
|
|
336
|
+
}
|
|
292
337
|
},
|
|
293
338
|
{
|
|
294
|
-
id: "
|
|
295
|
-
name: "
|
|
296
|
-
description: "
|
|
339
|
+
id: "mobileclip-s2",
|
|
340
|
+
name: "MobileCLIP S2",
|
|
341
|
+
description: "Apple MobileCLIP S2 — high-accuracy vision encoder, 512-dim, 256×256 (150 MB ONNX)",
|
|
297
342
|
inputSize: {
|
|
298
343
|
width: 256,
|
|
299
344
|
height: 256
|
|
300
345
|
},
|
|
301
346
|
labels: [],
|
|
302
|
-
inputLayout: "nchw",
|
|
303
347
|
inputNormalization: "none",
|
|
304
|
-
formats: {
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
348
|
+
formats: {
|
|
349
|
+
onnx: {
|
|
350
|
+
url: hf("clip/mobileclip-s2/onnx/camstack-mobileclip-s2-vision.onnx"),
|
|
351
|
+
sizeMB: 150
|
|
352
|
+
},
|
|
353
|
+
openvino: ovFormat(hf("clip/mobileclip-s2/openvino/camstack-mobileclip-s2-vision.xml"), 90),
|
|
354
|
+
coreml: {
|
|
355
|
+
url: hf("clip/mobileclip-s2/coreml/camstack-mobileclip-s2-vision.mlpackage"),
|
|
356
|
+
sizeMB: 110,
|
|
357
|
+
isDirectory: true,
|
|
358
|
+
files: [...MLPACKAGE_FILES],
|
|
359
|
+
runtimes: ["python"]
|
|
360
|
+
}
|
|
361
|
+
}
|
|
308
362
|
}
|
|
309
363
|
];
|
|
310
364
|
var CLIP_TEXT_MODELS = [
|
|
311
365
|
{
|
|
312
|
-
id: "
|
|
313
|
-
name: "
|
|
314
|
-
description: "Text encoder for
|
|
366
|
+
id: "mobileclip-s0-text",
|
|
367
|
+
name: "MobileCLIP S0 Text Encoder",
|
|
368
|
+
description: "Text encoder for MobileCLIP S0, 512-dim, int8 quantized (35 MB)",
|
|
315
369
|
inputSize: {
|
|
316
370
|
width: 0,
|
|
317
371
|
height: 0
|
|
318
372
|
},
|
|
319
373
|
labels: [],
|
|
320
|
-
formats: {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
374
|
+
formats: {
|
|
375
|
+
onnx: {
|
|
376
|
+
url: hf("clip/mobileclip-s0/onnx/camstack-mobileclip-s0-text.onnx"),
|
|
377
|
+
sizeMB: 35,
|
|
378
|
+
files: [TOKENIZER_FILE]
|
|
379
|
+
},
|
|
380
|
+
openvino: ovFormat(hf("clip/mobileclip-s0/openvino/camstack-mobileclip-s0-text.xml"), 22)
|
|
381
|
+
}
|
|
324
382
|
},
|
|
325
383
|
{
|
|
326
|
-
id: "
|
|
327
|
-
name: "
|
|
328
|
-
description: "Text encoder for
|
|
384
|
+
id: "mobileclip-s1-text",
|
|
385
|
+
name: "MobileCLIP S1 Text Encoder",
|
|
386
|
+
description: "Text encoder for MobileCLIP S1, 512-dim, int8 quantized (35 MB)",
|
|
329
387
|
inputSize: {
|
|
330
388
|
width: 0,
|
|
331
389
|
height: 0
|
|
332
390
|
},
|
|
333
391
|
labels: [],
|
|
334
|
-
formats: {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
392
|
+
formats: {
|
|
393
|
+
onnx: {
|
|
394
|
+
url: hf("clip/mobileclip-s1/onnx/camstack-mobileclip-s1-text.onnx"),
|
|
395
|
+
sizeMB: 35,
|
|
396
|
+
files: [TOKENIZER_FILE]
|
|
397
|
+
},
|
|
398
|
+
openvino: ovFormat(hf("clip/mobileclip-s1/openvino/camstack-mobileclip-s1-text.xml"), 22)
|
|
399
|
+
}
|
|
338
400
|
},
|
|
339
401
|
{
|
|
340
|
-
id: "
|
|
341
|
-
name: "
|
|
342
|
-
description: "Text encoder for
|
|
402
|
+
id: "mobileclip-s2-text",
|
|
403
|
+
name: "MobileCLIP S2 Text Encoder",
|
|
404
|
+
description: "Text encoder for MobileCLIP S2, 512-dim, int8 quantized (35 MB)",
|
|
343
405
|
inputSize: {
|
|
344
406
|
width: 0,
|
|
345
407
|
height: 0
|
|
346
408
|
},
|
|
347
409
|
labels: [],
|
|
348
|
-
formats: {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
410
|
+
formats: {
|
|
411
|
+
onnx: {
|
|
412
|
+
url: hf("clip/mobileclip-s2/onnx/camstack-mobileclip-s2-text.onnx"),
|
|
413
|
+
sizeMB: 35,
|
|
414
|
+
files: [TOKENIZER_FILE]
|
|
415
|
+
},
|
|
416
|
+
openvino: ovFormat(hf("clip/mobileclip-s2/openvino/camstack-mobileclip-s2-text.xml"), 22)
|
|
417
|
+
}
|
|
352
418
|
}
|
|
353
419
|
];
|
|
354
420
|
//#endregion
|
|
@@ -480,33 +546,155 @@ var PythonRawTensorEngine = class {
|
|
|
480
546
|
}
|
|
481
547
|
};
|
|
482
548
|
//#endregion
|
|
549
|
+
//#region src/embedding-encoder/shared/python-text-encoder-engine.ts
|
|
550
|
+
/**
|
|
551
|
+
* CLIP text-encoder engine backed by an embedded-Python subprocess
|
|
552
|
+
* (`text_encoder_inference.py`). Tokenization happens IN Python via the HF
|
|
553
|
+
* `tokenizers` Rust BPE (exact by construction) — this replaces the former
|
|
554
|
+
* hand-rolled TypeScript CLIP BPE.
|
|
555
|
+
*
|
|
556
|
+
* The caller sends raw UTF-8 text; Python tokenizes (truncate/pad to 77), runs
|
|
557
|
+
* onnxruntime, and returns the embedding tensor. Wire protocol = length-prefixed
|
|
558
|
+
* binary frames ([4B LE length][payload]):
|
|
559
|
+
* ready (in): [0x01]
|
|
560
|
+
* request (out): UTF-8 text bytes
|
|
561
|
+
* response (in): [1B ndims][dims × 4B LE uint32][float32 LE data]
|
|
562
|
+
*/
|
|
563
|
+
var PythonTextEncoderEngine = class {
|
|
564
|
+
pythonPath;
|
|
565
|
+
scriptPath;
|
|
566
|
+
modelPath;
|
|
567
|
+
tokenizerPath;
|
|
568
|
+
process = null;
|
|
569
|
+
receiveBuffer = Buffer.alloc(0);
|
|
570
|
+
pendingResolve = null;
|
|
571
|
+
pendingReject = null;
|
|
572
|
+
log;
|
|
573
|
+
constructor(pythonPath, scriptPath, modelPath, tokenizerPath, logger) {
|
|
574
|
+
this.pythonPath = pythonPath;
|
|
575
|
+
this.scriptPath = scriptPath;
|
|
576
|
+
this.modelPath = modelPath;
|
|
577
|
+
this.tokenizerPath = tokenizerPath;
|
|
578
|
+
this.log = logger ?? createNoopLogger();
|
|
579
|
+
}
|
|
580
|
+
async initialize() {
|
|
581
|
+
this.process = spawn(this.pythonPath, [
|
|
582
|
+
this.scriptPath,
|
|
583
|
+
this.modelPath,
|
|
584
|
+
this.tokenizerPath
|
|
585
|
+
], { stdio: [
|
|
586
|
+
"pipe",
|
|
587
|
+
"pipe",
|
|
588
|
+
"pipe"
|
|
589
|
+
] });
|
|
590
|
+
this.process.stderr?.on("data", (chunk) => {
|
|
591
|
+
const text = chunk.toString().trim();
|
|
592
|
+
if (text) this.log.warn(text);
|
|
593
|
+
});
|
|
594
|
+
this.process.on("error", (err) => {
|
|
595
|
+
this.log.error("Python text-encoder process error", { meta: { error: err.message } });
|
|
596
|
+
this.pendingReject?.(err);
|
|
597
|
+
this.pendingReject = null;
|
|
598
|
+
this.pendingResolve = null;
|
|
599
|
+
});
|
|
600
|
+
this.process.on("exit", (code) => {
|
|
601
|
+
if (code !== 0 && code !== null) {
|
|
602
|
+
const err = /* @__PURE__ */ new Error(`PythonTextEncoderEngine: process exited with code ${code}`);
|
|
603
|
+
this.pendingReject?.(err);
|
|
604
|
+
this.pendingReject = null;
|
|
605
|
+
this.pendingResolve = null;
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
this.process.stdout.on("data", (chunk) => {
|
|
609
|
+
this.receiveBuffer = Buffer.concat([this.receiveBuffer, chunk]);
|
|
610
|
+
this.tryReceive();
|
|
611
|
+
});
|
|
612
|
+
const ready = await this.receiveFrame();
|
|
613
|
+
if (ready.length !== 1 || ready[0] !== 1) throw new Error("PythonTextEncoderEngine: unexpected ready frame");
|
|
614
|
+
this.log.info("CLIP text-encoder engine ready (embedded Python)", { meta: {
|
|
615
|
+
modelPath: this.modelPath,
|
|
616
|
+
tokenizerPath: this.tokenizerPath
|
|
617
|
+
} });
|
|
618
|
+
}
|
|
619
|
+
/** Tokenize + encode `text` into the model embedding (float32). */
|
|
620
|
+
async encode(text) {
|
|
621
|
+
if (!this.process?.stdin) throw new Error("PythonTextEncoderEngine: not initialized — call initialize() first");
|
|
622
|
+
const payload = Buffer.from(text, "utf-8");
|
|
623
|
+
const lenBuf = Buffer.allocUnsafe(4);
|
|
624
|
+
lenBuf.writeUInt32LE(payload.length, 0);
|
|
625
|
+
this.process.stdin.write(Buffer.concat([lenBuf, payload]));
|
|
626
|
+
const resp = await this.receiveFrame();
|
|
627
|
+
const floatStart = 1 + resp.readUInt8(0) * 4;
|
|
628
|
+
const count = (resp.length - floatStart) / 4;
|
|
629
|
+
const out = new Float32Array(count);
|
|
630
|
+
for (let i = 0; i < count; i++) out[i] = resp.readFloatLE(floatStart + i * 4);
|
|
631
|
+
return out;
|
|
632
|
+
}
|
|
633
|
+
async dispose() {
|
|
634
|
+
const proc = this.process;
|
|
635
|
+
if (!proc) return;
|
|
636
|
+
this.process = null;
|
|
637
|
+
proc.stdin?.end();
|
|
638
|
+
proc.kill("SIGTERM");
|
|
639
|
+
await new Promise((resolve) => {
|
|
640
|
+
const timer = setTimeout(() => {
|
|
641
|
+
try {
|
|
642
|
+
proc.kill("SIGKILL");
|
|
643
|
+
} catch {}
|
|
644
|
+
resolve();
|
|
645
|
+
}, 5e3);
|
|
646
|
+
proc.once("exit", () => {
|
|
647
|
+
clearTimeout(timer);
|
|
648
|
+
resolve();
|
|
649
|
+
});
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
receiveFrame() {
|
|
653
|
+
return new Promise((resolve, reject) => {
|
|
654
|
+
this.pendingResolve = resolve;
|
|
655
|
+
this.pendingReject = reject;
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
tryReceive() {
|
|
659
|
+
if (this.receiveBuffer.length < 4) return;
|
|
660
|
+
const length = this.receiveBuffer.readUInt32LE(0);
|
|
661
|
+
if (this.receiveBuffer.length < 4 + length) return;
|
|
662
|
+
const payload = Buffer.from(this.receiveBuffer.subarray(4, 4 + length));
|
|
663
|
+
this.receiveBuffer = this.receiveBuffer.subarray(4 + length);
|
|
664
|
+
const resolve = this.pendingResolve;
|
|
665
|
+
this.pendingResolve = null;
|
|
666
|
+
this.pendingReject = null;
|
|
667
|
+
resolve?.(payload);
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
//#endregion
|
|
483
671
|
//#region src/embedding-encoder/addon/clip-models.ts
|
|
484
672
|
var CLIP_MODEL_META = {
|
|
485
|
-
"
|
|
486
|
-
imageModelId: "
|
|
487
|
-
textModelId: "
|
|
673
|
+
"mobileclip-s0": {
|
|
674
|
+
imageModelId: "mobileclip-s0",
|
|
675
|
+
textModelId: "mobileclip-s0-text",
|
|
488
676
|
embeddingDim: 512,
|
|
489
|
-
inputSize:
|
|
677
|
+
inputSize: 256,
|
|
490
678
|
tokenizerType: "clip"
|
|
491
679
|
},
|
|
492
|
-
"
|
|
493
|
-
imageModelId: "
|
|
494
|
-
textModelId: "
|
|
680
|
+
"mobileclip-s1": {
|
|
681
|
+
imageModelId: "mobileclip-s1",
|
|
682
|
+
textModelId: "mobileclip-s1-text",
|
|
495
683
|
embeddingDim: 512,
|
|
496
|
-
inputSize:
|
|
684
|
+
inputSize: 256,
|
|
497
685
|
tokenizerType: "clip"
|
|
498
686
|
},
|
|
499
|
-
"
|
|
500
|
-
imageModelId: "
|
|
501
|
-
textModelId: "
|
|
502
|
-
embeddingDim:
|
|
687
|
+
"mobileclip-s2": {
|
|
688
|
+
imageModelId: "mobileclip-s2",
|
|
689
|
+
textModelId: "mobileclip-s2-text",
|
|
690
|
+
embeddingDim: 512,
|
|
503
691
|
inputSize: 256,
|
|
504
|
-
tokenizerType: "
|
|
692
|
+
tokenizerType: "clip"
|
|
505
693
|
}
|
|
506
694
|
};
|
|
507
|
-
var DEFAULT_CLIP_MODEL = "
|
|
695
|
+
var DEFAULT_CLIP_MODEL = "mobileclip-s1";
|
|
508
696
|
function getModelMeta(modelId) {
|
|
509
|
-
return CLIP_MODEL_META[modelId] ?? CLIP_MODEL_META["
|
|
697
|
+
return CLIP_MODEL_META[modelId] ?? CLIP_MODEL_META["mobileclip-s1"];
|
|
510
698
|
}
|
|
511
699
|
//#endregion
|
|
512
700
|
//#region src/embedding-encoder/addon/clip-preprocessing.ts
|
|
@@ -554,7 +742,7 @@ function l2Normalize(vec) {
|
|
|
554
742
|
//#region src/embedding-encoder/addon/index.ts
|
|
555
743
|
var EmbeddingEncoderAddon = class extends BaseAddon {
|
|
556
744
|
imageRawEngine = null;
|
|
557
|
-
|
|
745
|
+
textEngine = null;
|
|
558
746
|
models = null;
|
|
559
747
|
constructor() {
|
|
560
748
|
super({
|
|
@@ -595,9 +783,8 @@ var EmbeddingEncoderAddon = class extends BaseAddon {
|
|
|
595
783
|
await this.ensureTextEngine();
|
|
596
784
|
const meta = getModelMeta(this.config.modelId);
|
|
597
785
|
const start = Date.now();
|
|
598
|
-
|
|
599
|
-
const
|
|
600
|
-
const output = await this.textRawEngine.run(inputTensor, [1, tokenIds.length]);
|
|
786
|
+
if (!this.textEngine) throw new Error("EmbeddingEncoder: text engine not loaded — ensureTextEngine() must run first");
|
|
787
|
+
const output = await this.textEngine.encode(text);
|
|
601
788
|
const sliced = output.length > meta.embeddingDim ? output.slice(0, meta.embeddingDim) : output;
|
|
602
789
|
const normalized = l2Normalize(new Float32Array(sliced));
|
|
603
790
|
return {
|
|
@@ -621,7 +808,7 @@ var EmbeddingEncoderAddon = class extends BaseAddon {
|
|
|
621
808
|
await this.resolveForEntry(imageEntry, "image");
|
|
622
809
|
}
|
|
623
810
|
async ensureTextEngine() {
|
|
624
|
-
if (this.
|
|
811
|
+
if (this.textEngine) return;
|
|
625
812
|
const meta = getModelMeta(this.config.modelId);
|
|
626
813
|
const textEntry = CLIP_TEXT_MODELS.find((m) => m.id === meta.textModelId);
|
|
627
814
|
if (!textEntry) throw new Error(`EmbeddingEncoderAddon: unknown text model "${meta.textModelId}"`);
|
|
@@ -638,14 +825,21 @@ var EmbeddingEncoderAddon = class extends BaseAddon {
|
|
|
638
825
|
if (!pythonPath) throw new Error("EmbeddingEncoder: embedded Python is unavailable — cannot run ONNX embeddings. ctx.deps.ensurePython() returned null (portable Python download likely failed).");
|
|
639
826
|
const pythonDir = resolveEmbeddingPythonDir();
|
|
640
827
|
await this.ctx.deps.installPythonRequirements(path$1.join(pythonDir, "requirements-embedding.txt"));
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
828
|
+
if (target === "image") {
|
|
829
|
+
const rawEngine = new PythonRawTensorEngine(pythonPath, path$1.join(pythonDir, "raw_tensor_inference.py"), modelPath, engineLogger);
|
|
830
|
+
await rawEngine.initialize();
|
|
831
|
+
this.imageRawEngine = rawEngine;
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const tokenizerPath = path$1.join(path$1.dirname(modelPath), TOKENIZER_FILE);
|
|
835
|
+
if (!fs.existsSync(tokenizerPath)) throw new Error(`EmbeddingEncoder: CLIP tokenizer not found at "${tokenizerPath}" — the tokenizer.json sibling download likely failed.`);
|
|
836
|
+
const textEngine = new PythonTextEncoderEngine(pythonPath, path$1.join(pythonDir, "text_encoder_inference.py"), modelPath, tokenizerPath, engineLogger);
|
|
837
|
+
await textEngine.initialize();
|
|
838
|
+
this.textEngine = textEngine;
|
|
645
839
|
}
|
|
646
840
|
async onShutdown() {
|
|
647
841
|
await this.imageRawEngine?.dispose();
|
|
648
|
-
await this.
|
|
842
|
+
await this.textEngine?.dispose();
|
|
649
843
|
}
|
|
650
844
|
globalSettingsSchema() {
|
|
651
845
|
return this.schema({ sections: [{
|
|
@@ -701,21 +895,6 @@ var EmbeddingEncoderAddon = class extends BaseAddon {
|
|
|
701
895
|
async onConfigChanged() {}
|
|
702
896
|
};
|
|
703
897
|
/**
|
|
704
|
-
* Minimal CLIP tokenizer — encodes ASCII text to token IDs.
|
|
705
|
-
* Production implementations should use a proper BPE tokenizer;
|
|
706
|
-
* this is a simplified placeholder that maps characters to IDs
|
|
707
|
-
* with SOT/EOT tokens for basic functionality.
|
|
708
|
-
*/
|
|
709
|
-
function clipTokenize(text, maxLength = 77) {
|
|
710
|
-
const SOT_TOKEN = 49406;
|
|
711
|
-
const EOT_TOKEN = 49407;
|
|
712
|
-
const tokens = [SOT_TOKEN];
|
|
713
|
-
for (let i = 0; i < text.length && tokens.length < maxLength - 1; i++) tokens.push(text.charCodeAt(i) + 256);
|
|
714
|
-
tokens.push(EOT_TOKEN);
|
|
715
|
-
while (tokens.length < maxLength) tokens.push(0);
|
|
716
|
-
return tokens;
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
898
|
* Locate the addon's bundled `python/` dir (holds `raw_tensor_inference.py` +
|
|
720
899
|
* `requirements-embedding.txt`). Published package first, then `__dirname`
|
|
721
900
|
* candidates for the in-tree dev build.
|
|
@@ -2,8 +2,8 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const require_dist = require("../dist-
|
|
6
|
-
const require_resolve_frame = require("../resolve-frame-
|
|
5
|
+
const require_dist = require("../dist-n-zJ0Uox.js");
|
|
6
|
+
const require_resolve_frame = require("../resolve-frame-DB2NdMu2.js");
|
|
7
7
|
let _camstack_shm_ring = require("@camstack/shm-ring");
|
|
8
8
|
//#region src/enrichment-engine/types.ts
|
|
9
9
|
var DEFAULT_ENRICHMENT_CONFIG = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as string, S as object, b as boolean, f as BaseAddon, g as createEvent, h as asJsonObject, m as EventCategory, v as _enum, w as tuple, x as number, y as array } from "../dist-BpGP9ago.mjs";
|
|
2
2
|
import { n as extractCrop, t as resolveFrame } from "../resolve-frame-CT1T1tWy.mjs";
|
|
3
3
|
import { FrameRingReaderCache } from "@camstack/shm-ring";
|
|
4
4
|
//#region src/enrichment-engine/types.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as e, i as t, n, o as r, r as i, t as a } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react__loadShare__.js-C0AuF9av.mjs";
|
|
2
2
|
import { t as o } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-B3Wx5J80.mjs";
|
|
3
|
-
import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-
|
|
3
|
+
import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare___mf_0_camstack_mf_1_ui_mf_2_library__loadShare__.js-DBkzwlqD.mjs";
|
|
4
4
|
import { n as m, r as h, t as g } from "./_virtual_mf___mfe_internal__addon_pipeline_analytics_widgets__loadShare__react_mf_1_jsx_mf_2_runtime__loadShare__.js-Bm-iyjmq.mjs";
|
|
5
5
|
//#region ../../node_modules/lucide-react/dist/esm/shared/src/utils.js
|
|
6
6
|
var _ = (e) => e.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase(), v = (e) => e.replace(/^([A-Z])|[\s-_]+(\w)/g, (e, t, n) => n ? n.toUpperCase() : t.toLowerCase()), y = (e) => {
|
|
@@ -3,7 +3,7 @@ import "./dist-CYZr2fwk.mjs";
|
|
|
3
3
|
var e = {
|
|
4
4
|
"@camstack/sdk": {
|
|
5
5
|
name: "@camstack/sdk",
|
|
6
|
-
version: "1.1.
|
|
6
|
+
version: "1.1.6",
|
|
7
7
|
scope: ["default"],
|
|
8
8
|
loaded: !1,
|
|
9
9
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -18,7 +18,7 @@ var e = {
|
|
|
18
18
|
},
|
|
19
19
|
"@camstack/types": {
|
|
20
20
|
name: "@camstack/types",
|
|
21
|
-
version: "1.1.
|
|
21
|
+
version: "1.1.6",
|
|
22
22
|
scope: ["default"],
|
|
23
23
|
loaded: !1,
|
|
24
24
|
from: "addon_pipeline_analytics_widgets",
|
|
@@ -33,7 +33,7 @@ var e = {
|
|
|
33
33
|
},
|
|
34
34
|
"@camstack/ui-library": {
|
|
35
35
|
name: "@camstack/ui-library",
|
|
36
|
-
version: "1.1.
|
|
36
|
+
version: "1.1.6",
|
|
37
37
|
scope: ["default"],
|
|
38
38
|
loaded: !1,
|
|
39
39
|
from: "addon_pipeline_analytics_widgets",
|