@elizaos/plugin-vision 1.2.1

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.
Files changed (106) hide show
  1. package/.npmignore +5 -0
  2. package/README.md +270 -0
  3. package/build.config.ts +70 -0
  4. package/dist/action.d.ts +8 -0
  5. package/dist/action.js +1212 -0
  6. package/dist/action.js.map +1 -0
  7. package/dist/audio-capture-stream.d.ts +42 -0
  8. package/dist/audio-capture-stream.js +516 -0
  9. package/dist/audio-capture-stream.js.map +1 -0
  10. package/dist/audio-capture.d.ts +25 -0
  11. package/dist/audio-capture.js +412 -0
  12. package/dist/audio-capture.js.map +1 -0
  13. package/dist/basic.test.d.ts +1 -0
  14. package/dist/basic.test.js +97 -0
  15. package/dist/basic.test.js.map +1 -0
  16. package/dist/config.d.ts +73 -0
  17. package/dist/config.js +254 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/entity-tracker.d.ts +32 -0
  20. package/dist/entity-tracker.js +361 -0
  21. package/dist/entity-tracker.js.map +1 -0
  22. package/dist/errors.d.ts +67 -0
  23. package/dist/errors.js +395 -0
  24. package/dist/errors.js.map +1 -0
  25. package/dist/face-recognition.d.ts +31 -0
  26. package/dist/face-recognition.js +332 -0
  27. package/dist/face-recognition.js.map +1 -0
  28. package/dist/florence2-local.d.ts +25 -0
  29. package/dist/florence2-local.js +280 -0
  30. package/dist/florence2-local.js.map +1 -0
  31. package/dist/florence2-model.d.ts +36 -0
  32. package/dist/florence2-model.js +503 -0
  33. package/dist/florence2-model.js.map +1 -0
  34. package/dist/index.d.ts +3 -0
  35. package/dist/index.js +73 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/ocr-service-real.d.ts +32 -0
  38. package/dist/ocr-service-real.js +396 -0
  39. package/dist/ocr-service-real.js.map +1 -0
  40. package/dist/ocr-service.d.ts +28 -0
  41. package/dist/ocr-service.js +216 -0
  42. package/dist/ocr-service.js.map +1 -0
  43. package/dist/provider.d.ts +2 -0
  44. package/dist/provider.js +285 -0
  45. package/dist/provider.js.map +1 -0
  46. package/dist/screen-capture.d.ts +16 -0
  47. package/dist/screen-capture.js +302 -0
  48. package/dist/screen-capture.js.map +1 -0
  49. package/dist/service.d.ts +73 -0
  50. package/dist/service.js +1662 -0
  51. package/dist/service.js.map +1 -0
  52. package/dist/tests/e2e/index.d.ts +8 -0
  53. package/dist/tests/e2e/index.js +33 -0
  54. package/dist/tests/e2e/index.js.map +1 -0
  55. package/dist/tests/e2e/run-local.d.ts +2 -0
  56. package/dist/tests/e2e/run-local.js +166 -0
  57. package/dist/tests/e2e/run-local.js.map +1 -0
  58. package/dist/tests/e2e/screen-vision.d.ts +11 -0
  59. package/dist/tests/e2e/screen-vision.js +384 -0
  60. package/dist/tests/e2e/screen-vision.js.map +1 -0
  61. package/dist/tests/e2e/vision-autonomy.d.ts +11 -0
  62. package/dist/tests/e2e/vision-autonomy.js +375 -0
  63. package/dist/tests/e2e/vision-autonomy.js.map +1 -0
  64. package/dist/tests/e2e/vision-basic.d.ts +11 -0
  65. package/dist/tests/e2e/vision-basic.js +434 -0
  66. package/dist/tests/e2e/vision-basic.js.map +1 -0
  67. package/dist/tests/e2e/vision-capture-log.d.ts +11 -0
  68. package/dist/tests/e2e/vision-capture-log.js +302 -0
  69. package/dist/tests/e2e/vision-capture-log.js.map +1 -0
  70. package/dist/tests/e2e/vision-runtime.d.ts +11 -0
  71. package/dist/tests/e2e/vision-runtime.js +357 -0
  72. package/dist/tests/e2e/vision-runtime.js.map +1 -0
  73. package/dist/tests/e2e/vision-worker-tests.d.ts +11 -0
  74. package/dist/tests/e2e/vision-worker-tests.js +466 -0
  75. package/dist/tests/e2e/vision-worker-tests.js.map +1 -0
  76. package/dist/tests/test-pattern-generator.d.ts +40 -0
  77. package/dist/tests/test-pattern-generator.js +191 -0
  78. package/dist/tests/test-pattern-generator.js.map +1 -0
  79. package/dist/tests.d.ts +3 -0
  80. package/dist/tests.js +11 -0
  81. package/dist/tests.js.map +1 -0
  82. package/dist/types.d.ts +222 -0
  83. package/dist/types.js +16 -0
  84. package/dist/types.js.map +1 -0
  85. package/dist/vision-models.d.ts +47 -0
  86. package/dist/vision-models.js +501 -0
  87. package/dist/vision-models.js.map +1 -0
  88. package/dist/vision-worker-manager.d.ts +61 -0
  89. package/dist/vision-worker-manager.js +668 -0
  90. package/dist/vision-worker-manager.js.map +1 -0
  91. package/dist/workers/florence2-worker-simple.d.ts +13 -0
  92. package/dist/workers/florence2-worker-simple.js +121 -0
  93. package/dist/workers/florence2-worker-simple.js.map +1 -0
  94. package/dist/workers/florence2-worker.d.ts +1 -0
  95. package/dist/workers/florence2-worker.js +328 -0
  96. package/dist/workers/florence2-worker.js.map +1 -0
  97. package/dist/workers/ocr-worker.d.ts +1 -0
  98. package/dist/workers/ocr-worker.js +354 -0
  99. package/dist/workers/ocr-worker.js.map +1 -0
  100. package/dist/workers/screen-capture-worker.d.ts +1 -0
  101. package/dist/workers/screen-capture-worker.js +427 -0
  102. package/dist/workers/screen-capture-worker.js.map +1 -0
  103. package/dist/workers/worker-logger.d.ts +9 -0
  104. package/dist/workers/worker-logger.js +95 -0
  105. package/dist/workers/worker-logger.js.map +1 -0
  106. package/package.json +100 -0
@@ -0,0 +1,332 @@
1
+ "use strict";
2
+ var __assign = (this && this.__assign) || function () {
3
+ __assign = Object.assign || function(t) {
4
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
5
+ s = arguments[i];
6
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
+ t[p] = s[p];
8
+ }
9
+ return t;
10
+ };
11
+ return __assign.apply(this, arguments);
12
+ };
13
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
+ return new (P || (P = Promise))(function (resolve, reject) {
16
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
20
+ });
21
+ };
22
+ var __generator = (this && this.__generator) || function (thisArg, body) {
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
+ function verb(n) { return function (v) { return step([n, v]); }; }
26
+ function step(op) {
27
+ if (f) throw new TypeError("Generator is already executing.");
28
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
29
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
+ if (y = 0, t) op = [op[0] & 2, t.value];
31
+ switch (op[0]) {
32
+ case 0: case 1: t = op; break;
33
+ case 4: _.label++; return { value: op[1], done: false };
34
+ case 5: _.label++; y = op[1]; op = [0]; continue;
35
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
+ default:
37
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
+ if (t[2]) _.ops.pop();
42
+ _.trys.pop(); continue;
43
+ }
44
+ op = body.call(thisArg, _);
45
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
+ }
48
+ };
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.FaceRecognition = void 0;
51
+ var faceapi = require("face-api.js");
52
+ var core_1 = require("@elizaos/core");
53
+ var path = require("path");
54
+ var url_1 = require("url");
55
+ var __filename = (0, url_1.fileURLToPath)(import.meta.url);
56
+ var __dirname = path.dirname(__filename);
57
+ // Dynamic imports for optional dependencies
58
+ var Canvas, Image, ImageData;
59
+ function initializeCanvas() {
60
+ return __awaiter(this, void 0, void 0, function () {
61
+ var canvas, error_1;
62
+ return __generator(this, function (_a) {
63
+ switch (_a.label) {
64
+ case 0:
65
+ _a.trys.push([0, 2, , 3]);
66
+ return [4 /*yield*/, Promise.resolve().then(function () { return require('canvas'); })];
67
+ case 1:
68
+ canvas = _a.sent();
69
+ Canvas = canvas.Canvas;
70
+ Image = canvas.Image;
71
+ ImageData = canvas.ImageData;
72
+ // Polyfill for face-api.js
73
+ faceapi.env.monkeyPatch({ Canvas: Canvas, Image: Image, ImageData: ImageData });
74
+ return [3 /*break*/, 3];
75
+ case 2:
76
+ error_1 = _a.sent();
77
+ core_1.logger.error('[FaceRecognition] Canvas module not available:', error_1);
78
+ throw new Error('Canvas module is required for face recognition. Install with: npm install canvas');
79
+ case 3: return [2 /*return*/];
80
+ }
81
+ });
82
+ });
83
+ }
84
+ var FaceRecognition = /** @class */ (function () {
85
+ function FaceRecognition() {
86
+ this.initialized = false;
87
+ this.faceLibrary = {
88
+ faces: new Map(),
89
+ embeddings: new Map(),
90
+ };
91
+ this.modelPath = path.join(__dirname, '..', 'models', 'face-api');
92
+ // Thresholds
93
+ this.FACE_MATCH_THRESHOLD = 0.6; // Euclidean distance threshold
94
+ this.MIN_FACE_SIZE = 50; // Minimum face size in pixels
95
+ }
96
+ FaceRecognition.prototype.initialize = function () {
97
+ return __awaiter(this, void 0, void 0, function () {
98
+ var error_2;
99
+ return __generator(this, function (_a) {
100
+ switch (_a.label) {
101
+ case 0:
102
+ if (this.initialized) {
103
+ return [2 /*return*/];
104
+ }
105
+ _a.label = 1;
106
+ case 1:
107
+ _a.trys.push([1, 8, , 9]);
108
+ core_1.logger.info('[FaceRecognition] Loading face detection models...');
109
+ // Initialize canvas first
110
+ return [4 /*yield*/, initializeCanvas()];
111
+ case 2:
112
+ // Initialize canvas first
113
+ _a.sent();
114
+ // Load face-api.js models
115
+ return [4 /*yield*/, faceapi.nets.ssdMobilenetv1.loadFromDisk(this.modelPath)];
116
+ case 3:
117
+ // Load face-api.js models
118
+ _a.sent();
119
+ return [4 /*yield*/, faceapi.nets.faceLandmark68Net.loadFromDisk(this.modelPath)];
120
+ case 4:
121
+ _a.sent();
122
+ return [4 /*yield*/, faceapi.nets.faceRecognitionNet.loadFromDisk(this.modelPath)];
123
+ case 5:
124
+ _a.sent();
125
+ return [4 /*yield*/, faceapi.nets.faceExpressionNet.loadFromDisk(this.modelPath)];
126
+ case 6:
127
+ _a.sent();
128
+ return [4 /*yield*/, faceapi.nets.ageGenderNet.loadFromDisk(this.modelPath)];
129
+ case 7:
130
+ _a.sent();
131
+ this.initialized = true;
132
+ core_1.logger.info('[FaceRecognition] Models loaded successfully');
133
+ return [3 /*break*/, 9];
134
+ case 8:
135
+ error_2 = _a.sent();
136
+ core_1.logger.error('[FaceRecognition] Failed to load models:', error_2);
137
+ core_1.logger.info('[FaceRecognition] Download models from: https://github.com/justadudewhohacks/face-api.js-models');
138
+ throw error_2;
139
+ case 9: return [2 /*return*/];
140
+ }
141
+ });
142
+ });
143
+ };
144
+ FaceRecognition.prototype.detectFaces = function (imageData, width, height) {
145
+ return __awaiter(this, void 0, void 0, function () {
146
+ var expectedSize, canvas, ctx, imageDataObj, detections, error_3;
147
+ var _this = this;
148
+ return __generator(this, function (_a) {
149
+ switch (_a.label) {
150
+ case 0:
151
+ if (!!this.initialized) return [3 /*break*/, 2];
152
+ return [4 /*yield*/, this.initialize()];
153
+ case 1:
154
+ _a.sent();
155
+ _a.label = 2;
156
+ case 2:
157
+ // Validate input parameters
158
+ if (!imageData || imageData.length === 0 || width <= 0 || height <= 0) {
159
+ core_1.logger.warn('[FaceRecognition] Invalid input parameters:', {
160
+ dataLength: (imageData === null || imageData === void 0 ? void 0 : imageData.length) || 0,
161
+ width: width,
162
+ height: height,
163
+ });
164
+ return [2 /*return*/, []];
165
+ }
166
+ expectedSize = width * height * 4;
167
+ if (imageData.length !== expectedSize) {
168
+ core_1.logger.warn('[FaceRecognition] Buffer size mismatch:', {
169
+ expected: expectedSize,
170
+ actual: imageData.length,
171
+ width: width,
172
+ height: height,
173
+ });
174
+ return [2 /*return*/, []];
175
+ }
176
+ _a.label = 3;
177
+ case 3:
178
+ _a.trys.push([3, 5, , 6]);
179
+ canvas = new Canvas(width, height);
180
+ ctx = canvas.getContext('2d');
181
+ imageDataObj = new ImageData(new Uint8ClampedArray(imageData), width, height);
182
+ ctx.putImageData(imageDataObj, 0, 0);
183
+ return [4 /*yield*/, faceapi
184
+ .detectAllFaces(canvas, new faceapi.SsdMobilenetv1Options({
185
+ minConfidence: 0.5,
186
+ maxResults: 10,
187
+ }))
188
+ .withFaceLandmarks()
189
+ .withFaceDescriptors()
190
+ .withFaceExpressions()
191
+ .withAgeAndGender()];
192
+ case 4:
193
+ detections = _a.sent();
194
+ return [2 /*return*/, detections.filter(function (d) {
195
+ var box = d.detection.box;
196
+ return box.width >= _this.MIN_FACE_SIZE && box.height >= _this.MIN_FACE_SIZE;
197
+ })];
198
+ case 5:
199
+ error_3 = _a.sent();
200
+ core_1.logger.error('[FaceRecognition] Face detection failed:', error_3);
201
+ return [2 /*return*/, []];
202
+ case 6: return [2 /*return*/];
203
+ }
204
+ });
205
+ });
206
+ };
207
+ FaceRecognition.prototype.recognizeFace = function (descriptor) {
208
+ return __awaiter(this, void 0, void 0, function () {
209
+ var bestMatch, minDistance, _i, _a, _b, profileId, embeddings, _c, embeddings_1, knownEmbedding, distance;
210
+ return __generator(this, function (_d) {
211
+ bestMatch = null;
212
+ minDistance = Infinity;
213
+ // Compare with all known faces
214
+ for (_i = 0, _a = this.faceLibrary.embeddings; _i < _a.length; _i++) {
215
+ _b = _a[_i], profileId = _b[0], embeddings = _b[1];
216
+ for (_c = 0, embeddings_1 = embeddings; _c < embeddings_1.length; _c++) {
217
+ knownEmbedding = embeddings_1[_c];
218
+ distance = this.euclideanDistance(descriptor, knownEmbedding);
219
+ if (distance < this.FACE_MATCH_THRESHOLD && distance < minDistance) {
220
+ minDistance = distance;
221
+ bestMatch = { profileId: profileId, distance: distance };
222
+ }
223
+ }
224
+ }
225
+ return [2 /*return*/, bestMatch];
226
+ });
227
+ });
228
+ };
229
+ FaceRecognition.prototype.addOrUpdateFace = function (descriptor, attributes) {
230
+ return __awaiter(this, void 0, void 0, function () {
231
+ var match, profile, embeddings, profileId, profile;
232
+ return __generator(this, function (_a) {
233
+ switch (_a.label) {
234
+ case 0: return [4 /*yield*/, this.recognizeFace(descriptor)];
235
+ case 1:
236
+ match = _a.sent();
237
+ if (match) {
238
+ profile = this.faceLibrary.faces.get(match.profileId);
239
+ profile.lastSeen = Date.now();
240
+ profile.seenCount++;
241
+ embeddings = this.faceLibrary.embeddings.get(match.profileId);
242
+ if (embeddings.length < 10) {
243
+ // Keep up to 10 embeddings per person
244
+ embeddings.push(Array.from(descriptor));
245
+ }
246
+ // Update attributes if provided
247
+ if (attributes) {
248
+ Object.assign(profile, attributes);
249
+ }
250
+ return [2 /*return*/, match.profileId];
251
+ }
252
+ else {
253
+ profileId = "face-".concat(Date.now(), "-").concat(Math.random().toString(36).substr(2, 9));
254
+ profile = __assign({ id: profileId, embeddings: [Array.from(descriptor)], firstSeen: Date.now(), lastSeen: Date.now(), seenCount: 1 }, attributes);
255
+ this.faceLibrary.faces.set(profileId, profile);
256
+ this.faceLibrary.embeddings.set(profileId, [Array.from(descriptor)]);
257
+ core_1.logger.info("[FaceRecognition] New face registered: ".concat(profileId));
258
+ return [2 /*return*/, profileId];
259
+ }
260
+ return [2 /*return*/];
261
+ }
262
+ });
263
+ });
264
+ };
265
+ FaceRecognition.prototype.getFaceProfile = function (profileId) {
266
+ return this.faceLibrary.faces.get(profileId);
267
+ };
268
+ FaceRecognition.prototype.getAllProfiles = function () {
269
+ return Array.from(this.faceLibrary.faces.values());
270
+ };
271
+ FaceRecognition.prototype.euclideanDistance = function (a, b) {
272
+ var sum = 0;
273
+ var aArray = Array.from(a);
274
+ for (var i = 0; i < aArray.length; i++) {
275
+ sum += Math.pow(aArray[i] - b[i], 2);
276
+ }
277
+ return Math.sqrt(sum);
278
+ };
279
+ // Persistence methods
280
+ FaceRecognition.prototype.saveFaceLibrary = function (path) {
281
+ return __awaiter(this, void 0, void 0, function () {
282
+ var data, fs;
283
+ return __generator(this, function (_a) {
284
+ switch (_a.label) {
285
+ case 0:
286
+ data = {
287
+ faces: Array.from(this.faceLibrary.faces.entries()),
288
+ embeddings: Array.from(this.faceLibrary.embeddings.entries()),
289
+ };
290
+ return [4 /*yield*/, Promise.resolve().then(function () { return require('fs/promises'); })];
291
+ case 1:
292
+ fs = _a.sent();
293
+ return [4 /*yield*/, fs.writeFile(path, JSON.stringify(data, null, 2))];
294
+ case 2:
295
+ _a.sent();
296
+ core_1.logger.info("[FaceRecognition] Face library saved to ".concat(path));
297
+ return [2 /*return*/];
298
+ }
299
+ });
300
+ });
301
+ };
302
+ FaceRecognition.prototype.loadFaceLibrary = function (path) {
303
+ return __awaiter(this, void 0, void 0, function () {
304
+ var fs, data, _a, _b, error_4;
305
+ return __generator(this, function (_c) {
306
+ switch (_c.label) {
307
+ case 0:
308
+ _c.trys.push([0, 3, , 4]);
309
+ return [4 /*yield*/, Promise.resolve().then(function () { return require('fs/promises'); })];
310
+ case 1:
311
+ fs = _c.sent();
312
+ _b = (_a = JSON).parse;
313
+ return [4 /*yield*/, fs.readFile(path, 'utf-8')];
314
+ case 2:
315
+ data = _b.apply(_a, [_c.sent()]);
316
+ this.faceLibrary.faces = new Map(data.faces);
317
+ this.faceLibrary.embeddings = new Map(data.embeddings);
318
+ core_1.logger.info("[FaceRecognition] Loaded ".concat(this.faceLibrary.faces.size, " face profiles"));
319
+ return [3 /*break*/, 4];
320
+ case 3:
321
+ error_4 = _c.sent();
322
+ core_1.logger.warn('[FaceRecognition] Could not load face library:', error_4);
323
+ return [3 /*break*/, 4];
324
+ case 4: return [2 /*return*/];
325
+ }
326
+ });
327
+ });
328
+ };
329
+ return FaceRecognition;
330
+ }());
331
+ exports.FaceRecognition = FaceRecognition;
332
+ //# sourceMappingURL=face-recognition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"face-recognition.js","sourceRoot":"","sources":["../src/face-recognition.ts"],"names":[],"mappings":"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","sourcesContent":["import * as faceapi from 'face-api.js';\nimport { logger } from '@elizaos/core';\nimport * as path from 'path';\nimport { fileURLToPath } from 'url';\nimport type { FaceProfile, FaceLibrary } from './types';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// Dynamic imports for optional dependencies\nlet Canvas: any, Image: any, ImageData: any;\n\nasync function initializeCanvas() {\n try {\n const canvas = await import('canvas');\n Canvas = canvas.Canvas;\n Image = canvas.Image;\n ImageData = canvas.ImageData;\n\n // Polyfill for face-api.js\n faceapi.env.monkeyPatch({ Canvas, Image, ImageData });\n } catch (error) {\n logger.error('[FaceRecognition] Canvas module not available:', error);\n throw new Error(\n 'Canvas module is required for face recognition. Install with: npm install canvas'\n );\n }\n}\n\nexport class FaceRecognition {\n private initialized = false;\n private faceLibrary: FaceLibrary = {\n faces: new Map(),\n embeddings: new Map(),\n };\n private modelPath = path.join(__dirname, '..', 'models', 'face-api');\n\n // Thresholds\n private readonly FACE_MATCH_THRESHOLD = 0.6; // Euclidean distance threshold\n private readonly MIN_FACE_SIZE = 50; // Minimum face size in pixels\n\n async initialize(): Promise<void> {\n if (this.initialized) {\n return;\n }\n\n try {\n logger.info('[FaceRecognition] Loading face detection models...');\n\n // Initialize canvas first\n await initializeCanvas();\n\n // Load face-api.js models\n await faceapi.nets.ssdMobilenetv1.loadFromDisk(this.modelPath);\n await faceapi.nets.faceLandmark68Net.loadFromDisk(this.modelPath);\n await faceapi.nets.faceRecognitionNet.loadFromDisk(this.modelPath);\n await faceapi.nets.faceExpressionNet.loadFromDisk(this.modelPath);\n await faceapi.nets.ageGenderNet.loadFromDisk(this.modelPath);\n\n this.initialized = true;\n logger.info('[FaceRecognition] Models loaded successfully');\n } catch (error) {\n logger.error('[FaceRecognition] Failed to load models:', error);\n logger.info(\n '[FaceRecognition] Download models from: https://github.com/justadudewhohacks/face-api.js-models'\n );\n throw error;\n }\n }\n\n async detectFaces(\n imageData: Buffer,\n width: number,\n height: number\n ): Promise<\n Array<{\n detection: faceapi.FaceDetection;\n landmarks: faceapi.FaceLandmarks68;\n descriptor: Float32Array;\n expressions: faceapi.FaceExpressions;\n ageGender?: { age: number; gender: string; genderProbability: number };\n }>\n > {\n if (!this.initialized) {\n await this.initialize();\n }\n\n // Validate input parameters\n if (!imageData || imageData.length === 0 || width <= 0 || height <= 0) {\n logger.warn('[FaceRecognition] Invalid input parameters:', {\n dataLength: imageData?.length || 0,\n width,\n height,\n });\n return [];\n }\n\n // Validate that the buffer size matches expected dimensions\n const expectedSize = width * height * 4; // RGBA\n if (imageData.length !== expectedSize) {\n logger.warn('[FaceRecognition] Buffer size mismatch:', {\n expected: expectedSize,\n actual: imageData.length,\n width,\n height,\n });\n return [];\n }\n\n try {\n // Create canvas from image data\n const canvas = new Canvas(width, height);\n const ctx = canvas.getContext('2d');\n const imageDataObj = new ImageData(new Uint8ClampedArray(imageData), width, height);\n ctx.putImageData(imageDataObj, 0, 0);\n\n // Detect faces with full analysis\n const detections = await faceapi\n .detectAllFaces(\n canvas as any,\n new faceapi.SsdMobilenetv1Options({\n minConfidence: 0.5,\n maxResults: 10,\n })\n )\n .withFaceLandmarks()\n .withFaceDescriptors()\n .withFaceExpressions()\n .withAgeAndGender();\n\n return detections.filter(\n (d: {\n detection: {\n box: {\n width: number;\n height: number;\n };\n };\n }) => {\n const box = d.detection.box;\n return box.width >= this.MIN_FACE_SIZE && box.height >= this.MIN_FACE_SIZE;\n }\n );\n } catch (error) {\n logger.error('[FaceRecognition] Face detection failed:', error);\n return [];\n }\n }\n\n async recognizeFace(\n descriptor: Float32Array\n ): Promise<{ profileId: string; distance: number } | null> {\n let bestMatch: { profileId: string; distance: number } | null = null;\n let minDistance = Infinity;\n\n // Compare with all known faces\n for (const [profileId, embeddings] of this.faceLibrary.embeddings) {\n for (const knownEmbedding of embeddings) {\n const distance = this.euclideanDistance(descriptor, knownEmbedding);\n\n if (distance < this.FACE_MATCH_THRESHOLD && distance < minDistance) {\n minDistance = distance;\n bestMatch = { profileId, distance };\n }\n }\n }\n\n return bestMatch;\n }\n\n async addOrUpdateFace(\n descriptor: Float32Array,\n attributes?: Partial<FaceProfile>\n ): Promise<string> {\n // Check if this face already exists\n const match = await this.recognizeFace(descriptor);\n\n if (match) {\n // Update existing profile\n const profile = this.faceLibrary.faces.get(match.profileId)!;\n profile.lastSeen = Date.now();\n profile.seenCount++;\n\n // Add new embedding for better recognition\n const embeddings = this.faceLibrary.embeddings.get(match.profileId)!;\n if (embeddings.length < 10) {\n // Keep up to 10 embeddings per person\n embeddings.push(Array.from(descriptor));\n }\n\n // Update attributes if provided\n if (attributes) {\n Object.assign(profile, attributes);\n }\n\n return match.profileId;\n } else {\n // Create new profile\n const profileId = `face-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n const profile: FaceProfile = {\n id: profileId,\n embeddings: [Array.from(descriptor)],\n firstSeen: Date.now(),\n lastSeen: Date.now(),\n seenCount: 1,\n ...attributes,\n };\n\n this.faceLibrary.faces.set(profileId, profile);\n this.faceLibrary.embeddings.set(profileId, [Array.from(descriptor)]);\n\n logger.info(`[FaceRecognition] New face registered: ${profileId}`);\n return profileId;\n }\n }\n\n getFaceProfile(profileId: string): FaceProfile | undefined {\n return this.faceLibrary.faces.get(profileId);\n }\n\n getAllProfiles(): FaceProfile[] {\n return Array.from(this.faceLibrary.faces.values());\n }\n\n private euclideanDistance(a: Float32Array | number[], b: number[]): number {\n let sum = 0;\n const aArray = Array.from(a);\n for (let i = 0; i < aArray.length; i++) {\n sum += Math.pow(aArray[i] - b[i], 2);\n }\n return Math.sqrt(sum);\n }\n\n // Persistence methods\n async saveFaceLibrary(path: string): Promise<void> {\n const data = {\n faces: Array.from(this.faceLibrary.faces.entries()),\n embeddings: Array.from(this.faceLibrary.embeddings.entries()),\n };\n\n const fs = await import('fs/promises');\n await fs.writeFile(path, JSON.stringify(data, null, 2));\n logger.info(`[FaceRecognition] Face library saved to ${path}`);\n }\n\n async loadFaceLibrary(path: string): Promise<void> {\n try {\n const fs = await import('fs/promises');\n const data = JSON.parse(await fs.readFile(path, 'utf-8'));\n\n this.faceLibrary.faces = new Map(data.faces);\n this.faceLibrary.embeddings = new Map(data.embeddings);\n\n logger.info(`[FaceRecognition] Loaded ${this.faceLibrary.faces.size} face profiles`);\n } catch (error) {\n logger.warn('[FaceRecognition] Could not load face library:', error);\n }\n }\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import type { Florence2Result } from './types';
2
+ interface Florence2LocalConfig {
3
+ modelPath?: string;
4
+ modelUrl?: string;
5
+ cacheDir?: string;
6
+ }
7
+ export declare class Florence2Local {
8
+ private model;
9
+ private initialized;
10
+ private config;
11
+ private readonly IMAGE_SIZE;
12
+ private readonly VOCAB_SIZE;
13
+ constructor(config?: Florence2LocalConfig);
14
+ initialize(): Promise<void>;
15
+ analyzeImage(imageBuffer: Buffer): Promise<Florence2Result>;
16
+ private preprocessImage;
17
+ private runInference;
18
+ private parseModelOutput;
19
+ private generateCaptionFromFeatures;
20
+ private extractTagsFromCaption;
21
+ private enhancedFallback;
22
+ isInitialized(): boolean;
23
+ dispose(): Promise<void>;
24
+ }
25
+ export {};