@reftrixmcp/ml 0.1.7
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/LICENSE +661 -0
- package/dist/dinov2/index.d.ts +7 -0
- package/dist/dinov2/index.d.ts.map +1 -0
- package/dist/dinov2/index.js +7 -0
- package/dist/dinov2/index.js.map +1 -0
- package/dist/dinov2/service.d.ts +106 -0
- package/dist/dinov2/service.d.ts.map +1 -0
- package/dist/dinov2/service.js +446 -0
- package/dist/dinov2/service.js.map +1 -0
- package/dist/dinov2/worker-thread-types.d.ts +77 -0
- package/dist/dinov2/worker-thread-types.d.ts.map +1 -0
- package/dist/dinov2/worker-thread-types.js +4 -0
- package/dist/dinov2/worker-thread-types.js.map +1 -0
- package/dist/dinov2/worker-thread.d.ts +2 -0
- package/dist/dinov2/worker-thread.d.ts.map +1 -0
- package/dist/dinov2/worker-thread.js +231 -0
- package/dist/dinov2/worker-thread.js.map +1 -0
- package/dist/embeddings/index.d.ts +12 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +13 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/embeddings/multimodal-embedding.service.d.ts +400 -0
- package/dist/embeddings/multimodal-embedding.service.d.ts.map +1 -0
- package/dist/embeddings/multimodal-embedding.service.js +650 -0
- package/dist/embeddings/multimodal-embedding.service.js.map +1 -0
- package/dist/embeddings/service.d.ts +261 -0
- package/dist/embeddings/service.d.ts.map +1 -0
- package/dist/embeddings/service.js +1093 -0
- package/dist/embeddings/service.js.map +1 -0
- package/dist/embeddings/style-embedding.service.d.ts +117 -0
- package/dist/embeddings/style-embedding.service.d.ts.map +1 -0
- package/dist/embeddings/style-embedding.service.js +157 -0
- package/dist/embeddings/style-embedding.service.js.map +1 -0
- package/dist/embeddings/types.d.ts +83 -0
- package/dist/embeddings/types.d.ts.map +1 -0
- package/dist/embeddings/types.js +4 -0
- package/dist/embeddings/types.js.map +1 -0
- package/dist/embeddings/vision-embedding.service.d.ts +70 -0
- package/dist/embeddings/vision-embedding.service.d.ts.map +1 -0
- package/dist/embeddings/vision-embedding.service.js +221 -0
- package/dist/embeddings/vision-embedding.service.js.map +1 -0
- package/dist/embeddings/vision-embedding.types.d.ts +102 -0
- package/dist/embeddings/vision-embedding.types.d.ts.map +1 -0
- package/dist/embeddings/vision-embedding.types.js +4 -0
- package/dist/embeddings/vision-embedding.types.js.map +1 -0
- package/dist/embeddings/worker-thread-types.d.ts +152 -0
- package/dist/embeddings/worker-thread-types.d.ts.map +1 -0
- package/dist/embeddings/worker-thread-types.js +4 -0
- package/dist/embeddings/worker-thread-types.js.map +1 -0
- package/dist/embeddings/worker-thread.d.ts +4 -0
- package/dist/embeddings/worker-thread.d.ts.map +1 -0
- package/dist/embeddings/worker-thread.js +441 -0
- package/dist/embeddings/worker-thread.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/search/fulltext-helpers.d.ts +30 -0
- package/dist/search/fulltext-helpers.d.ts.map +1 -0
- package/dist/search/fulltext-helpers.js +40 -0
- package/dist/search/fulltext-helpers.js.map +1 -0
- package/dist/search/hybrid.d.ts +40 -0
- package/dist/search/hybrid.d.ts.map +1 -0
- package/dist/search/hybrid.js +61 -0
- package/dist/search/hybrid.js.map +1 -0
- package/dist/search/index.d.ts +12 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +11 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/rrf.d.ts +69 -0
- package/dist/search/rrf.d.ts.map +1 -0
- package/dist/search/rrf.js +108 -0
- package/dist/search/rrf.js.map +1 -0
- package/dist/search/types.d.ts +130 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +4 -0
- package/dist/search/types.js.map +1 -0
- package/package.json +65 -0
- package/src/dinov2/index.ts +21 -0
- package/src/dinov2/service.ts +539 -0
- package/src/dinov2/worker-thread-types.ts +103 -0
- package/src/dinov2/worker-thread.ts +306 -0
- package/src/embeddings/index.ts +74 -0
- package/src/embeddings/multimodal-embedding.service.ts +992 -0
- package/src/embeddings/service.ts +1287 -0
- package/src/embeddings/style-embedding.service.ts +201 -0
- package/src/embeddings/types.ts +95 -0
- package/src/embeddings/vision-embedding.service.ts +273 -0
- package/src/embeddings/vision-embedding.types.ts +117 -0
- package/src/embeddings/worker-thread-types.ts +194 -0
- package/src/embeddings/worker-thread.ts +529 -0
- package/src/index.ts +70 -0
- package/src/search/fulltext-helpers.ts +45 -0
- package/src/search/hybrid.ts +107 -0
- package/src/search/index.ts +25 -0
- package/src/search/rrf.ts +154 -0
- package/src/search/types.ts +141 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 TKMD and Reftrix Contributors
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
/**
|
|
4
|
+
* DINOv2 visual embedding service exports
|
|
5
|
+
*/
|
|
6
|
+
export { DINOv2Service, DINOV2_EMBEDDING_DIMENSION, DINOV2_INPUT_SIZE } from "./service.js";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dinov2/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,yCAAyC;AAEzC;;GAEG;AAEH,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** DINOv2 ViT-B/14 output dimension */
|
|
2
|
+
export declare const DINOV2_EMBEDDING_DIMENSION = 768;
|
|
3
|
+
/** Expected input image size (width and height) */
|
|
4
|
+
export declare const DINOV2_INPUT_SIZE = 224;
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for DINOv2Service
|
|
7
|
+
*/
|
|
8
|
+
export interface DINOv2ServiceConfig {
|
|
9
|
+
/**
|
|
10
|
+
* Path to the ONNX model file.
|
|
11
|
+
* Can also be set via env var DINOV2_MODEL_PATH.
|
|
12
|
+
*/
|
|
13
|
+
modelPath: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* DINOv2Service - Generates visual embeddings using DINOv2 ViT-B/14
|
|
17
|
+
*
|
|
18
|
+
* ONNX inference is offloaded to a Worker Thread by default.
|
|
19
|
+
* The main thread manages the Worker lifecycle; the worker owns
|
|
20
|
+
* the ONNX InferenceSession lifecycle (init, inference, dispose).
|
|
21
|
+
*/
|
|
22
|
+
export declare class DINOv2Service {
|
|
23
|
+
private modelPath;
|
|
24
|
+
private useWorkerThread;
|
|
25
|
+
private worker;
|
|
26
|
+
private workerInitPromise;
|
|
27
|
+
private workerReady;
|
|
28
|
+
private workerRestartCount;
|
|
29
|
+
private pendingRequests;
|
|
30
|
+
private lastCrashTime;
|
|
31
|
+
private inProcessSession;
|
|
32
|
+
private _isInitialized;
|
|
33
|
+
constructor(config: DINOv2ServiceConfig);
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the service. Spawns the worker thread and loads the model.
|
|
36
|
+
* Must be called before generateEmbedding().
|
|
37
|
+
*/
|
|
38
|
+
initialize(): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Ensure the worker thread is spawned and initialized.
|
|
41
|
+
*/
|
|
42
|
+
private ensureWorkerReady;
|
|
43
|
+
private spawnAndInitWorker;
|
|
44
|
+
/**
|
|
45
|
+
* Send a message to the worker and return a Promise for the response.
|
|
46
|
+
*/
|
|
47
|
+
private sendWorkerMessage;
|
|
48
|
+
/**
|
|
49
|
+
* Route a response from the worker to the pending request's promise.
|
|
50
|
+
*/
|
|
51
|
+
private handleWorkerResponse;
|
|
52
|
+
/**
|
|
53
|
+
* Handle worker thread crash: reject all pending requests, track restart count.
|
|
54
|
+
*/
|
|
55
|
+
private handleWorkerCrash;
|
|
56
|
+
private canRestartWorker;
|
|
57
|
+
private initializeInProcess;
|
|
58
|
+
private generateInProcess;
|
|
59
|
+
/**
|
|
60
|
+
* Generate a visual embedding for a single image.
|
|
61
|
+
*
|
|
62
|
+
* The imageBuffer must contain raw 224x224x3 RGB pixel data (150,528 bytes).
|
|
63
|
+
* The caller is responsible for resizing/cropping to 224x224 via Sharp.
|
|
64
|
+
*
|
|
65
|
+
* @param imageBuffer - Raw 224x224x3 RGB pixel buffer
|
|
66
|
+
* @returns 768-dimensional L2-normalized embedding vector
|
|
67
|
+
*/
|
|
68
|
+
generateEmbedding(imageBuffer: Buffer): Promise<number[]>;
|
|
69
|
+
/**
|
|
70
|
+
* Generate embeddings for multiple images sequentially.
|
|
71
|
+
*
|
|
72
|
+
* DINOv2 processes one image at a time (no native batching for ViT),
|
|
73
|
+
* so this runs inference sequentially through the single Worker Thread.
|
|
74
|
+
*
|
|
75
|
+
* @param imageBuffers - Array of raw 224x224x3 RGB pixel buffers
|
|
76
|
+
* @returns Array of 768-dimensional L2-normalized embedding vectors
|
|
77
|
+
*/
|
|
78
|
+
generateBatchEmbeddings(imageBuffers: Buffer[]): Promise<number[][]>;
|
|
79
|
+
/**
|
|
80
|
+
* Generate embedding via Worker Thread with crash recovery.
|
|
81
|
+
*/
|
|
82
|
+
private generateViaWorker;
|
|
83
|
+
/**
|
|
84
|
+
* Dispose the ONNX session to free native memory.
|
|
85
|
+
* After disposal, the next generateEmbedding() call will re-initialize.
|
|
86
|
+
*/
|
|
87
|
+
dispose(): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Terminate the worker thread completely and clean up.
|
|
90
|
+
* After this, the service cannot be used until a new instance is created.
|
|
91
|
+
*/
|
|
92
|
+
terminate(): Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* Whether the service is initialized and ready for inference.
|
|
95
|
+
*/
|
|
96
|
+
get initialized(): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Whether this service is using a Worker Thread for inference.
|
|
99
|
+
*/
|
|
100
|
+
isUsingWorkerThread(): boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Get the number of worker thread restarts that have occurred.
|
|
103
|
+
*/
|
|
104
|
+
getWorkerRestartCount(): number;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/dinov2/service.ts"],"names":[],"mappings":"AA8BA,uCAAuC;AACvC,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,mDAAmD;AACnD,eAAO,MAAM,iBAAiB,MAAM,CAAC;AAYrC;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;CACnB;AA6CD;;;;;;GAMG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAU;IAGjC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,iBAAiB,CAA8B;IACvD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,eAAe,CAA0C;IACjE,OAAO,CAAC,aAAa,CAAK;IAG1B,OAAO,CAAC,gBAAgB,CAAwB;IAEhD,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,EAAE,mBAAmB;IASvC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC;;OAEG;YACW,iBAAiB;YAkBjB,kBAAkB;IAkDhC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAS5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAezB,OAAO,CAAC,gBAAgB;YAQV,mBAAmB;YASnB,iBAAiB;IAqE/B;;;;;;;;OAQG;IACG,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAkB/D;;;;;;;;OAQG;IACG,uBAAuB,CAAC,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;IAS1E;;OAEG;YACW,iBAAiB;IAiC/B;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA2B9B;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IA2ChC;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,mBAAmB,IAAI,OAAO;IAI9B;;OAEG;IACH,qBAAqB,IAAI,MAAM;CAGhC"}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 TKMD and Reftrix Contributors
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
/**
|
|
4
|
+
* DINOv2 Embedding Service
|
|
5
|
+
*
|
|
6
|
+
* Generates visual embeddings using DINOv2 ViT-B/14 via ONNX Runtime.
|
|
7
|
+
* Inference is offloaded to a Worker Thread by default to keep the main
|
|
8
|
+
* event loop responsive for BullMQ heartbeats and IPC messages.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* const service = new DINOv2Service({ modelPath: '/path/to/model.onnx' });
|
|
12
|
+
* await service.initialize();
|
|
13
|
+
* const embedding = await service.generateEmbedding(imageBuffer);
|
|
14
|
+
* await service.dispose();
|
|
15
|
+
*
|
|
16
|
+
* Set env DINOV2_WORKER_THREAD=false to run inference in-process (for testing).
|
|
17
|
+
*
|
|
18
|
+
* @module dinov2/service
|
|
19
|
+
*/
|
|
20
|
+
import { Worker } from "node:worker_threads";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
// =====================================================
|
|
24
|
+
// Constants
|
|
25
|
+
// =====================================================
|
|
26
|
+
/** DINOv2 ViT-B/14 output dimension */
|
|
27
|
+
export const DINOV2_EMBEDDING_DIMENSION = 768;
|
|
28
|
+
/** Expected input image size (width and height) */
|
|
29
|
+
export const DINOV2_INPUT_SIZE = 224;
|
|
30
|
+
/** Maximum number of automatic worker thread restarts after crash. */
|
|
31
|
+
const MAX_WORKER_RESTARTS = 5;
|
|
32
|
+
/** Timeout for worker thread responses (ms). Covers model loading + inference. */
|
|
33
|
+
const WORKER_RESPONSE_TIMEOUT_MS = 30_000;
|
|
34
|
+
// =====================================================
|
|
35
|
+
// Helper: request ID generation
|
|
36
|
+
// =====================================================
|
|
37
|
+
let requestIdCounter = 0;
|
|
38
|
+
function generateRequestId() {
|
|
39
|
+
return `dinov2_${Date.now()}_${++requestIdCounter}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolve the path to the DINOv2 worker thread script.
|
|
43
|
+
*/
|
|
44
|
+
function resolveWorkerScriptPath() {
|
|
45
|
+
const currentDir = path.dirname(fileURLToPath(import.meta.url));
|
|
46
|
+
return path.resolve(currentDir, "worker-thread.js");
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whether to use worker thread for ONNX inference.
|
|
50
|
+
* Disabled by env var DINOV2_WORKER_THREAD=false or in test environments.
|
|
51
|
+
*/
|
|
52
|
+
function isWorkerThreadEnabled() {
|
|
53
|
+
const envVal = process.env.DINOV2_WORKER_THREAD;
|
|
54
|
+
if (envVal === "false" || envVal === "0")
|
|
55
|
+
return false;
|
|
56
|
+
// Disable in Vitest to avoid worker thread complications in test harness
|
|
57
|
+
if (process.env.VITEST === "true" || process.env.VITEST_WORKER_ID !== undefined)
|
|
58
|
+
return false;
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
// =====================================================
|
|
62
|
+
// DINOv2Service
|
|
63
|
+
// =====================================================
|
|
64
|
+
/**
|
|
65
|
+
* DINOv2Service - Generates visual embeddings using DINOv2 ViT-B/14
|
|
66
|
+
*
|
|
67
|
+
* ONNX inference is offloaded to a Worker Thread by default.
|
|
68
|
+
* The main thread manages the Worker lifecycle; the worker owns
|
|
69
|
+
* the ONNX InferenceSession lifecycle (init, inference, dispose).
|
|
70
|
+
*/
|
|
71
|
+
export class DINOv2Service {
|
|
72
|
+
modelPath;
|
|
73
|
+
useWorkerThread;
|
|
74
|
+
// --- Worker Thread state ---
|
|
75
|
+
worker = null;
|
|
76
|
+
workerInitPromise = null;
|
|
77
|
+
workerReady = false;
|
|
78
|
+
workerRestartCount = 0;
|
|
79
|
+
pendingRequests = new Map();
|
|
80
|
+
lastCrashTime = 0;
|
|
81
|
+
// --- In-process fallback state ---
|
|
82
|
+
inProcessSession = null;
|
|
83
|
+
_isInitialized = false;
|
|
84
|
+
constructor(config) {
|
|
85
|
+
this.modelPath = config.modelPath;
|
|
86
|
+
this.useWorkerThread = isWorkerThreadEnabled();
|
|
87
|
+
}
|
|
88
|
+
// =====================================================
|
|
89
|
+
// Worker Thread management
|
|
90
|
+
// =====================================================
|
|
91
|
+
/**
|
|
92
|
+
* Initialize the service. Spawns the worker thread and loads the model.
|
|
93
|
+
* Must be called before generateEmbedding().
|
|
94
|
+
*/
|
|
95
|
+
async initialize() {
|
|
96
|
+
if (this._isInitialized)
|
|
97
|
+
return;
|
|
98
|
+
if (this.useWorkerThread) {
|
|
99
|
+
await this.ensureWorkerReady();
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
await this.initializeInProcess();
|
|
103
|
+
}
|
|
104
|
+
this._isInitialized = true;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Ensure the worker thread is spawned and initialized.
|
|
108
|
+
*/
|
|
109
|
+
async ensureWorkerReady() {
|
|
110
|
+
if (this.workerReady && this.worker)
|
|
111
|
+
return;
|
|
112
|
+
if (this.workerInitPromise)
|
|
113
|
+
return this.workerInitPromise;
|
|
114
|
+
// Cooldown after crashes to prevent rapid spawn-crash cycles
|
|
115
|
+
if (this.lastCrashTime > 0) {
|
|
116
|
+
const CRASH_COOLDOWN_MS = 3_000;
|
|
117
|
+
const elapsed = Date.now() - this.lastCrashTime;
|
|
118
|
+
if (elapsed < CRASH_COOLDOWN_MS) {
|
|
119
|
+
const waitMs = CRASH_COOLDOWN_MS - elapsed;
|
|
120
|
+
await new Promise((resolve) => setTimeout(resolve, waitMs));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
this.workerInitPromise = this.spawnAndInitWorker();
|
|
124
|
+
return this.workerInitPromise;
|
|
125
|
+
}
|
|
126
|
+
async spawnAndInitWorker() {
|
|
127
|
+
try {
|
|
128
|
+
const scriptPath = resolveWorkerScriptPath();
|
|
129
|
+
// Worker threads inherit the parent's execArgv by default.
|
|
130
|
+
// Pass empty array to prevent parent flags from propagating.
|
|
131
|
+
this.worker = new Worker(scriptPath, { execArgv: [] });
|
|
132
|
+
this.worker.on("message", (response) => {
|
|
133
|
+
this.handleWorkerResponse(response);
|
|
134
|
+
});
|
|
135
|
+
this.worker.on("error", (error) => {
|
|
136
|
+
console.warn("[DINOv2] Worker Thread error:", error.message);
|
|
137
|
+
this.handleWorkerCrash(error);
|
|
138
|
+
});
|
|
139
|
+
this.worker.on("exit", (code) => {
|
|
140
|
+
if (code !== 0) {
|
|
141
|
+
console.warn("[DINOv2] Worker Thread exited with code:", code);
|
|
142
|
+
this.handleWorkerCrash(new Error(`Worker thread exited with code ${code}`));
|
|
143
|
+
}
|
|
144
|
+
this.workerReady = false;
|
|
145
|
+
this.worker = null;
|
|
146
|
+
});
|
|
147
|
+
const response = await this.sendWorkerMessage({
|
|
148
|
+
type: "init",
|
|
149
|
+
requestId: generateRequestId(),
|
|
150
|
+
modelPath: this.modelPath,
|
|
151
|
+
});
|
|
152
|
+
if (response.type === "error") {
|
|
153
|
+
throw new Error(`Worker init failed: ${response.error}`);
|
|
154
|
+
}
|
|
155
|
+
this.workerReady = true;
|
|
156
|
+
if (response.type === "init") {
|
|
157
|
+
// eslint-disable-next-line no-console
|
|
158
|
+
console.log("[DINOv2] Worker Thread initialized in %dms", response.loadTimeMs);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
this.workerInitPromise = null;
|
|
163
|
+
this.workerReady = false;
|
|
164
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
165
|
+
throw new Error(`Failed to initialize DINOv2 Worker Thread: ${message}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Send a message to the worker and return a Promise for the response.
|
|
170
|
+
*/
|
|
171
|
+
sendWorkerMessage(message) {
|
|
172
|
+
if (!this.worker) {
|
|
173
|
+
return Promise.reject(new Error("Worker thread not available"));
|
|
174
|
+
}
|
|
175
|
+
return new Promise((resolve, reject) => {
|
|
176
|
+
const timer = setTimeout(() => {
|
|
177
|
+
this.pendingRequests.delete(message.requestId);
|
|
178
|
+
reject(new Error(`Worker thread response timeout (${WORKER_RESPONSE_TIMEOUT_MS}ms) for ${message.type}`));
|
|
179
|
+
}, WORKER_RESPONSE_TIMEOUT_MS);
|
|
180
|
+
this.pendingRequests.set(message.requestId, { resolve, reject, timer });
|
|
181
|
+
this.worker.postMessage(message);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Route a response from the worker to the pending request's promise.
|
|
186
|
+
*/
|
|
187
|
+
handleWorkerResponse(response) {
|
|
188
|
+
const pending = this.pendingRequests.get(response.requestId);
|
|
189
|
+
if (!pending)
|
|
190
|
+
return;
|
|
191
|
+
clearTimeout(pending.timer);
|
|
192
|
+
this.pendingRequests.delete(response.requestId);
|
|
193
|
+
pending.resolve(response);
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Handle worker thread crash: reject all pending requests, track restart count.
|
|
197
|
+
*/
|
|
198
|
+
handleWorkerCrash(error) {
|
|
199
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
200
|
+
clearTimeout(pending.timer);
|
|
201
|
+
pending.reject(new Error(`Worker thread crashed: ${error.message}`));
|
|
202
|
+
this.pendingRequests.delete(id);
|
|
203
|
+
}
|
|
204
|
+
this.workerReady = false;
|
|
205
|
+
this.worker = null;
|
|
206
|
+
this.workerInitPromise = null;
|
|
207
|
+
this._isInitialized = false;
|
|
208
|
+
this.workerRestartCount++;
|
|
209
|
+
this.lastCrashTime = Date.now();
|
|
210
|
+
}
|
|
211
|
+
canRestartWorker() {
|
|
212
|
+
return this.workerRestartCount < MAX_WORKER_RESTARTS;
|
|
213
|
+
}
|
|
214
|
+
// =====================================================
|
|
215
|
+
// In-process fallback (for testing / debugging)
|
|
216
|
+
// =====================================================
|
|
217
|
+
async initializeInProcess() {
|
|
218
|
+
const ortModule = await import("onnxruntime-node");
|
|
219
|
+
this.inProcessSession = await ortModule.InferenceSession.create(this.modelPath, {
|
|
220
|
+
executionProviders: ["cpu"],
|
|
221
|
+
});
|
|
222
|
+
// eslint-disable-next-line no-console
|
|
223
|
+
console.log("[DINOv2] Session initialized in-process:", this.modelPath);
|
|
224
|
+
}
|
|
225
|
+
async generateInProcess(imageBuffer) {
|
|
226
|
+
const ortModule = await import("onnxruntime-node");
|
|
227
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
228
|
+
const sess = this.inProcessSession;
|
|
229
|
+
if (!sess)
|
|
230
|
+
throw new Error("DINOv2 in-process session not initialized");
|
|
231
|
+
const width = DINOV2_INPUT_SIZE;
|
|
232
|
+
const height = DINOV2_INPUT_SIZE;
|
|
233
|
+
const expectedSize = width * height * 3;
|
|
234
|
+
if (imageBuffer.length !== expectedSize) {
|
|
235
|
+
throw new Error(`Invalid buffer size: expected ${expectedSize}, got ${imageBuffer.length}`);
|
|
236
|
+
}
|
|
237
|
+
// Preprocess: HWC uint8 -> CHW float32 with ImageNet normalization
|
|
238
|
+
const MEAN = [0.485, 0.456, 0.406];
|
|
239
|
+
const STD = [0.229, 0.224, 0.225];
|
|
240
|
+
const float32 = new Float32Array(3 * width * height);
|
|
241
|
+
for (let c = 0; c < 3; c++) {
|
|
242
|
+
for (let h = 0; h < height; h++) {
|
|
243
|
+
for (let w = 0; w < width; w++) {
|
|
244
|
+
const srcIdx = (h * width + w) * 3 + c;
|
|
245
|
+
const dstIdx = c * height * width + h * width + w;
|
|
246
|
+
float32[dstIdx] = (imageBuffer[srcIdx] / 255.0 - MEAN[c]) / STD[c];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
const inputTensor = new ortModule.Tensor("float32", float32, [1, 3, height, width]);
|
|
251
|
+
const output = await sess.run({ pixel_values: inputTensor });
|
|
252
|
+
const lastHiddenState = output.last_hidden_state;
|
|
253
|
+
if (!lastHiddenState) {
|
|
254
|
+
throw new Error("Model output missing last_hidden_state");
|
|
255
|
+
}
|
|
256
|
+
const data = lastHiddenState.data;
|
|
257
|
+
// Extract CLS token (first token)
|
|
258
|
+
const clsToken = new Float32Array(DINOV2_EMBEDDING_DIMENSION);
|
|
259
|
+
for (let i = 0; i < DINOV2_EMBEDDING_DIMENSION; i++) {
|
|
260
|
+
clsToken[i] = data[i];
|
|
261
|
+
}
|
|
262
|
+
// L2 normalize
|
|
263
|
+
let norm = 0;
|
|
264
|
+
for (let i = 0; i < clsToken.length; i++) {
|
|
265
|
+
const v = clsToken[i];
|
|
266
|
+
if (!Number.isFinite(v)) {
|
|
267
|
+
throw new Error(`NaN/Infinity detected at index ${i}`);
|
|
268
|
+
}
|
|
269
|
+
norm += v * v;
|
|
270
|
+
}
|
|
271
|
+
norm = Math.sqrt(norm);
|
|
272
|
+
if (norm === 0) {
|
|
273
|
+
throw new Error("Zero vector: L2 norm is 0");
|
|
274
|
+
}
|
|
275
|
+
const normalized = new Float32Array(DINOV2_EMBEDDING_DIMENSION);
|
|
276
|
+
for (let i = 0; i < DINOV2_EMBEDDING_DIMENSION; i++) {
|
|
277
|
+
normalized[i] = clsToken[i] / norm;
|
|
278
|
+
}
|
|
279
|
+
return Array.from(normalized);
|
|
280
|
+
}
|
|
281
|
+
// =====================================================
|
|
282
|
+
// Public API
|
|
283
|
+
// =====================================================
|
|
284
|
+
/**
|
|
285
|
+
* Generate a visual embedding for a single image.
|
|
286
|
+
*
|
|
287
|
+
* The imageBuffer must contain raw 224x224x3 RGB pixel data (150,528 bytes).
|
|
288
|
+
* The caller is responsible for resizing/cropping to 224x224 via Sharp.
|
|
289
|
+
*
|
|
290
|
+
* @param imageBuffer - Raw 224x224x3 RGB pixel buffer
|
|
291
|
+
* @returns 768-dimensional L2-normalized embedding vector
|
|
292
|
+
*/
|
|
293
|
+
async generateEmbedding(imageBuffer) {
|
|
294
|
+
if (!this._isInitialized) {
|
|
295
|
+
await this.initialize();
|
|
296
|
+
}
|
|
297
|
+
const expectedSize = DINOV2_INPUT_SIZE * DINOV2_INPUT_SIZE * 3;
|
|
298
|
+
if (imageBuffer.length !== expectedSize) {
|
|
299
|
+
throw new Error(`Invalid image buffer size: expected ${expectedSize} (224x224x3 RGB), got ${imageBuffer.length}`);
|
|
300
|
+
}
|
|
301
|
+
if (this.useWorkerThread) {
|
|
302
|
+
return this.generateViaWorker(imageBuffer);
|
|
303
|
+
}
|
|
304
|
+
return this.generateInProcess(imageBuffer);
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Generate embeddings for multiple images sequentially.
|
|
308
|
+
*
|
|
309
|
+
* DINOv2 processes one image at a time (no native batching for ViT),
|
|
310
|
+
* so this runs inference sequentially through the single Worker Thread.
|
|
311
|
+
*
|
|
312
|
+
* @param imageBuffers - Array of raw 224x224x3 RGB pixel buffers
|
|
313
|
+
* @returns Array of 768-dimensional L2-normalized embedding vectors
|
|
314
|
+
*/
|
|
315
|
+
async generateBatchEmbeddings(imageBuffers) {
|
|
316
|
+
const results = [];
|
|
317
|
+
for (const buffer of imageBuffers) {
|
|
318
|
+
const embedding = await this.generateEmbedding(buffer);
|
|
319
|
+
results.push(embedding);
|
|
320
|
+
}
|
|
321
|
+
return results;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Generate embedding via Worker Thread with crash recovery.
|
|
325
|
+
*/
|
|
326
|
+
async generateViaWorker(imageBuffer) {
|
|
327
|
+
if (!this.workerReady || !this.worker) {
|
|
328
|
+
if (!this.canRestartWorker() && this.workerRestartCount > 0) {
|
|
329
|
+
throw new Error(`Worker thread exceeded max restarts (${MAX_WORKER_RESTARTS})`);
|
|
330
|
+
}
|
|
331
|
+
await this.ensureWorkerReady();
|
|
332
|
+
}
|
|
333
|
+
// Copy to a fresh ArrayBuffer for structured clone transfer
|
|
334
|
+
const arrayBuffer = new ArrayBuffer(imageBuffer.byteLength);
|
|
335
|
+
new Uint8Array(arrayBuffer).set(new Uint8Array(imageBuffer.buffer, imageBuffer.byteOffset, imageBuffer.byteLength));
|
|
336
|
+
const response = await this.sendWorkerMessage({
|
|
337
|
+
type: "infer",
|
|
338
|
+
requestId: generateRequestId(),
|
|
339
|
+
imageBuffer: arrayBuffer,
|
|
340
|
+
width: DINOV2_INPUT_SIZE,
|
|
341
|
+
height: DINOV2_INPUT_SIZE,
|
|
342
|
+
});
|
|
343
|
+
if (response.type === "error") {
|
|
344
|
+
throw new Error(`DINOv2 inference failed: ${response.error}`);
|
|
345
|
+
}
|
|
346
|
+
if (response.type !== "infer") {
|
|
347
|
+
throw new Error(`Unexpected worker response type: ${response.type}`);
|
|
348
|
+
}
|
|
349
|
+
return response.embedding;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Dispose the ONNX session to free native memory.
|
|
353
|
+
* After disposal, the next generateEmbedding() call will re-initialize.
|
|
354
|
+
*/
|
|
355
|
+
async dispose() {
|
|
356
|
+
if (this.useWorkerThread) {
|
|
357
|
+
if (this.worker && this.workerReady) {
|
|
358
|
+
try {
|
|
359
|
+
await this.sendWorkerMessage({
|
|
360
|
+
type: "dispose",
|
|
361
|
+
requestId: generateRequestId(),
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
catch {
|
|
365
|
+
// Disposal failure should not break the workflow
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
if (this.inProcessSession) {
|
|
371
|
+
try {
|
|
372
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
373
|
+
await this.inProcessSession.release();
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// Disposal failure should not break the workflow
|
|
377
|
+
}
|
|
378
|
+
this.inProcessSession = null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
this._isInitialized = false;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Terminate the worker thread completely and clean up.
|
|
385
|
+
* After this, the service cannot be used until a new instance is created.
|
|
386
|
+
*/
|
|
387
|
+
async terminate() {
|
|
388
|
+
if (this.worker) {
|
|
389
|
+
try {
|
|
390
|
+
await this.sendWorkerMessage({
|
|
391
|
+
type: "dispose",
|
|
392
|
+
requestId: generateRequestId(),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
catch {
|
|
396
|
+
// May fail if worker already exited
|
|
397
|
+
}
|
|
398
|
+
try {
|
|
399
|
+
await this.worker.terminate();
|
|
400
|
+
}
|
|
401
|
+
catch {
|
|
402
|
+
// Already terminated
|
|
403
|
+
}
|
|
404
|
+
this.worker = null;
|
|
405
|
+
this.workerReady = false;
|
|
406
|
+
this.workerInitPromise = null;
|
|
407
|
+
}
|
|
408
|
+
// Also dispose in-process session if present
|
|
409
|
+
if (this.inProcessSession) {
|
|
410
|
+
try {
|
|
411
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
412
|
+
await this.inProcessSession.release();
|
|
413
|
+
}
|
|
414
|
+
catch {
|
|
415
|
+
// Disposal failure should not break the workflow
|
|
416
|
+
}
|
|
417
|
+
this.inProcessSession = null;
|
|
418
|
+
}
|
|
419
|
+
this._isInitialized = false;
|
|
420
|
+
// Reject any remaining pending requests
|
|
421
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
422
|
+
clearTimeout(pending.timer);
|
|
423
|
+
pending.reject(new Error("Service terminated"));
|
|
424
|
+
this.pendingRequests.delete(id);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Whether the service is initialized and ready for inference.
|
|
429
|
+
*/
|
|
430
|
+
get initialized() {
|
|
431
|
+
return this._isInitialized;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Whether this service is using a Worker Thread for inference.
|
|
435
|
+
*/
|
|
436
|
+
isUsingWorkerThread() {
|
|
437
|
+
return this.useWorkerThread;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Get the number of worker thread restarts that have occurred.
|
|
441
|
+
*/
|
|
442
|
+
getWorkerRestartCount() {
|
|
443
|
+
return this.workerRestartCount;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/dinov2/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker Thread message types for DINOv2 ONNX inference.
|
|
3
|
+
*
|
|
4
|
+
* Communication protocol between main thread (DINOv2Service) and
|
|
5
|
+
* worker thread (worker-thread.ts). Messages are serialized via
|
|
6
|
+
* structured clone (MessagePort), so only plain objects and typed arrays
|
|
7
|
+
* are used -- no ONNX Session/Tensor objects cross the boundary.
|
|
8
|
+
*
|
|
9
|
+
* @module dinov2/worker-thread-types
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Initialize the ONNX InferenceSession in the worker thread.
|
|
13
|
+
*/
|
|
14
|
+
export interface DINOv2WorkerInitMessage {
|
|
15
|
+
type: "init";
|
|
16
|
+
requestId: string;
|
|
17
|
+
modelPath: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Run DINOv2 inference on a preprocessed image buffer.
|
|
21
|
+
* The main thread sends raw 224x224x3 RGB pixel data.
|
|
22
|
+
*/
|
|
23
|
+
export interface DINOv2WorkerInferMessage {
|
|
24
|
+
type: "infer";
|
|
25
|
+
requestId: string;
|
|
26
|
+
imageBuffer: ArrayBuffer;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Dispose the ONNX session to free native memory.
|
|
32
|
+
*/
|
|
33
|
+
export interface DINOv2WorkerDisposeMessage {
|
|
34
|
+
type: "dispose";
|
|
35
|
+
requestId: string;
|
|
36
|
+
}
|
|
37
|
+
export type DINOv2WorkerMessage = DINOv2WorkerInitMessage | DINOv2WorkerInferMessage | DINOv2WorkerDisposeMessage;
|
|
38
|
+
/**
|
|
39
|
+
* Successful response from init.
|
|
40
|
+
*/
|
|
41
|
+
export interface DINOv2WorkerInitResponse {
|
|
42
|
+
type: "init";
|
|
43
|
+
requestId: string;
|
|
44
|
+
success: true;
|
|
45
|
+
loadTimeMs: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Successful response from infer.
|
|
49
|
+
* Embedding is a plain number[] (structured clone compatible).
|
|
50
|
+
*/
|
|
51
|
+
export interface DINOv2WorkerInferResponse {
|
|
52
|
+
type: "infer";
|
|
53
|
+
requestId: string;
|
|
54
|
+
success: true;
|
|
55
|
+
embedding: number[];
|
|
56
|
+
inferenceTimeMs: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Successful response from dispose.
|
|
60
|
+
*/
|
|
61
|
+
export interface DINOv2WorkerDisposeResponse {
|
|
62
|
+
type: "dispose";
|
|
63
|
+
requestId: string;
|
|
64
|
+
success: true;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Error response for any message type.
|
|
68
|
+
*/
|
|
69
|
+
export interface DINOv2WorkerErrorResponse {
|
|
70
|
+
type: "error";
|
|
71
|
+
requestId: string;
|
|
72
|
+
success: false;
|
|
73
|
+
error: string;
|
|
74
|
+
originalType: DINOv2WorkerMessage["type"];
|
|
75
|
+
}
|
|
76
|
+
export type DINOv2WorkerResponse = DINOv2WorkerInitResponse | DINOv2WorkerInferResponse | DINOv2WorkerDisposeResponse | DINOv2WorkerErrorResponse;
|
|
77
|
+
//# sourceMappingURL=worker-thread-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-thread-types.d.ts","sourceRoot":"","sources":["../../src/dinov2/worker-thread-types.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AAMH;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,mBAAmB,GAC3B,uBAAuB,GACvB,wBAAwB,GACxB,0BAA0B,CAAC;AAM/B;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,IAAI,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,SAAS,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,IAAI,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;CAC3C;AAED,MAAM,MAAM,oBAAoB,GAC5B,wBAAwB,GACxB,yBAAyB,GACzB,2BAA2B,GAC3B,yBAAyB,CAAC"}
|