@workglow/tf-mediapipe 0.2.34 → 0.2.36

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 (42) hide show
  1. package/dist/ai/TensorFlowMediaPipeProvider.d.ts +8 -10
  2. package/dist/ai/TensorFlowMediaPipeProvider.d.ts.map +1 -1
  3. package/dist/ai/TensorFlowMediaPipeQueuedProvider.d.ts +6 -3
  4. package/dist/ai/TensorFlowMediaPipeQueuedProvider.d.ts.map +1 -1
  5. package/dist/ai/common/TFMP_Capabilities.d.ts +24 -0
  6. package/dist/ai/common/TFMP_Capabilities.d.ts.map +1 -0
  7. package/dist/ai/common/TFMP_CapabilitySets.d.ts +23 -0
  8. package/dist/ai/common/TFMP_CapabilitySets.d.ts.map +1 -0
  9. package/dist/ai/common/TFMP_Constants.d.ts +1 -1
  10. package/dist/ai/common/TFMP_Constants.d.ts.map +1 -1
  11. package/dist/ai/common/TFMP_Download.d.ts +14 -2
  12. package/dist/ai/common/TFMP_Download.d.ts.map +1 -1
  13. package/dist/ai/common/TFMP_FaceDetector.d.ts.map +1 -1
  14. package/dist/ai/common/TFMP_FaceLandmarker.d.ts.map +1 -1
  15. package/dist/ai/common/TFMP_GestureRecognizer.d.ts.map +1 -1
  16. package/dist/ai/common/TFMP_HandLandmarker.d.ts.map +1 -1
  17. package/dist/ai/common/TFMP_ImageClassification.d.ts.map +1 -1
  18. package/dist/ai/common/TFMP_ImageEmbedding.d.ts.map +1 -1
  19. package/dist/ai/common/TFMP_ImageSegmentation.d.ts.map +1 -1
  20. package/dist/ai/common/TFMP_JobRunFns.d.ts +9 -2
  21. package/dist/ai/common/TFMP_JobRunFns.d.ts.map +1 -1
  22. package/dist/ai/common/TFMP_ModelInfo.d.ts.map +1 -1
  23. package/dist/ai/common/TFMP_ModelSchema.d.ts +3 -3
  24. package/dist/ai/common/TFMP_ObjectDetection.d.ts.map +1 -1
  25. package/dist/ai/common/TFMP_PoseLandmarker.d.ts.map +1 -1
  26. package/dist/ai/common/TFMP_Runtime.d.ts +2 -1
  27. package/dist/ai/common/TFMP_Runtime.d.ts.map +1 -1
  28. package/dist/ai/common/TFMP_TextClassification.d.ts.map +1 -1
  29. package/dist/ai/common/TFMP_TextEmbedding.d.ts.map +1 -1
  30. package/dist/ai/common/TFMP_TextLanguageDetection.d.ts.map +1 -1
  31. package/dist/ai/common/TFMP_Unload.d.ts +2 -2
  32. package/dist/ai/common/TFMP_Unload.d.ts.map +1 -1
  33. package/dist/ai/index.d.ts +25 -0
  34. package/dist/ai/index.d.ts.map +1 -1
  35. package/dist/ai/runtime.d.ts.map +1 -1
  36. package/dist/ai-runtime.d.ts.map +1 -1
  37. package/dist/ai-runtime.js +482 -395
  38. package/dist/ai-runtime.js.map +28 -26
  39. package/dist/ai.d.ts.map +1 -1
  40. package/dist/ai.js +735 -22
  41. package/dist/ai.js.map +27 -6
  42. package/package.json +12 -13
package/dist/ai.js CHANGED
@@ -9,8 +9,8 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
9
9
  // src/ai/common/TFMP_Constants.ts
10
10
  var TENSORFLOW_MEDIAPIPE = "TENSORFLOW_MEDIAPIPE";
11
11
  var TFMP_DEFAULT_TASK_TYPES = [
12
- "DownloadModelTask",
13
- "UnloadModelTask",
12
+ "ModelDownloadTask",
13
+ "ModelDownloadRemoveTask",
14
14
  "ModelInfoTask",
15
15
  "TextEmbeddingTask",
16
16
  "TextLanguageDetectionTask",
@@ -46,7 +46,6 @@ var TextPipelineTask = {
46
46
  "vision-object-detector": "vision-object-detector",
47
47
  "vision-pose-landmarker": "vision-pose-landmarker"
48
48
  };
49
-
50
49
  // src/ai/common/TFMP_ModelSchema.ts
51
50
  import { ModelConfigSchema, ModelRecordSchema } from "@workglow/ai/worker";
52
51
  var TFMPModelSchema = {
@@ -100,7 +99,6 @@ var TFMPModelConfigSchema = {
100
99
  required: [...ModelConfigSchema.required, ...TFMPModelSchema.required],
101
100
  additionalProperties: false
102
101
  };
103
-
104
102
  // src/ai/common/TFMP_ModelSearch.ts
105
103
  import { filterModelSearchResultsByQuery } from "@workglow/ai/provider-utils";
106
104
  var TFMP_MODEL_RESULTS = [
@@ -112,7 +110,7 @@ var TFMP_MODEL_RESULTS = [
112
110
  provider: TENSORFLOW_MEDIAPIPE,
113
111
  title: "Universal Sentence Encoder",
114
112
  description: "Universal Sentence Encoder",
115
- tasks: ["TextEmbeddingTask"],
113
+ capabilities: ["text.embedding"],
116
114
  provider_config: {
117
115
  model_path: "https://storage.googleapis.com/mediapipe-tasks/text_embedder/universal_sentence_encoder.tflite",
118
116
  task_engine: "text",
@@ -130,7 +128,7 @@ var TFMP_MODEL_RESULTS = [
130
128
  provider: TENSORFLOW_MEDIAPIPE,
131
129
  title: "MediaPipe Language Detector",
132
130
  description: "MediaPipe Language Detector",
133
- tasks: ["TextLanguageDetectionTask"],
131
+ capabilities: ["text.language-detection"],
134
132
  provider_config: {
135
133
  model_path: "https://storage.googleapis.com/mediapipe-models/language_detector/language_detector/float32/latest/language_detector.tflite",
136
134
  task_engine: "text",
@@ -148,7 +146,7 @@ var TFMP_MODEL_RESULTS = [
148
146
  provider: TENSORFLOW_MEDIAPIPE,
149
147
  title: "MediaPipe BERT Text Classifier",
150
148
  description: "MediaPipe BERT Text Classifier",
151
- tasks: ["TextClassificationTask"],
149
+ capabilities: ["text.classification"],
152
150
  provider_config: {
153
151
  model_path: "https://storage.googleapis.com/mediapipe-tasks/text_classifier/bert_text_classifier.tflite",
154
152
  task_engine: "text",
@@ -166,7 +164,7 @@ var TFMP_MODEL_RESULTS = [
166
164
  provider: TENSORFLOW_MEDIAPIPE,
167
165
  title: "MediaPipe Image Embedder",
168
166
  description: "MediaPipe Image Embedder",
169
- tasks: ["ImageEmbeddingTask"],
167
+ capabilities: ["image.embedding"],
170
168
  provider_config: {
171
169
  model_path: "https://storage.googleapis.com/mediapipe-models/image_embedder/mobilenet_v3_small/float32/1/mobilenet_v3_small.tflite",
172
170
  task_engine: "vision",
@@ -184,7 +182,7 @@ var TFMP_MODEL_RESULTS = [
184
182
  provider: TENSORFLOW_MEDIAPIPE,
185
183
  title: "EfficientNet Lite0",
186
184
  description: "Image classification model",
187
- tasks: ["ImageClassificationTask"],
185
+ capabilities: ["image.classification"],
188
186
  provider_config: {
189
187
  model_path: "https://storage.googleapis.com/mediapipe-models/image_classifier/efficientnet_lite0/float32/1/efficientnet_lite0.tflite",
190
188
  task_engine: "vision",
@@ -202,7 +200,7 @@ var TFMP_MODEL_RESULTS = [
202
200
  provider: TENSORFLOW_MEDIAPIPE,
203
201
  title: "Efficient Object Detector Lite0",
204
202
  description: "Object detection model",
205
- tasks: ["ObjectDetectionTask"],
203
+ capabilities: ["image.object-detection"],
206
204
  provider_config: {
207
205
  model_path: "https://storage.googleapis.com/mediapipe-models/object_detector/efficientdet_lite0/float32/1/efficientdet_lite0.tflite",
208
206
  task_engine: "vision",
@@ -220,7 +218,7 @@ var TFMP_MODEL_RESULTS = [
220
218
  provider: TENSORFLOW_MEDIAPIPE,
221
219
  title: "Efficient Image Segmenter Lite0",
222
220
  description: "Image segmentation model",
223
- tasks: ["ImageSegmentationTask"],
221
+ capabilities: ["image.segmentation"],
224
222
  provider_config: {
225
223
  model_path: "https://storage.googleapis.com/mediapipe-assets/deeplabv3.tflite?generation=1661875711618421",
226
224
  task_engine: "vision",
@@ -238,7 +236,7 @@ var TFMP_MODEL_RESULTS = [
238
236
  provider: TENSORFLOW_MEDIAPIPE,
239
237
  title: "Face Landmarker",
240
238
  description: "Detects 478 facial landmarks with blendshapes",
241
- tasks: ["FaceLandmarkerTask"],
239
+ capabilities: ["vision.face-landmarks"],
242
240
  provider_config: {
243
241
  model_path: "https://storage.googleapis.com/mediapipe-models/face_landmarker/face_landmarker/float16/1/face_landmarker.task",
244
242
  task_engine: "vision",
@@ -256,7 +254,7 @@ var TFMP_MODEL_RESULTS = [
256
254
  provider: TENSORFLOW_MEDIAPIPE,
257
255
  title: "Gesture Recognizer",
258
256
  description: "Recognizes hand gestures such as thumbs up and victory",
259
- tasks: ["GestureRecognizerTask"],
257
+ capabilities: ["vision.gesture"],
260
258
  provider_config: {
261
259
  model_path: "https://storage.googleapis.com/mediapipe-models/gesture_recognizer/gesture_recognizer/float16/1/gesture_recognizer.task",
262
260
  task_engine: "vision",
@@ -274,7 +272,7 @@ var TFMP_MODEL_RESULTS = [
274
272
  provider: TENSORFLOW_MEDIAPIPE,
275
273
  title: "Hand Landmarker",
276
274
  description: "Detects 21 hand landmarks",
277
- tasks: ["HandLandmarkerTask"],
275
+ capabilities: ["vision.hand-landmarks"],
278
276
  provider_config: {
279
277
  model_path: "https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task",
280
278
  task_engine: "vision",
@@ -292,7 +290,7 @@ var TFMP_MODEL_RESULTS = [
292
290
  provider: TENSORFLOW_MEDIAPIPE,
293
291
  title: "Pose Landmarker",
294
292
  description: "Detects 33 body pose landmarks",
295
- tasks: ["PoseLandmarkerTask"],
293
+ capabilities: ["vision.pose-landmarks"],
296
294
  provider_config: {
297
295
  model_path: "https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task",
298
296
  task_engine: "vision",
@@ -304,29 +302,131 @@ var TFMP_MODEL_RESULTS = [
304
302
  }
305
303
  ];
306
304
  function createTFMPModelSearch(providerId) {
307
- return async (input) => {
305
+ return async (input, _model, _signal, emit) => {
308
306
  const results = filterModelSearchResultsByQuery(TFMP_MODEL_RESULTS.map((result) => ({
309
307
  ...result,
310
308
  record: { ...result.record, provider: providerId }
311
309
  })), input.query);
312
- return { results };
310
+ emit({ type: "finish", data: { results } });
313
311
  };
314
312
  }
315
313
  var TFMP_ModelSearch = createTFMPModelSearch(TENSORFLOW_MEDIAPIPE);
316
-
317
314
  // src/ai/registerTensorFlowMediaPipe.ts
318
315
  import { registerProviderWithWorker } from "@workglow/ai/provider-utils";
319
316
 
320
317
  // src/ai/TensorFlowMediaPipeQueuedProvider.ts
321
318
  import { AiProvider } from "@workglow/ai";
319
+
320
+ // src/ai/common/TFMP_CapabilitySets.ts
321
+ var TFMP_TEXT_EMBEDDING = ["text.embedding"];
322
+ var TFMP_TEXT_CLASSIFICATION = ["text.classification"];
323
+ var TFMP_TEXT_LANGUAGE_DETECTION = [
324
+ "text.language-detection"
325
+ ];
326
+ var TFMP_IMAGE_CLASSIFICATION = ["image.classification"];
327
+ var TFMP_IMAGE_EMBEDDING = ["image.embedding"];
328
+ var TFMP_IMAGE_SEGMENTATION = ["image.segmentation"];
329
+ var TFMP_IMAGE_OBJECT_DETECTION = [
330
+ "image.object-detection"
331
+ ];
332
+ var TFMP_VISION_FACE_DETECTION = ["vision.face-detection"];
333
+ var TFMP_VISION_FACE_LANDMARKS = ["vision.face-landmarks"];
334
+ var TFMP_VISION_HAND_LANDMARKS = ["vision.hand-landmarks"];
335
+ var TFMP_VISION_POSE_LANDMARKS = ["vision.pose-landmarks"];
336
+ var TFMP_VISION_GESTURE = ["vision.gesture"];
337
+ var TFMP_MODEL_DOWNLOAD = ["model.download"];
338
+ var TFMP_MODEL_UNLOAD = ["model.download-remove"];
339
+ var TFMP_MODEL_SEARCH = ["model.search"];
340
+ var TFMP_MODEL_INFO = ["model.info"];
341
+ var TFMP_CAPABILITY_SETS = [
342
+ TFMP_TEXT_EMBEDDING,
343
+ TFMP_TEXT_CLASSIFICATION,
344
+ TFMP_TEXT_LANGUAGE_DETECTION,
345
+ TFMP_IMAGE_CLASSIFICATION,
346
+ TFMP_IMAGE_EMBEDDING,
347
+ TFMP_IMAGE_SEGMENTATION,
348
+ TFMP_IMAGE_OBJECT_DETECTION,
349
+ TFMP_VISION_FACE_DETECTION,
350
+ TFMP_VISION_FACE_LANDMARKS,
351
+ TFMP_VISION_HAND_LANDMARKS,
352
+ TFMP_VISION_POSE_LANDMARKS,
353
+ TFMP_VISION_GESTURE,
354
+ TFMP_MODEL_DOWNLOAD,
355
+ TFMP_MODEL_UNLOAD,
356
+ TFMP_MODEL_SEARCH,
357
+ TFMP_MODEL_INFO
358
+ ];
359
+
360
+ // src/ai/common/TFMP_Capabilities.ts
361
+ var TFMP_RUN_FN_SPECS = TFMP_CAPABILITY_SETS.map((serves) => ({ serves }));
362
+ function tfmpWorkerRunFnSpecs() {
363
+ return TFMP_RUN_FN_SPECS;
364
+ }
365
+ function inferTfmpCapabilities(model) {
366
+ const declared = model.capabilities ?? [];
367
+ if (declared.length > 0)
368
+ return declared;
369
+ const id = String(model.model_id ?? model.provider_config?.model_path ?? model.provider_config?.model_name ?? "");
370
+ const baseName = (id.split("/").pop() ?? id).toLowerCase();
371
+ if (/gesture_recognizer/.test(baseName)) {
372
+ return [
373
+ "vision.gesture",
374
+ "vision.hand-landmarks",
375
+ "model.download-remove",
376
+ "model.info",
377
+ "model.search"
378
+ ];
379
+ }
380
+ if (/hand_landmarker/.test(baseName)) {
381
+ return ["vision.hand-landmarks", "model.download-remove", "model.info", "model.search"];
382
+ }
383
+ if (/face_landmarker/.test(baseName)) {
384
+ return ["vision.face-landmarks", "model.download-remove", "model.info", "model.search"];
385
+ }
386
+ if (/face_detector|blaze_face/.test(baseName)) {
387
+ return ["vision.face-detection", "model.download-remove", "model.info", "model.search"];
388
+ }
389
+ if (/pose_landmarker/.test(baseName)) {
390
+ return ["vision.pose-landmarks", "model.download-remove", "model.info", "model.search"];
391
+ }
392
+ if (/object_detector|efficientdet|ssd_mobilenet|yolo/.test(baseName)) {
393
+ return ["image.object-detection", "model.download-remove", "model.info", "model.search"];
394
+ }
395
+ if (/segmenter|deeplab|selfie/.test(baseName)) {
396
+ return ["image.segmentation", "model.download-remove", "model.info", "model.search"];
397
+ }
398
+ if (/image_classifier|efficientnet|mobilenet/.test(baseName)) {
399
+ return ["image.classification", "model.download-remove", "model.info", "model.search"];
400
+ }
401
+ if (/image_embed/.test(baseName)) {
402
+ return ["image.embedding", "model.download-remove", "model.info", "model.search"];
403
+ }
404
+ if (/text_embed|universal_sentence_encoder|use_/.test(baseName)) {
405
+ return ["text.embedding", "model.download-remove", "model.info", "model.search"];
406
+ }
407
+ if (/text_classifier|bert_classifier/.test(baseName)) {
408
+ return ["text.classification", "model.download-remove", "model.info", "model.search"];
409
+ }
410
+ if (/language_detector/.test(baseName)) {
411
+ return ["text.language-detection", "model.download-remove", "model.info", "model.search"];
412
+ }
413
+ return ["model.search", "model.info"];
414
+ }
415
+
416
+ // src/ai/TensorFlowMediaPipeQueuedProvider.ts
322
417
  class TensorFlowMediaPipeQueuedProvider extends AiProvider {
323
418
  name = TENSORFLOW_MEDIAPIPE;
324
419
  displayName = "TensorFlow MediaPipe";
325
420
  isLocal = true;
326
421
  supportsBrowser = true;
327
- taskTypes = TFMP_DEFAULT_TASK_TYPES;
328
- constructor(tasks, previewTasks) {
329
- super(tasks, undefined, previewTasks);
422
+ constructor(promiseRunFns, previewTasks) {
423
+ super(promiseRunFns, previewTasks);
424
+ }
425
+ inferCapabilities(model) {
426
+ return inferTfmpCapabilities(model);
427
+ }
428
+ workerRunFnSpecs() {
429
+ return tfmpWorkerRunFnSpecs();
330
430
  }
331
431
  }
332
432
 
@@ -334,9 +434,622 @@ class TensorFlowMediaPipeQueuedProvider extends AiProvider {
334
434
  async function registerTensorFlowMediaPipe(options) {
335
435
  await registerProviderWithWorker(new TensorFlowMediaPipeQueuedProvider, "TensorFlow MediaPipe", options);
336
436
  }
437
+ // src/ai/common/TFMP_Download.ts
438
+ import { PermanentJobError as PermanentJobError2 } from "@workglow/job-queue";
439
+
440
+ // src/ai/common/TFMP_Client.ts
441
+ var _loadPromiseText;
442
+ var _loadPromiseVision;
443
+ async function loadTfmpTasksTextSDK() {
444
+ _loadPromiseText ??= import("@mediapipe/tasks-text").catch(() => {
445
+ _loadPromiseText = undefined;
446
+ throw new Error("@mediapipe/tasks-text is required for TensorFlow MediaPipe text (and related) tasks. Install with: bun add @mediapipe/tasks-text");
447
+ });
448
+ return _loadPromiseText;
449
+ }
450
+ async function loadTfmpTasksVisionSDK() {
451
+ _loadPromiseVision ??= import("@mediapipe/tasks-vision").catch(() => {
452
+ _loadPromiseVision = undefined;
453
+ throw new Error("@mediapipe/tasks-vision is required for TensorFlow MediaPipe vision tasks. Install with: bun add @mediapipe/tasks-vision");
454
+ });
455
+ return _loadPromiseVision;
456
+ }
457
+
458
+ // src/ai/common/TFMP_Runtime.ts
459
+ import { PermanentJobError } from "@workglow/job-queue";
460
+ var wasm_tasks = new Map;
461
+ var wasm_reference_counts = new Map;
462
+ var modelTaskCache = new Map;
463
+ var optionsMatch = (opts1, opts2) => {
464
+ const keys1 = Object.keys(opts1).sort();
465
+ const keys2 = Object.keys(opts2).sort();
466
+ if (keys1.length !== keys2.length)
467
+ return false;
468
+ return keys1.every((key) => {
469
+ const val1 = opts1[key];
470
+ const val2 = opts2[key];
471
+ if (Array.isArray(val1) && Array.isArray(val2)) {
472
+ return JSON.stringify(val1) === JSON.stringify(val2);
473
+ }
474
+ return val1 === val2;
475
+ });
476
+ };
477
+ var getWasmTask = async (model, emit, signal) => {
478
+ const task_engine = model.provider_config.task_engine;
479
+ if (wasm_tasks.has(task_engine)) {
480
+ return wasm_tasks.get(task_engine);
481
+ }
482
+ if (signal.aborted) {
483
+ throw new PermanentJobError("Aborted job");
484
+ }
485
+ emit({ type: "phase", message: "Loading WASM task", progress: 0.1 });
486
+ let wasmFileset;
487
+ switch (task_engine) {
488
+ case "vision": {
489
+ const { FilesetResolver } = await loadTfmpTasksVisionSDK();
490
+ wasmFileset = await FilesetResolver.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm");
491
+ break;
492
+ }
493
+ case "text": {
494
+ const { FilesetResolver } = await loadTfmpTasksTextSDK();
495
+ wasmFileset = await FilesetResolver.forTextTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-text@latest/wasm");
496
+ break;
497
+ }
498
+ case "audio": {
499
+ const { FilesetResolver } = await loadTfmpTasksTextSDK();
500
+ wasmFileset = await FilesetResolver.forAudioTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-audio@latest/wasm");
501
+ break;
502
+ }
503
+ case "genai": {
504
+ const { FilesetResolver } = await loadTfmpTasksTextSDK();
505
+ wasmFileset = await FilesetResolver.forGenAiTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-genai@latest/wasm");
506
+ break;
507
+ }
508
+ default:
509
+ throw new PermanentJobError("Invalid task engine");
510
+ }
511
+ wasm_tasks.set(task_engine, wasmFileset);
512
+ return wasmFileset;
513
+ };
514
+ var getModelTask = async (model, options, emit, signal, TaskType) => {
515
+ const model_path = model.provider_config.model_path;
516
+ const task_engine = model.provider_config.task_engine;
517
+ const cachedTasks = modelTaskCache.get(model_path);
518
+ if (cachedTasks) {
519
+ const matchedTask = cachedTasks.find((cached) => optionsMatch(cached.options, options));
520
+ if (matchedTask) {
521
+ return matchedTask.task;
522
+ }
523
+ }
524
+ const wasmFileset = await getWasmTask(model, emit, signal);
525
+ emit({ type: "phase", message: "Creating model task", progress: 0.2 });
526
+ const task = await TaskType.createFromOptions(wasmFileset, {
527
+ baseOptions: {
528
+ modelAssetPath: model_path
529
+ },
530
+ ...options
531
+ });
532
+ const cachedTask = { task, options, task_engine };
533
+ if (!modelTaskCache.has(model_path)) {
534
+ modelTaskCache.set(model_path, []);
535
+ }
536
+ modelTaskCache.get(model_path).push(cachedTask);
537
+ wasm_reference_counts.set(task_engine, (wasm_reference_counts.get(task_engine) || 0) + 1);
538
+ return task;
539
+ };
540
+
541
+ // src/ai/common/TFMP_Download.ts
542
+ var TFMP_Download = async (input, model, signal, emit) => {
543
+ const pipeline = model?.provider_config.pipeline;
544
+ let task;
545
+ switch (pipeline) {
546
+ case "text-embedder": {
547
+ const { TextEmbedder } = await loadTfmpTasksTextSDK();
548
+ task = await getModelTask(model, {}, emit, signal, TextEmbedder);
549
+ break;
550
+ }
551
+ case "text-classifier": {
552
+ const { TextClassifier } = await loadTfmpTasksTextSDK();
553
+ task = await getModelTask(model, {}, emit, signal, TextClassifier);
554
+ break;
555
+ }
556
+ case "text-language-detector": {
557
+ const { LanguageDetector } = await loadTfmpTasksTextSDK();
558
+ task = await getModelTask(model, {}, emit, signal, LanguageDetector);
559
+ break;
560
+ }
561
+ case "vision-image-classifier": {
562
+ const { ImageClassifier } = await loadTfmpTasksVisionSDK();
563
+ task = await getModelTask(model, {}, emit, signal, ImageClassifier);
564
+ break;
565
+ }
566
+ case "vision-image-embedder": {
567
+ const { ImageEmbedder } = await loadTfmpTasksVisionSDK();
568
+ task = await getModelTask(model, {}, emit, signal, ImageEmbedder);
569
+ break;
570
+ }
571
+ case "vision-image-segmenter": {
572
+ const { ImageSegmenter } = await loadTfmpTasksVisionSDK();
573
+ task = await getModelTask(model, {}, emit, signal, ImageSegmenter);
574
+ break;
575
+ }
576
+ case "vision-object-detector": {
577
+ const { ObjectDetector } = await loadTfmpTasksVisionSDK();
578
+ task = await getModelTask(model, {}, emit, signal, ObjectDetector);
579
+ break;
580
+ }
581
+ case "vision-face-detector": {
582
+ const { FaceDetector } = await loadTfmpTasksVisionSDK();
583
+ task = await getModelTask(model, {}, emit, signal, FaceDetector);
584
+ break;
585
+ }
586
+ case "vision-face-landmarker": {
587
+ const { FaceLandmarker } = await loadTfmpTasksVisionSDK();
588
+ task = await getModelTask(model, {}, emit, signal, FaceLandmarker);
589
+ break;
590
+ }
591
+ case "vision-gesture-recognizer": {
592
+ const { GestureRecognizer } = await loadTfmpTasksVisionSDK();
593
+ task = await getModelTask(model, {}, emit, signal, GestureRecognizer);
594
+ break;
595
+ }
596
+ case "vision-hand-landmarker": {
597
+ const { HandLandmarker } = await loadTfmpTasksVisionSDK();
598
+ task = await getModelTask(model, {}, emit, signal, HandLandmarker);
599
+ break;
600
+ }
601
+ case "vision-pose-landmarker": {
602
+ const { PoseLandmarker } = await loadTfmpTasksVisionSDK();
603
+ task = await getModelTask(model, {}, emit, signal, PoseLandmarker);
604
+ break;
605
+ }
606
+ default:
607
+ throw new PermanentJobError2(`Invalid pipeline: ${pipeline}. Supported pipelines: text-embedder, text-classifier, text-language-detector, vision-image-classifier, vision-image-embedder, vision-image-segmenter, vision-object-detector, vision-face-detector, vision-face-landmarker, vision-gesture-recognizer, vision-hand-landmarker, vision-pose-landmarker`);
608
+ }
609
+ emit({ type: "phase", message: "Pipeline loaded", progress: 0.9 });
610
+ task.close();
611
+ const task_engine = model.provider_config.task_engine;
612
+ wasm_reference_counts.set(task_engine, wasm_reference_counts.get(task_engine) - 1);
613
+ emit({ type: "finish", data: { model: input.model } });
614
+ };
615
+
616
+ // src/ai/common/TFMP_FaceDetector.ts
617
+ import { PermanentJobError as PermanentJobError3 } from "@workglow/job-queue";
618
+ var TFMP_FaceDetector = async (input, model, signal, emit) => {
619
+ const { FaceDetector } = await loadTfmpTasksVisionSDK();
620
+ const faceDetector = await getModelTask(model, {
621
+ minDetectionConfidence: input.minDetectionConfidence,
622
+ minSuppressionThreshold: input.minSuppressionThreshold
623
+ }, emit, signal, FaceDetector);
624
+ const result = faceDetector.detect(input.image);
625
+ if (!result.detections) {
626
+ throw new PermanentJobError3("Failed to detect faces: Empty result");
627
+ }
628
+ const faces = result.detections.map((detection) => ({
629
+ box: {
630
+ x: detection.boundingBox?.originX || 0,
631
+ y: detection.boundingBox?.originY || 0,
632
+ width: detection.boundingBox?.width || 0,
633
+ height: detection.boundingBox?.height || 0
634
+ },
635
+ keypoints: detection.keypoints?.map((kp) => ({
636
+ x: kp.x,
637
+ y: kp.y,
638
+ label: kp.label
639
+ })) || [],
640
+ score: detection.categories?.[0]?.score || 0
641
+ }));
642
+ emit({ type: "finish", data: { faces } });
643
+ };
644
+
645
+ // src/ai/common/TFMP_FaceLandmarker.ts
646
+ import { PermanentJobError as PermanentJobError4 } from "@workglow/job-queue";
647
+ var TFMP_FaceLandmarker = async (input, model, signal, emit) => {
648
+ const { FaceLandmarker } = await loadTfmpTasksVisionSDK();
649
+ const faceLandmarker = await getModelTask(model, {
650
+ numFaces: input.numFaces,
651
+ minFaceDetectionConfidence: input.minFaceDetectionConfidence,
652
+ minFacePresenceConfidence: input.minFacePresenceConfidence,
653
+ minTrackingConfidence: input.minTrackingConfidence,
654
+ outputFaceBlendshapes: input.outputFaceBlendshapes,
655
+ outputFacialTransformationMatrixes: input.outputFacialTransformationMatrixes
656
+ }, emit, signal, FaceLandmarker);
657
+ const result = faceLandmarker.detect(input.image);
658
+ if (!result.faceLandmarks) {
659
+ throw new PermanentJobError4("Failed to detect face landmarks: Empty result");
660
+ }
661
+ const faces = result.faceLandmarks.map((landmarks, index) => {
662
+ const face = {
663
+ landmarks: landmarks.map((l) => ({
664
+ x: l.x,
665
+ y: l.y,
666
+ z: l.z
667
+ }))
668
+ };
669
+ if (result.faceBlendshapes && result.faceBlendshapes[index]) {
670
+ face.blendshapes = result.faceBlendshapes[index].categories.map((b) => ({
671
+ label: b.categoryName,
672
+ score: b.score
673
+ }));
674
+ }
675
+ if (result.facialTransformationMatrixes && result.facialTransformationMatrixes[index]) {
676
+ face.transformationMatrix = Array.from(result.facialTransformationMatrixes[index].data);
677
+ }
678
+ return face;
679
+ });
680
+ emit({ type: "finish", data: { faces } });
681
+ };
682
+
683
+ // src/ai/common/TFMP_GestureRecognizer.ts
684
+ import { PermanentJobError as PermanentJobError5 } from "@workglow/job-queue";
685
+ var TFMP_GestureRecognizer = async (input, model, signal, emit) => {
686
+ const { GestureRecognizer } = await loadTfmpTasksVisionSDK();
687
+ const gestureRecognizer = await getModelTask(model, {
688
+ numHands: input.numHands,
689
+ minHandDetectionConfidence: input.minHandDetectionConfidence,
690
+ minHandPresenceConfidence: input.minHandPresenceConfidence,
691
+ minTrackingConfidence: input.minTrackingConfidence
692
+ }, emit, signal, GestureRecognizer);
693
+ const result = gestureRecognizer.recognize(input.image);
694
+ if (!result.gestures || !result.landmarks) {
695
+ throw new PermanentJobError5("Failed to recognize gestures: Empty result");
696
+ }
697
+ const hands = result.gestures.map((gestures, index) => ({
698
+ gestures: gestures.map((g) => ({
699
+ label: g.categoryName,
700
+ score: g.score
701
+ })),
702
+ handedness: result.handedness[index].map((h) => ({
703
+ label: h.categoryName,
704
+ score: h.score
705
+ })),
706
+ landmarks: result.landmarks[index].map((l) => ({
707
+ x: l.x,
708
+ y: l.y,
709
+ z: l.z
710
+ })),
711
+ worldLandmarks: result.worldLandmarks[index].map((l) => ({
712
+ x: l.x,
713
+ y: l.y,
714
+ z: l.z
715
+ }))
716
+ }));
717
+ emit({ type: "finish", data: { hands } });
718
+ };
719
+
720
+ // src/ai/common/TFMP_HandLandmarker.ts
721
+ import { PermanentJobError as PermanentJobError6 } from "@workglow/job-queue";
722
+ var TFMP_HandLandmarker = async (input, model, signal, emit) => {
723
+ const { HandLandmarker } = await loadTfmpTasksVisionSDK();
724
+ const handLandmarker = await getModelTask(model, {
725
+ numHands: input.numHands,
726
+ minHandDetectionConfidence: input.minHandDetectionConfidence,
727
+ minHandPresenceConfidence: input.minHandPresenceConfidence,
728
+ minTrackingConfidence: input.minTrackingConfidence
729
+ }, emit, signal, HandLandmarker);
730
+ const result = handLandmarker.detect(input.image);
731
+ if (!result.landmarks) {
732
+ throw new PermanentJobError6("Failed to detect hand landmarks: Empty result");
733
+ }
734
+ const hands = result.landmarks.map((landmarks, index) => ({
735
+ handedness: result.handedness[index].map((h) => ({
736
+ label: h.categoryName,
737
+ score: h.score
738
+ })),
739
+ landmarks: landmarks.map((l) => ({
740
+ x: l.x,
741
+ y: l.y,
742
+ z: l.z
743
+ })),
744
+ worldLandmarks: result.worldLandmarks[index].map((l) => ({
745
+ x: l.x,
746
+ y: l.y,
747
+ z: l.z
748
+ }))
749
+ }));
750
+ emit({ type: "finish", data: { hands } });
751
+ };
752
+
753
+ // src/ai/common/TFMP_ImageClassification.ts
754
+ import { PermanentJobError as PermanentJobError7 } from "@workglow/job-queue";
755
+ var TFMP_ImageClassification = async (input, model, signal, emit) => {
756
+ const { ImageClassifier } = await loadTfmpTasksVisionSDK();
757
+ const imageClassifier = await getModelTask(model, {
758
+ maxResults: input.maxCategories
759
+ }, emit, signal, ImageClassifier);
760
+ const result = imageClassifier.classify(input.image);
761
+ if (!result.classifications?.[0]?.categories) {
762
+ throw new PermanentJobError7("Failed to classify image: Empty result");
763
+ }
764
+ const categories = result.classifications[0].categories.map((category) => ({
765
+ label: category.categoryName,
766
+ score: category.score
767
+ }));
768
+ emit({ type: "finish", data: { categories } });
769
+ };
770
+
771
+ // src/ai/common/TFMP_ImageEmbedding.ts
772
+ import { PermanentJobError as PermanentJobError8 } from "@workglow/job-queue";
773
+ var TFMP_ImageEmbedding = async (input, model, signal, emit) => {
774
+ const { ImageEmbedder } = await loadTfmpTasksVisionSDK();
775
+ const imageEmbedder = await getModelTask(model, {}, emit, signal, ImageEmbedder);
776
+ if (Array.isArray(input.image)) {
777
+ const vectors = [];
778
+ for (const image of input.image) {
779
+ const result2 = imageEmbedder.embed(image);
780
+ if (!result2.embeddings?.[0]?.floatEmbedding) {
781
+ throw new PermanentJobError8("Failed to generate embedding: Empty result");
782
+ }
783
+ vectors.push(Float32Array.from(result2.embeddings[0].floatEmbedding));
784
+ }
785
+ emit({ type: "finish", data: { vector: vectors } });
786
+ return;
787
+ }
788
+ const result = imageEmbedder.embed(input.image);
789
+ if (!result.embeddings?.[0]?.floatEmbedding) {
790
+ throw new PermanentJobError8("Failed to generate embedding: Empty result");
791
+ }
792
+ const embedding = Float32Array.from(result.embeddings[0].floatEmbedding);
793
+ emit({ type: "finish", data: { vector: embedding } });
794
+ };
795
+
796
+ // src/ai/common/TFMP_ImageSegmentation.ts
797
+ import { PermanentJobError as PermanentJobError9 } from "@workglow/job-queue";
798
+ var TFMP_ImageSegmentation = async (input, model, signal, emit) => {
799
+ const { ImageSegmenter } = await loadTfmpTasksVisionSDK();
800
+ const imageSegmenter = await getModelTask(model, {}, emit, signal, ImageSegmenter);
801
+ const result = imageSegmenter.segment(input.image);
802
+ if (!result.categoryMask) {
803
+ throw new PermanentJobError9("Failed to segment image: Empty result");
804
+ }
805
+ const masks = [
806
+ {
807
+ label: "segment",
808
+ score: 1,
809
+ mask: {
810
+ data: result.categoryMask.canvas,
811
+ width: result.categoryMask.width,
812
+ height: result.categoryMask.height
813
+ }
814
+ }
815
+ ];
816
+ emit({ type: "finish", data: { masks } });
817
+ };
818
+
819
+ // src/ai/common/TFMP_ModelInfo.ts
820
+ var TFMP_EMBEDDING_DIMENSIONS = {
821
+ "universal-sentence-encoder": { native_dimensions: 512, mrl: false }
822
+ };
823
+ var TFMP_ModelInfo = async (input, model, _signal, emit) => {
824
+ if (input.detail === "dimensions") {
825
+ const pc = model?.provider_config;
826
+ let native_dimensions = typeof pc?.native_dimensions === "number" ? pc.native_dimensions : undefined;
827
+ const mrl = typeof pc?.mrl === "boolean" ? pc.mrl : false;
828
+ if (native_dimensions === undefined) {
829
+ const modelPath = pc?.model_path ?? "";
830
+ const known = TFMP_EMBEDDING_DIMENSIONS[modelPath];
831
+ if (known) {
832
+ native_dimensions = known.native_dimensions;
833
+ }
834
+ }
835
+ emit({
836
+ type: "finish",
837
+ data: {
838
+ model: input.model,
839
+ is_local: true,
840
+ is_remote: false,
841
+ supports_browser: true,
842
+ supports_node: false,
843
+ is_cached: false,
844
+ is_loaded: false,
845
+ file_sizes: null,
846
+ ...native_dimensions !== undefined ? { native_dimensions } : {},
847
+ ...mrl ? { mrl } : {}
848
+ }
849
+ });
850
+ return;
851
+ }
852
+ const model_path = model.provider_config.model_path;
853
+ const is_loaded = modelTaskCache.has(model_path);
854
+ emit({
855
+ type: "finish",
856
+ data: {
857
+ model: input.model,
858
+ is_local: true,
859
+ is_remote: false,
860
+ supports_browser: true,
861
+ supports_node: false,
862
+ is_cached: is_loaded,
863
+ is_loaded,
864
+ file_sizes: null
865
+ }
866
+ });
867
+ };
868
+
869
+ // src/ai/common/TFMP_ObjectDetection.ts
870
+ import { PermanentJobError as PermanentJobError10 } from "@workglow/job-queue";
871
+ var TFMP_ObjectDetection = async (input, model, signal, emit) => {
872
+ const { ObjectDetector } = await loadTfmpTasksVisionSDK();
873
+ const objectDetector = await getModelTask(model, {
874
+ scoreThreshold: input.threshold
875
+ }, emit, signal, ObjectDetector);
876
+ const result = objectDetector.detect(input.image);
877
+ if (!result.detections) {
878
+ throw new PermanentJobError10("Failed to detect objects: Empty result");
879
+ }
880
+ const detections = result.detections.map((detection) => ({
881
+ label: detection.categories?.[0]?.categoryName || "unknown",
882
+ score: detection.categories?.[0]?.score || 0,
883
+ box: {
884
+ x: detection.boundingBox?.originX || 0,
885
+ y: detection.boundingBox?.originY || 0,
886
+ width: detection.boundingBox?.width || 0,
887
+ height: detection.boundingBox?.height || 0
888
+ }
889
+ }));
890
+ emit({ type: "finish", data: { detections } });
891
+ };
892
+
893
+ // src/ai/common/TFMP_PoseLandmarker.ts
894
+ import { PermanentJobError as PermanentJobError11 } from "@workglow/job-queue";
895
+ var TFMP_PoseLandmarker = async (input, model, signal, emit) => {
896
+ const { PoseLandmarker } = await loadTfmpTasksVisionSDK();
897
+ const poseLandmarker = await getModelTask(model, {
898
+ numPoses: input.numPoses,
899
+ minPoseDetectionConfidence: input.minPoseDetectionConfidence,
900
+ minPosePresenceConfidence: input.minPosePresenceConfidence,
901
+ minTrackingConfidence: input.minTrackingConfidence,
902
+ outputSegmentationMasks: input.outputSegmentationMasks
903
+ }, emit, signal, PoseLandmarker);
904
+ const result = poseLandmarker.detect(input.image);
905
+ if (!result.landmarks) {
906
+ throw new PermanentJobError11("Failed to detect pose landmarks: Empty result");
907
+ }
908
+ const poses = result.landmarks.map((landmarks, index) => {
909
+ const pose = {
910
+ landmarks: landmarks.map((l) => ({
911
+ x: l.x,
912
+ y: l.y,
913
+ z: l.z,
914
+ visibility: l.visibility,
915
+ presence: l.presence
916
+ })),
917
+ worldLandmarks: result.worldLandmarks[index].map((l) => ({
918
+ x: l.x,
919
+ y: l.y,
920
+ z: l.z,
921
+ visibility: l.visibility,
922
+ presence: l.presence
923
+ }))
924
+ };
925
+ if (result.segmentationMasks && result.segmentationMasks[index]) {
926
+ const mask = result.segmentationMasks[index];
927
+ pose.segmentationMask = {
928
+ data: mask.canvas || mask,
929
+ width: mask.width,
930
+ height: mask.height
931
+ };
932
+ }
933
+ return pose;
934
+ });
935
+ emit({ type: "finish", data: { poses } });
936
+ };
937
+
938
+ // src/ai/common/TFMP_TextClassification.ts
939
+ import { PermanentJobError as PermanentJobError12 } from "@workglow/job-queue";
940
+ var TFMP_TextClassification = async (input, model, signal, emit) => {
941
+ const { TextClassifier } = await loadTfmpTasksTextSDK();
942
+ const TextClassification = await getModelTask(model, {
943
+ maxCategories: input.maxCategories
944
+ }, emit, signal, TextClassifier);
945
+ const result = TextClassification.classify(input.text);
946
+ if (!result.classifications?.[0]?.categories) {
947
+ throw new PermanentJobError12("Failed to classify text: Empty result");
948
+ }
949
+ const categories = result.classifications[0].categories.map((category) => ({
950
+ label: category.categoryName,
951
+ score: category.score
952
+ }));
953
+ emit({ type: "finish", data: { categories } });
954
+ };
955
+
956
+ // src/ai/common/TFMP_TextEmbedding.ts
957
+ import { PermanentJobError as PermanentJobError13 } from "@workglow/job-queue";
958
+ var TFMP_TextEmbedding = async (input, model, signal, emit) => {
959
+ const { TextEmbedder } = await loadTfmpTasksTextSDK();
960
+ const textEmbedder = await getModelTask(model, {}, emit, signal, TextEmbedder);
961
+ if (Array.isArray(input.text)) {
962
+ const embeddings = input.text.map((text) => {
963
+ const result2 = textEmbedder.embed(text);
964
+ if (!result2.embeddings?.[0]?.floatEmbedding) {
965
+ throw new PermanentJobError13("Failed to generate embedding: Empty result");
966
+ }
967
+ return Float32Array.from(result2.embeddings[0].floatEmbedding);
968
+ });
969
+ emit({ type: "finish", data: { vector: embeddings } });
970
+ return;
971
+ }
972
+ const result = textEmbedder.embed(input.text);
973
+ if (!result.embeddings?.[0]?.floatEmbedding) {
974
+ throw new PermanentJobError13("Failed to generate embedding: Empty result");
975
+ }
976
+ const embedding = Float32Array.from(result.embeddings[0].floatEmbedding);
977
+ emit({ type: "finish", data: { vector: embedding } });
978
+ };
979
+
980
+ // src/ai/common/TFMP_TextLanguageDetection.ts
981
+ import { PermanentJobError as PermanentJobError14 } from "@workglow/job-queue";
982
+ var TFMP_TextLanguageDetection = async (input, model, signal, emit) => {
983
+ const maxLanguages = input.maxLanguages === 0 ? -1 : input.maxLanguages;
984
+ const { LanguageDetector } = await loadTfmpTasksTextSDK();
985
+ const textLanguageDetector = await getModelTask(model, {
986
+ maxLanguages
987
+ }, emit, signal, LanguageDetector);
988
+ const result = textLanguageDetector.detect(input.text);
989
+ if (!result.languages?.[0]?.languageCode) {
990
+ throw new PermanentJobError14("Failed to detect language: Empty result");
991
+ }
992
+ const languages = result.languages.map((language) => ({
993
+ language: language.languageCode,
994
+ score: language.probability
995
+ }));
996
+ emit({ type: "finish", data: { languages } });
997
+ };
998
+
999
+ // src/ai/common/TFMP_Unload.ts
1000
+ var TFMP_Unload = async (input, model, _signal, emit) => {
1001
+ const model_path = model.provider_config.model_path;
1002
+ if (modelTaskCache.has(model_path)) {
1003
+ const cachedTasks = modelTaskCache.get(model_path);
1004
+ for (const cachedTask of cachedTasks) {
1005
+ const task = cachedTask.task;
1006
+ if ("close" in task && typeof task.close === "function")
1007
+ task.close();
1008
+ const task_engine = cachedTask.task_engine;
1009
+ const currentCount = wasm_reference_counts.get(task_engine) || 0;
1010
+ const newCount = currentCount - 1;
1011
+ if (newCount <= 0) {
1012
+ wasm_tasks.delete(task_engine);
1013
+ wasm_reference_counts.delete(task_engine);
1014
+ } else {
1015
+ wasm_reference_counts.set(task_engine, newCount);
1016
+ }
1017
+ }
1018
+ modelTaskCache.delete(model_path);
1019
+ }
1020
+ emit({ type: "finish", data: { model: input.model } });
1021
+ };
1022
+
1023
+ // src/ai/common/TFMP_JobRunFns.ts
1024
+ var TFMP_RUN_FNS = [
1025
+ { serves: TFMP_TEXT_EMBEDDING, runFn: TFMP_TextEmbedding },
1026
+ { serves: TFMP_TEXT_CLASSIFICATION, runFn: TFMP_TextClassification },
1027
+ { serves: TFMP_TEXT_LANGUAGE_DETECTION, runFn: TFMP_TextLanguageDetection },
1028
+ { serves: TFMP_IMAGE_CLASSIFICATION, runFn: TFMP_ImageClassification },
1029
+ { serves: TFMP_IMAGE_EMBEDDING, runFn: TFMP_ImageEmbedding },
1030
+ { serves: TFMP_IMAGE_SEGMENTATION, runFn: TFMP_ImageSegmentation },
1031
+ { serves: TFMP_IMAGE_OBJECT_DETECTION, runFn: TFMP_ObjectDetection },
1032
+ { serves: TFMP_VISION_FACE_DETECTION, runFn: TFMP_FaceDetector },
1033
+ { serves: TFMP_VISION_FACE_LANDMARKS, runFn: TFMP_FaceLandmarker },
1034
+ { serves: TFMP_VISION_HAND_LANDMARKS, runFn: TFMP_HandLandmarker },
1035
+ { serves: TFMP_VISION_POSE_LANDMARKS, runFn: TFMP_PoseLandmarker },
1036
+ { serves: TFMP_VISION_GESTURE, runFn: TFMP_GestureRecognizer },
1037
+ { serves: TFMP_MODEL_DOWNLOAD, runFn: TFMP_Download },
1038
+ { serves: TFMP_MODEL_UNLOAD, runFn: TFMP_Unload },
1039
+ { serves: TFMP_MODEL_SEARCH, runFn: TFMP_ModelSearch },
1040
+ { serves: TFMP_MODEL_INFO, runFn: TFMP_ModelInfo }
1041
+ ];
1042
+
1043
+ // src/ai/index.ts
1044
+ var _testOnly = {
1045
+ TensorFlowMediaPipeQueuedProvider,
1046
+ TFMP_RUN_FN_SPECS,
1047
+ TFMP_RUN_FNS
1048
+ };
337
1049
  export {
338
1050
  registerTensorFlowMediaPipe,
339
1051
  createTFMPModelSearch,
1052
+ _testOnly,
340
1053
  TextPipelineTask,
341
1054
  TFMP_ModelSearch,
342
1055
  TFMP_DEFAULT_TASK_TYPES,
@@ -346,4 +1059,4 @@ export {
346
1059
  TENSORFLOW_MEDIAPIPE
347
1060
  };
348
1061
 
349
- //# debugId=50E8E246C2C5CE2A64756E2164756E21
1062
+ //# debugId=23504D8C865655B764756E2164756E21