@webex/ladon-ts 5.2.0 → 5.4.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.
package/CHANGELOG.md CHANGED
@@ -2,20 +2,56 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
- ## [5.2.0](https://github.com/beyonddunbar/ladon-ts/compare/v5.0.1...v5.2.0) (2025-01-17)
5
+ ### [5.4.1](https://github.com/beyonddunbar/ladon-ts/compare/v5.4.0...v5.4.1) (2025-03-11)
6
+
7
+ ## [5.4.0](https://github.com/beyonddunbar/ladon-ts/compare/v5.0.1...v5.4.0) (2025-03-11)
8
+
9
+
10
+ ### Features
11
+
12
+ * upgrade onnx version ([0a5a0ad](https://github.com/beyonddunbar/ladon-ts/commit/0a5a0adbfeb70ddae824c74c8a7f03090d813243))
13
+ * fetch and cache assets locally; load them as array buffers ([f1cc74e](https://github.com/beyonddunbar/ladon-ts/commit/f1cc74ed60122f3873cb25014568e2a3ab20eee5))
14
+ * passthrough with generator to support step away ([#20](https://github.com/beyonddunbar/ladon-ts/issues/20)) ([f7e6b58](https://github.com/beyonddunbar/ladon-ts/commit/f7e6b5814d75f42daee67c6174fc1eb80a684b54))
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * lint ([f2a8f94](https://github.com/beyonddunbar/ladon-ts/commit/f2a8f94012a3e17ccdbdc47cc1a60ebf5f163448))
20
+ * publish missing worker files in build folder ([#18](https://github.com/beyonddunbar/ladon-ts/issues/18)) ([de1b8d9](https://github.com/beyonddunbar/ladon-ts/commit/de1b8d9122ff1b2f9eaf3883a3c52a96e56225a2))
21
+ * webgl syntax error ([#22](https://github.com/beyonddunbar/ladon-ts/issues/22)) ([5a7e513](https://github.com/beyonddunbar/ladon-ts/commit/5a7e513bfd2b39f2b5c1a5b8b9c892f99a017285))
22
+ * yarn build error ([#16](https://github.com/beyonddunbar/ladon-ts/issues/16)) ([38eb5af](https://github.com/beyonddunbar/ladon-ts/commit/38eb5afa8c37947187af3d0b4fe061971b8a2436))
23
+
24
+ ## [5.3.0](https://github.com/beyonddunbar/ladon-ts/compare/v5.0.1...v5.3.0) (2025-03-11)
6
25
 
7
26
 
8
27
  ### Features
9
28
 
29
+ * upgrade onnx version ([0a5a0ad](https://github.com/beyonddunbar/ladon-ts/commit/0a5a0adbfeb70ddae824c74c8a7f03090d813243))
30
+ * fetch and cache assets locally; load them as array buffers ([f1cc74e](https://github.com/beyonddunbar/ladon-ts/commit/f1cc74ed60122f3873cb25014568e2a3ab20eee5))
10
31
  * passthrough with generator to support step away ([#20](https://github.com/beyonddunbar/ladon-ts/issues/20)) ([f7e6b58](https://github.com/beyonddunbar/ladon-ts/commit/f7e6b5814d75f42daee67c6174fc1eb80a684b54))
11
32
 
12
33
 
13
34
  ### Bug Fixes
14
35
 
36
+ * lint ([f2a8f94](https://github.com/beyonddunbar/ladon-ts/commit/f2a8f94012a3e17ccdbdc47cc1a60ebf5f163448))
15
37
  * publish missing worker files in build folder ([#18](https://github.com/beyonddunbar/ladon-ts/issues/18)) ([de1b8d9](https://github.com/beyonddunbar/ladon-ts/commit/de1b8d9122ff1b2f9eaf3883a3c52a96e56225a2))
16
38
  * webgl syntax error ([#22](https://github.com/beyonddunbar/ladon-ts/issues/22)) ([5a7e513](https://github.com/beyonddunbar/ladon-ts/commit/5a7e513bfd2b39f2b5c1a5b8b9c892f99a017285))
17
39
  * yarn build error ([#16](https://github.com/beyonddunbar/ladon-ts/issues/16)) ([38eb5af](https://github.com/beyonddunbar/ladon-ts/commit/38eb5afa8c37947187af3d0b4fe061971b8a2436))
18
40
 
41
+ ## [5.2.0](https://github.com/beyonddunbar/ladon-ts/compare/v5.0.1...v5.2.0) (2025-01-17)
42
+
43
+
44
+ ### Features
45
+
46
+ * passthrough with generator to support step away ([#20](https://github.com/beyonddunbar/ladon-ts/issues/20)) ([f7e6b58](https://github.com/beyonddunbar/ladon-ts/commit/f7e6b5814d75f42daee67c6174fc1eb80a684b54))
47
+
48
+
49
+ ### Bug Fixes
50
+
51
+ * publish missing worker files in build folder ([#18](https://github.com/beyonddunbar/ladon-ts/issues/18)) ([de1b8d9](https://github.com/beyonddunbar/ladon-ts/commit/de1b8d9122ff1b2f9eaf3883a3c52a96e56225a2))
52
+ * webgl syntax error ([#22](https://github.com/beyonddunbar/ladon-ts/issues/22)) ([5a7e513](https://github.com/beyonddunbar/ladon-ts/commit/5a7e513bfd2b39f2b5c1a5b8b9c892f99a017285))
53
+ * yarn build error ([#16](https://github.com/beyonddunbar/ladon-ts/issues/16)) ([38eb5af](https://github.com/beyonddunbar/ladon-ts/commit/38eb5afa8c37947187af3d0b4fe061971b8a2436))
54
+
19
55
  ## [5.1.0](https://github.com/beyonddunbar/ladon-ts/compare/v5.0.1...v5.1.0) (2025-01-15)
20
56
 
21
57
 
@@ -1,4 +1,4 @@
1
- const e = "1.15.1b", t = "0.7.7.2", i = "segmentation.js", n = { int: "https://models.int.infra.intelligence.webex.com", prod: "https://models.intelligence.webex.com" }, o = { models: "ladon/models", wasm: "ladon/wasm", workers: "ladon/workers" }, l = { weak: { kernelSize: 9, sigma: 2 }, moderate: { kernelSize: 15, sigma: 6 }, strong: { kernelSize: 25, sigma: 11 }, stronger: { kernelSize: 37, sigma: 17 }, strongest: { kernelSize: 49, sigma: 23 } }, h = { tiny: { modelFile: "tiny-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 48, modelRank: 4 }, low: { modelFile: "low-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 48, modelRank: 4 }, medium: { modelFile: "medium-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 36, modelRank: 4 }, high: { modelFile: "medium-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 24, modelRank: 4 }, ultra: { modelFile: "medium-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 0, modelRank: 4 } }, s = "${BASE_PATH_MODELS}/${MODEL_VERSION}/${MODEL_FILE}", a = "${BASE_PATH_WASM}/${ONNX_VERSION}/", d = "${BASE_PATH_WORKERS}/${LIB_VERSION}/${WORKER_FILE}", m = {
1
+ const e = "1.20.1", t = "0.7.7.2", i = "segmentation.js", n = { int: "https://models.int.infra.intelligence.webex.com", prod: "https://models.intelligence.webex.com" }, o = { models: "ladon/models", wasm: "ladon/wasm", workers: "ladon/workers" }, l = { weak: { kernelSize: 9, sigma: 2 }, moderate: { kernelSize: 15, sigma: 6 }, strong: { kernelSize: 25, sigma: 11 }, stronger: { kernelSize: 37, sigma: 17 }, strongest: { kernelSize: 49, sigma: 23 } }, h = { tiny: { modelFile: "tiny-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 48, modelRank: 4 }, low: { modelFile: "low-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 48, modelRank: 4 }, medium: { modelFile: "medium-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 36, modelRank: 4 }, high: { modelFile: "medium-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 24, modelRank: 4 }, ultra: { modelFile: "medium-640x360.onnx", inputSize: { width: 640, height: 360 }, outputSize: { width: 640, height: 360 }, upscaleSize: { width: 640, height: 360 }, generationIntervalMs: 0, modelRank: 4 } }, s = "${BASE_PATH_MODELS}/${MODEL_VERSION}/${MODEL_FILE}", a = "${BASE_PATH_WASM}/${ONNX_VERSION}/", d = "${BASE_PATH_WORKERS}/${LIB_VERSION}/${WORKER_FILE}", m = {
2
2
  onnxVersion: e,
3
3
  modelVersion: t,
4
4
  workerFile: i,
@@ -1,41 +1,42 @@
1
- import { getBlurConfig as o, getConfig as t, getPreloadConfig as p } from "./lib/config.js";
2
- import { ConfigurationBuilder as l } from "./lib/config-builder.js";
3
- import { BlurStrength as m, Quality as f } from "./lib/config-types.js";
4
- import { LocalGenerator as x, NullGenerator as g, WorkerGenerator as d } from "./lib/generator.js";
1
+ import { getBlurConfig as o, getConfig as t, getPreloadConfig as a } from "./lib/config.js";
2
+ import { ConfigurationBuilder as n } from "./lib/config-builder.js";
3
+ import { BlurStrength as m, Quality as i } from "./lib/config-types.js";
4
+ import { LocalGenerator as d, NullGenerator as x, WorkerGenerator as g } from "./lib/generator.js";
5
5
  import { Pipeline as u } from "./lib/pipeline.js";
6
6
  import { BlurRenderer as h } from "./lib/renderer/blur-renderer.js";
7
7
  import { PassthroughRenderer as B } from "./lib/renderer/passthrough-renderer.js";
8
- import { ReplacementRenderer as C } from "./lib/renderer/replacement-renderer.js";
8
+ import { ReplacementRenderer as I } from "./lib/renderer/replacement-renderer.js";
9
9
  import { WebGLRenderer as P } from "./lib/renderer/webgl-renderer.js";
10
- import { InterpolationMethod as b, bilinearUpsample as L, compileShader as S, isResolvedUri as k, lanczos3Upsample as z, linkProgram as M, resizeImage as N, toAbsoluteURI as W } from "./lib/util.js";
10
+ import { InterpolationMethod as b, bilinearUpsample as L, compileShader as S, isResolvedUri as k, lanczos3Upsample as z, linkProgram as A, loadAndCacheFile as M, resizeImage as N, toAbsoluteURI as W } from "./lib/util.js";
11
11
  import { LIB_VERSION as y } from "./lib/version.js";
12
- import { sharedResourceManager as E } from "./lib/shared-resource-manager.js";
12
+ import { sharedResourceManager as F } from "./lib/shared-resource-manager.js";
13
13
  import { preload as Q } from "./lib/preload.js";
14
14
  export {
15
15
  h as BlurRenderer,
16
16
  m as BlurStrength,
17
- l as ConfigurationBuilder,
17
+ n as ConfigurationBuilder,
18
18
  b as InterpolationMethod,
19
19
  y as LIB_VERSION,
20
- x as LocalGenerator,
21
- g as NullGenerator,
20
+ d as LocalGenerator,
21
+ x as NullGenerator,
22
22
  B as PassthroughRenderer,
23
23
  u as Pipeline,
24
- f as Quality,
25
- C as ReplacementRenderer,
24
+ i as Quality,
25
+ I as ReplacementRenderer,
26
26
  P as WebGLRenderer,
27
- d as WorkerGenerator,
27
+ g as WorkerGenerator,
28
28
  L as bilinearUpsample,
29
29
  S as compileShader,
30
30
  o as getBlurConfig,
31
31
  t as getConfig,
32
- p as getPreloadConfig,
32
+ a as getPreloadConfig,
33
33
  k as isResolvedUri,
34
34
  z as lanczos3Upsample,
35
- M as linkProgram,
35
+ A as linkProgram,
36
+ M as loadAndCacheFile,
36
37
  Q as preload,
37
38
  N as resizeImage,
38
- E as sharedResourceManager,
39
+ F as sharedResourceManager,
39
40
  W as toAbsoluteURI
40
41
  };
41
42
  //# sourceMappingURL=index.js.map
@@ -12,7 +12,7 @@ export declare enum BlurStrength {
12
12
  STRONGER = "STRONGER",
13
13
  STRONGEST = "STRONGEST"
14
14
  }
15
- export declare type ResolutionConfig = {
15
+ export type ResolutionConfig = {
16
16
  readonly height: number;
17
17
  readonly width: number;
18
18
  };
@@ -29,8 +29,8 @@ export interface ModelQualityConfig {
29
29
  readonly outputSize: ResolutionConfig;
30
30
  readonly upscaleSize: ResolutionConfig;
31
31
  }
32
- export declare type InputConfig = ResolutionConfig;
33
- export declare type AssetUrlResolver = (assetUri: string, config: PreloadConfig) => Promise<string>;
32
+ export type InputConfig = ResolutionConfig;
33
+ export type AssetUrlResolver = (assetUri: string, config: PreloadConfig) => Promise<string>;
34
34
  export interface RenderConfig {
35
35
  readonly type: 'blur' | 'passthrough' | 'replacement';
36
36
  readonly horizontalMirror?: boolean;
@@ -48,8 +48,8 @@ export interface ReplacementConfig extends RenderConfig {
48
48
  export interface PassthroughConfig extends RenderConfig {
49
49
  readonly type: 'passthrough';
50
50
  }
51
- export declare type Generator = 'local' | 'worker';
52
- export declare type BaseMaskConfig = {
51
+ export type Generator = 'local' | 'worker';
52
+ export type BaseMaskConfig = {
53
53
  readonly generator: Generator;
54
54
  readonly generationIntervalMs: number;
55
55
  readonly modelRank: number;
@@ -59,16 +59,16 @@ export declare type BaseMaskConfig = {
59
59
  readonly outputSize?: ResolutionConfig;
60
60
  readonly upscaleSize?: ResolutionConfig;
61
61
  };
62
- export declare type MaskConfig = BaseMaskConfig & SizeConfig;
63
- export declare type PreloadConfig = {
62
+ export type MaskConfig = BaseMaskConfig & SizeConfig;
63
+ export type PreloadConfig = {
64
64
  readonly baseUrl?: string;
65
65
  readonly wasmUri: string;
66
66
  readonly mask: BaseMaskConfig;
67
67
  readonly executionProviders?: string[];
68
68
  readonly assetUrlResolver?: AssetUrlResolver;
69
69
  };
70
- export declare type WorkerConfig = Omit<PreloadConfig, 'assetUrlResolver'>;
71
- export declare type PipelineConfig = PreloadConfig & {
70
+ export type WorkerConfig = Omit<PreloadConfig, 'assetUrlResolver'>;
71
+ export type PipelineConfig = PreloadConfig & {
72
72
  readonly render: BlurConfig | RenderConfig | ReplacementConfig;
73
73
  readonly input: InputConfig;
74
74
  readonly mask: MaskConfig;
@@ -5,7 +5,7 @@ declare global {
5
5
  url: string;
6
6
  }
7
7
  }
8
- export declare type FrameData = Uint8ClampedArray | HTMLVideoElement;
8
+ export type FrameData = Uint8ClampedArray | HTMLVideoElement;
9
9
  export interface FacesAndLandmarks {
10
10
  data: Float32Array;
11
11
  dims: readonly number[];
@@ -1,5 +1,5 @@
1
1
  import * as c from "onnxruntime-web";
2
- import { sharedResourceManager as n } from "./shared-resource-manager.js";
2
+ import { sharedResourceManager as d } from "./shared-resource-manager.js";
3
3
  class R {
4
4
  constructor(t) {
5
5
  this.config = t, this.lastMaskGenerationTime = 0;
@@ -30,19 +30,19 @@ class R {
30
30
  preprocess(t, a) {
31
31
  const {
32
32
  modelRank: e,
33
- inputSize: r,
33
+ inputSize: l,
34
34
  outputSize: s
35
- } = this.config.mask, { height: o, width: l } = r, d = o * l;
36
- this.output ?? (this.output = new Float32Array(d * e));
35
+ } = this.config.mask, { height: r, width: i } = l, o = r * i;
36
+ this.output ?? (this.output = new Float32Array(o * e));
37
37
  const k = t.length / 4;
38
- for (let i = 0; i < 3; i++)
39
- for (let h = 0; h < k; h++)
40
- this.output[h + i * d] = t[h * 4 + (2 - i)];
41
- const w = s.width / l, g = s.height / o;
42
- for (let i = 0; i < l; i++) {
43
- const h = Math.floor(i * w);
44
- for (let m = 0; m < o; m++) {
45
- const f = Math.floor(m * g), p = h + f * s.width, M = i + m * l + 3 * d, y = Math.min(Math.max(a[p], 0), 255);
38
+ for (let n = 0; n < 3; n++)
39
+ for (let m = 0; m < k; m++)
40
+ this.output[m + n * o] = t[m * 4 + (2 - n)];
41
+ const w = s.width / i, g = s.height / r;
42
+ for (let n = 0; n < i; n++) {
43
+ const m = Math.floor(n * w);
44
+ for (let h = 0; h < r; h++) {
45
+ const f = Math.floor(h * g), p = m + f * s.width, M = n + h * i + 3 * o, y = Math.min(Math.max(a[p], 0), 255);
46
46
  this.output[M] = y;
47
47
  }
48
48
  }
@@ -52,7 +52,7 @@ class R {
52
52
  return Date.now() - this.lastMaskGenerationTime;
53
53
  }
54
54
  async getLadonOutput(t, a) {
55
- var s, o, l, d;
55
+ var s, r, i, o;
56
56
  if (!this.maskModel)
57
57
  throw new Error("[ladon-ts] - mask model not loaded.");
58
58
  if (this.getTimeSinceLastGeneration() < this.config.mask.generationIntervalMs)
@@ -70,25 +70,25 @@ class R {
70
70
  this.config.mask.modelRank,
71
71
  this.config.mask.inputSize.height,
72
72
  this.config.mask.inputSize.width
73
- ]), r = await this.maskModel.run({ input: e });
74
- return this.lastMask = r.segmentation, this.lastResult = {
73
+ ]), l = await this.maskModel.run({ input: e });
74
+ return this.lastMask = l.segmentation, this.lastResult = {
75
75
  data: this.lastMask.data ?? new Float32Array(0),
76
76
  facesAndLandmarks: {
77
- data: ((s = r.faces_and_landmarks) == null ? void 0 : s.data) ?? new Float32Array(0),
78
- dims: ((o = r.faces_and_landmarks) == null ? void 0 : o.dims) ?? []
77
+ data: ((s = l.faces_and_landmarks) == null ? void 0 : s.data) ?? new Float32Array(0),
78
+ dims: ((r = l.faces_and_landmarks) == null ? void 0 : r.dims) ?? []
79
79
  },
80
- gesture: ((l = r.gesture) == null ? void 0 : l.data) ?? new Float32Array(0),
81
- motion: ((d = r.motion) == null ? void 0 : d.data[0]) ?? 0,
80
+ gesture: ((i = l.gesture) == null ? void 0 : i.data) ?? new Float32Array(0),
81
+ motion: ((o = l.motion) == null ? void 0 : o.data[0]) ?? 0,
82
82
  timestamp: a,
83
83
  warm: !0
84
84
  }, this.lastResult;
85
85
  }
86
86
  async load() {
87
- const t = await n.resolveUri(
87
+ const t = await d.resolveUri(
88
88
  this.config,
89
89
  this.config.mask.modelUri
90
90
  );
91
- if (this.maskModel = n.getModelSession(t), this.maskModel ?? (this.maskModel = await n.loadModel(this.config)), !this.maskModel)
91
+ if (this.maskModel = d.getModelSession(t), this.maskModel ?? (this.maskModel = await d.loadModel(this.config)), !this.maskModel)
92
92
  throw new Error("Failed to load the ONNX model.");
93
93
  }
94
94
  isLoaded() {
@@ -154,9 +154,36 @@ class F {
154
154
  return this.newMask = !1, a;
155
155
  }
156
156
  async load() {
157
- const t = await n.prepareWorkerConfig(this.config);
158
- if (this.worker = n.getWorker(), this.worker ?? (this.worker = await n.initializeWorker(t)), !this.worker)
157
+ const t = await d.prepareWorkerConfig(this.config);
158
+ if (this.worker = d.getWorker(), this.worker ?? (this.worker = await d.initializeWorker(t)), !this.worker)
159
159
  throw new Error("[ladon-ts] - worker is not defined.");
160
+ this.worker.onmessage = (s) => {
161
+ if (s.data.type === "log") {
162
+ const { message: r, severity: i } = s.data, o = `[ladon-ts] Message received from worker: ${r}`;
163
+ switch (i) {
164
+ case "warn":
165
+ console.warn(o);
166
+ break;
167
+ case "error":
168
+ console.error(o);
169
+ break;
170
+ default:
171
+ console.log(o);
172
+ }
173
+ } else if (s.data.status === "generated")
174
+ this.lastMask = s.data.mask, this.lastResult = {
175
+ data: s.data.mask,
176
+ facesAndLandmarks: s.data.facesAndLandmarks,
177
+ gesture: s.data.gesture,
178
+ motion: s.data.motion,
179
+ timestamp: s.data.timestamp,
180
+ warm: !0
181
+ }, this.newMask = !0;
182
+ else {
183
+ const r = d.getWorkerUrl();
184
+ r && URL.revokeObjectURL(r), e == null || e();
185
+ }
186
+ };
160
187
  const a = {
161
188
  baseUrl: t.baseUrl,
162
189
  input: t.input,
@@ -166,24 +193,9 @@ class F {
166
193
  };
167
194
  this.worker.postMessage({ type: "init", config: a });
168
195
  let e;
169
- const r = new Promise((s) => {
196
+ return new Promise((s) => {
170
197
  e = s;
171
198
  });
172
- return this.worker.onmessage = (s) => {
173
- if (s.data.status === "generated")
174
- this.lastMask = s.data.mask, this.lastResult = {
175
- data: s.data.mask,
176
- facesAndLandmarks: s.data.facesAndLandmarks,
177
- gesture: s.data.gesture,
178
- motion: s.data.motion,
179
- timestamp: s.data.timestamp,
180
- warm: !0
181
- }, this.newMask = !0;
182
- else {
183
- const o = n.getWorkerUrl();
184
- o && URL.revokeObjectURL(o), e == null || e();
185
- }
186
- }, r;
187
199
  }
188
200
  isLoaded() {
189
201
  return !!this.worker;
@@ -201,7 +213,7 @@ class F {
201
213
  );
202
214
  }
203
215
  destroy() {
204
- n.terminateWorker();
216
+ d.terminateWorker();
205
217
  }
206
218
  }
207
219
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","sources":["../../../src/lib/generator.ts"],"sourcesContent":["import * as ort from 'onnxruntime-web';\n\nimport { PipelineConfig } from './config-types';\nimport { sharedResourceManager } from './shared-resource-manager';\n\ndeclare global {\n interface ImportMeta {\n url: string;\n }\n}\n\nexport type FrameData = Uint8ClampedArray | HTMLVideoElement;\n\nexport interface FacesAndLandmarks {\n data: Float32Array;\n dims: readonly number[];\n}\nexport interface LadonOutput {\n data: Float32Array; // 1x1x144x256 or 1x1x360x640\n facesAndLandmarks: FacesAndLandmarks; // 1x1x9x16x1439\n gesture: Float32Array; // 1x9\n motion: number; // 1x1x1x1\n timestamp: number;\n warm: boolean;\n}\n\nexport interface MaskGenerator {\n getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput>;\n load(): Promise<void>;\n isLoaded(): boolean;\n postRender(input: Uint8ClampedArray, timestamp: number): Promise<void>;\n destroy(): void;\n}\n\nexport class LocalGenerator implements MaskGenerator {\n private lastResult: LadonOutput;\n private lastMask: ort.Tensor;\n private maskModel?: ort.InferenceSession;\n private lastMaskGenerationTime = 0;\n private output?: Float32Array;\n\n constructor(public readonly config: PipelineConfig) {\n const { height, width } = this.config.mask.outputSize;\n this.lastMask = new ort.Tensor('float32', new Float32Array(height * width), [\n 1,\n 1,\n height,\n width,\n ]);\n this.lastResult = {\n data: this.lastMask.data,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n /**\n * This method preprocesses an input Uint8ClampedArray to a Float32Array\n * while maintaining memory efficiency by reusing a class-scoped output buffer.\n * If the model rank is 4 (e.g., newer tiny model), it sets an alpha channel value.\n *\n * @param {Uint8ClampedArray} input - The input data to be preprocessed\n * @param {Float32Array} alpha - The alpha channel data\n * @returns {Float32Array} - The processed data\n */\n private preprocess(input: Uint8ClampedArray, alpha: Float32Array): Float32Array {\n const {\n modelRank: model_rank,\n inputSize: input_size,\n outputSize: output_size,\n } = this.config.mask;\n const { height, width } = input_size;\n const numImagePixels = height * width;\n\n // Initialize the output buffer if it is not already set\n this.output ??= new Float32Array(numImagePixels * model_rank);\n\n const numInputPixels = input.length / 4; // Divide by 4 for RGBA\n\n // Directly copy channels (assumes fixed order like BGR or RGB)\n for (let channel = 0; channel < 3; channel++) {\n for (let pixel = 0; pixel < numInputPixels; pixel++) {\n // Map input channels directly to output\n this.output[pixel + channel * numImagePixels] = input[pixel * 4 + (2 - channel)];\n }\n }\n\n // Scaling factors for width and height\n const widthScale = output_size.width / width;\n const heightScale = output_size.height / height;\n\n // Process alpha channel\n for (let x = 0; x < width; x++) {\n const nearestNeighborX = Math.floor(x * widthScale);\n for (let y = 0; y < height; y++) {\n const nearestNeighborY = Math.floor(y * heightScale);\n const maskIdx = nearestNeighborX + nearestNeighborY * output_size.width;\n const outputIdx = x + y * width + 3 * numImagePixels;\n\n // Normalize and scale alpha to [0, 255]\n const normalizedValue = Math.min(Math.max(alpha[maskIdx], 0), 255);\n this.output[outputIdx] = normalizedValue;\n }\n }\n\n return this.output;\n }\n\n public getTimeSinceLastGeneration(): number {\n return Date.now() - this.lastMaskGenerationTime;\n }\n\n public async getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput> {\n if (!this.maskModel) {\n throw new Error('[ladon-ts] - mask model not loaded.');\n }\n\n if (this.getTimeSinceLastGeneration() < this.config.mask.generationIntervalMs) {\n return {\n data: this.lastMask.data,\n facesAndLandmarks: this.lastResult.facesAndLandmarks,\n gesture: this.lastResult.gesture,\n motion: this.lastResult.motion,\n timestamp: this.lastResult.timestamp,\n warm: false,\n };\n }\n\n this.lastMaskGenerationTime = Date.now();\n\n const imageTensor = new ort.Tensor('float32', this.preprocess(input, this.lastMask.data), [\n 1,\n this.config.mask.modelRank,\n this.config.mask.inputSize.height,\n this.config.mask.inputSize.width,\n ]);\n\n const results = await this.maskModel.run({ input: imageTensor });\n this.lastMask = results.segmentation;\n\n this.lastResult = {\n data: this.lastMask.data ?? new Float32Array(0),\n facesAndLandmarks: {\n data: results.faces_and_landmarks?.data ?? new Float32Array(0),\n dims: results.faces_and_landmarks?.dims ?? ([] as readonly number[]),\n },\n gesture: results.gesture?.data ?? new Float32Array(0),\n motion: results.motion?.data[0] ?? 0,\n timestamp,\n warm: true,\n };\n\n return this.lastResult;\n }\n\n async load() {\n const modelUrl = await sharedResourceManager.resolveUri(\n this.config,\n this.config.mask.modelUri\n );\n\n // Attempt to retrieve a preloaded InferenceSession from the shared resource manager.\n this.maskModel = sharedResourceManager.getModelSession(modelUrl);\n // If the model is not preloaded, load it from the provided model URL.\n this.maskModel ??= await sharedResourceManager.loadModel(this.config);\n\n if (!this.maskModel) {\n throw new Error('Failed to load the ONNX model.');\n }\n }\n\n public isLoaded(): boolean {\n return !!this.maskModel;\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async postRender(_: Uint8ClampedArray): Promise<void> {\n // empty for local generator\n }\n\n public destroy(): void {\n // empty for local generator\n }\n}\n\nexport class NullGenerator implements MaskGenerator {\n private lastMask: Float32Array;\n\n constructor(public readonly config: PipelineConfig) {\n this.lastMask = new Float32Array(\n this.config.mask.outputSize.height * this.config.mask.outputSize.width\n );\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput> {\n return {\n data: this.lastMask,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n public async load(): Promise<void> {\n // empty for null generator\n }\n\n public isLoaded(): boolean {\n return true;\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async postRender(_: Uint8ClampedArray): Promise<void> {\n // empty for null generator\n }\n\n public destroy(): void {\n // empty for null generator\n }\n}\n\nexport class WorkerGenerator implements MaskGenerator {\n private lastMask: Float32Array;\n private newMask = true;\n private worker?: Worker;\n private lastResult: LadonOutput;\n\n constructor(public readonly config: PipelineConfig) {\n this.lastMask = new Float32Array(\n this.config.mask.outputSize.height * this.config.mask.outputSize.width\n );\n this.lastResult = {\n data: this.lastMask,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput> {\n const toReturn = {\n data: this.lastMask,\n facesAndLandmarks: this.lastResult.facesAndLandmarks,\n gesture: this.lastResult.gesture,\n motion: this.lastResult.motion,\n timestamp: this.lastResult.timestamp,\n warm: this.newMask,\n };\n\n this.newMask = false;\n\n return toReturn;\n }\n\n public async load(): Promise<void> {\n // Prepare the worker configuration by resolving the final URLs and paths to send to the worker.\n const config = await sharedResourceManager.prepareWorkerConfig(this.config);\n\n this.worker = sharedResourceManager.getWorker();\n this.worker ??= await sharedResourceManager.initializeWorker(config);\n\n if (!this.worker) {\n throw new Error('[ladon-ts] - worker is not defined.');\n }\n\n const workerConfig: PipelineConfig = {\n baseUrl: config.baseUrl,\n input: config.input,\n mask: config.mask,\n wasmUri: config.wasmUri,\n render: { type: 'passthrough' },\n };\n\n this.worker.postMessage({ type: 'init', config: workerConfig });\n\n let resolutionCb: () => void;\n const result = new Promise<void>((resolve) => {\n resolutionCb = resolve;\n });\n\n this.worker.onmessage = (event) => {\n if (event.data.status === 'generated') {\n this.lastMask = event.data.mask;\n this.lastResult = {\n data: event.data.mask,\n facesAndLandmarks: event.data.facesAndLandmarks,\n gesture: event.data.gesture,\n motion: event.data.motion,\n timestamp: event.data.timestamp,\n warm: true,\n };\n this.newMask = true;\n } else {\n const workerUrl = sharedResourceManager.getWorkerUrl();\n\n if (workerUrl) {\n URL.revokeObjectURL(workerUrl);\n }\n\n resolutionCb?.();\n }\n };\n\n return result;\n }\n\n public isLoaded(): boolean {\n return !!this.worker;\n }\n\n public async postRender(input: Uint8ClampedArray, timestamp: number): Promise<void> {\n // claim ownership of the input tensor's buffer and forward to worker\n\n if (!this.worker) {\n throw new Error('[ladon-ts] - worker is not defined.');\n }\n\n this.worker.postMessage(\n {\n type: 'generate',\n image: input,\n timestamp,\n },\n [input.buffer]\n );\n }\n\n public destroy(): void {\n sharedResourceManager.terminateWorker();\n }\n}\n"],"names":["LocalGenerator","config","height","width","ort","input","alpha","model_rank","input_size","output_size","numImagePixels","numInputPixels","channel","pixel","widthScale","heightScale","x","nearestNeighborX","y","nearestNeighborY","maskIdx","outputIdx","normalizedValue","timestamp","imageTensor","results","_a","_b","_c","_d","modelUrl","sharedResourceManager","_","NullGenerator","WorkerGenerator","toReturn","workerConfig","resolutionCb","result","resolve","event","workerUrl"],"mappings":"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"}
1
+ {"version":3,"file":"generator.js","sources":["../../../src/lib/generator.ts"],"sourcesContent":["import * as ort from 'onnxruntime-web';\n\nimport { PipelineConfig } from './config-types';\nimport { sharedResourceManager } from './shared-resource-manager';\n\ndeclare global {\n interface ImportMeta {\n url: string;\n }\n}\n\nexport type FrameData = Uint8ClampedArray | HTMLVideoElement;\n\nexport interface FacesAndLandmarks {\n data: Float32Array;\n dims: readonly number[];\n}\nexport interface LadonOutput {\n data: Float32Array; // 1x1x144x256 or 1x1x360x640\n facesAndLandmarks: FacesAndLandmarks; // 1x1x9x16x1439\n gesture: Float32Array; // 1x9\n motion: number; // 1x1x1x1\n timestamp: number;\n warm: boolean;\n}\n\nexport interface MaskGenerator {\n getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput>;\n load(): Promise<void>;\n isLoaded(): boolean;\n postRender(input: Uint8ClampedArray, timestamp: number): Promise<void>;\n destroy(): void;\n}\n\nexport class LocalGenerator implements MaskGenerator {\n private lastResult: LadonOutput;\n private lastMask: ort.Tensor;\n private maskModel?: ort.InferenceSession;\n private lastMaskGenerationTime = 0;\n private output?: Float32Array;\n\n constructor(public readonly config: PipelineConfig) {\n const { height, width } = this.config.mask.outputSize;\n this.lastMask = new ort.Tensor('float32', new Float32Array(height * width), [\n 1,\n 1,\n height,\n width,\n ]);\n this.lastResult = {\n data: this.lastMask.data,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n /**\n * This method preprocesses an input Uint8ClampedArray to a Float32Array\n * while maintaining memory efficiency by reusing a class-scoped output buffer.\n * If the model rank is 4 (e.g., newer tiny model), it sets an alpha channel value.\n *\n * @param {Uint8ClampedArray} input - The input data to be preprocessed\n * @param {Float32Array} alpha - The alpha channel data\n * @returns {Float32Array} - The processed data\n */\n private preprocess(input: Uint8ClampedArray, alpha: Float32Array): Float32Array {\n const {\n modelRank: model_rank,\n inputSize: input_size,\n outputSize: output_size,\n } = this.config.mask;\n const { height, width } = input_size;\n const numImagePixels = height * width;\n\n // Initialize the output buffer if it is not already set\n this.output ??= new Float32Array(numImagePixels * model_rank);\n\n const numInputPixels = input.length / 4; // Divide by 4 for RGBA\n\n // Directly copy channels (assumes fixed order like BGR or RGB)\n for (let channel = 0; channel < 3; channel++) {\n for (let pixel = 0; pixel < numInputPixels; pixel++) {\n // Map input channels directly to output\n this.output[pixel + channel * numImagePixels] = input[pixel * 4 + (2 - channel)];\n }\n }\n\n // Scaling factors for width and height\n const widthScale = output_size.width / width;\n const heightScale = output_size.height / height;\n\n // Process alpha channel\n for (let x = 0; x < width; x++) {\n const nearestNeighborX = Math.floor(x * widthScale);\n for (let y = 0; y < height; y++) {\n const nearestNeighborY = Math.floor(y * heightScale);\n const maskIdx = nearestNeighborX + nearestNeighborY * output_size.width;\n const outputIdx = x + y * width + 3 * numImagePixels;\n\n // Normalize and scale alpha to [0, 255]\n const normalizedValue = Math.min(Math.max(alpha[maskIdx], 0), 255);\n this.output[outputIdx] = normalizedValue;\n }\n }\n\n return this.output;\n }\n\n public getTimeSinceLastGeneration(): number {\n return Date.now() - this.lastMaskGenerationTime;\n }\n\n public async getLadonOutput(input: Uint8ClampedArray, timestamp: number): Promise<LadonOutput> {\n if (!this.maskModel) {\n throw new Error('[ladon-ts] - mask model not loaded.');\n }\n\n if (this.getTimeSinceLastGeneration() < this.config.mask.generationIntervalMs) {\n return {\n data: this.lastMask.data,\n facesAndLandmarks: this.lastResult.facesAndLandmarks,\n gesture: this.lastResult.gesture,\n motion: this.lastResult.motion,\n timestamp: this.lastResult.timestamp,\n warm: false,\n };\n }\n\n this.lastMaskGenerationTime = Date.now();\n\n const imageTensor = new ort.Tensor('float32', this.preprocess(input, this.lastMask.data), [\n 1,\n this.config.mask.modelRank,\n this.config.mask.inputSize.height,\n this.config.mask.inputSize.width,\n ]);\n\n const results = await this.maskModel.run({ input: imageTensor });\n this.lastMask = results.segmentation;\n\n this.lastResult = {\n data: this.lastMask.data ?? new Float32Array(0),\n facesAndLandmarks: {\n data: results.faces_and_landmarks?.data ?? new Float32Array(0),\n dims: results.faces_and_landmarks?.dims ?? ([] as readonly number[]),\n },\n gesture: results.gesture?.data ?? new Float32Array(0),\n motion: results.motion?.data[0] ?? 0,\n timestamp,\n warm: true,\n };\n\n return this.lastResult;\n }\n\n async load() {\n const modelUrl = await sharedResourceManager.resolveUri(\n this.config,\n this.config.mask.modelUri\n );\n\n // Attempt to retrieve a preloaded InferenceSession from the shared resource manager.\n this.maskModel = sharedResourceManager.getModelSession(modelUrl);\n // If the model is not preloaded, load it from the provided model URL.\n this.maskModel ??= await sharedResourceManager.loadModel(this.config);\n\n if (!this.maskModel) {\n throw new Error('Failed to load the ONNX model.');\n }\n }\n\n public isLoaded(): boolean {\n return !!this.maskModel;\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async postRender(_: Uint8ClampedArray): Promise<void> {\n // empty for local generator\n }\n\n public destroy(): void {\n // empty for local generator\n }\n}\n\nexport class NullGenerator implements MaskGenerator {\n private lastMask: Float32Array;\n\n constructor(public readonly config: PipelineConfig) {\n this.lastMask = new Float32Array(\n this.config.mask.outputSize.height * this.config.mask.outputSize.width\n );\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput> {\n return {\n data: this.lastMask,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n public async load(): Promise<void> {\n // empty for null generator\n }\n\n public isLoaded(): boolean {\n return true;\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async postRender(_: Uint8ClampedArray): Promise<void> {\n // empty for null generator\n }\n\n public destroy(): void {\n // empty for null generator\n }\n}\n\nexport class WorkerGenerator implements MaskGenerator {\n private lastMask: Float32Array;\n private newMask = true;\n private worker?: Worker;\n private lastResult: LadonOutput;\n\n constructor(public readonly config: PipelineConfig) {\n this.lastMask = new Float32Array(\n this.config.mask.outputSize.height * this.config.mask.outputSize.width\n );\n this.lastResult = {\n data: this.lastMask,\n facesAndLandmarks: { data: new Float32Array(0), dims: [] },\n gesture: new Float32Array(0),\n motion: 0,\n timestamp: 0,\n warm: false,\n };\n }\n\n /* eslint-disable-next-line @typescript-eslint/no-unused-vars */\n public async getLadonOutput(_: Uint8ClampedArray): Promise<LadonOutput> {\n const toReturn = {\n data: this.lastMask,\n facesAndLandmarks: this.lastResult.facesAndLandmarks,\n gesture: this.lastResult.gesture,\n motion: this.lastResult.motion,\n timestamp: this.lastResult.timestamp,\n warm: this.newMask,\n };\n\n this.newMask = false;\n\n return toReturn;\n }\n\n public async load(): Promise<void> {\n // Prepare the worker configuration by resolving the final URLs and paths to send to the worker.\n const config = await sharedResourceManager.prepareWorkerConfig(this.config);\n\n this.worker = sharedResourceManager.getWorker();\n this.worker ??= await sharedResourceManager.initializeWorker(config);\n\n if (!this.worker) {\n throw new Error('[ladon-ts] - worker is not defined.');\n }\n\n this.worker.onmessage = (event) => {\n if (event.data.type === 'log') {\n // Forward log messages from the worker to the console.\n const { message, severity } = event.data;\n const msg = `[ladon-ts] Message received from worker: ${message}`;\n switch (severity) {\n case 'warn':\n console.warn(msg);\n break;\n case 'error':\n console.error(msg);\n break;\n default:\n console.log(msg);\n }\n } else if (event.data.status === 'generated') {\n // Update the last mask and result with the new data from the worker.\n this.lastMask = event.data.mask;\n this.lastResult = {\n data: event.data.mask,\n facesAndLandmarks: event.data.facesAndLandmarks,\n gesture: event.data.gesture,\n motion: event.data.motion,\n timestamp: event.data.timestamp,\n warm: true,\n };\n this.newMask = true;\n } else {\n // Clean up the worker and revoke the URL when the worker is finished\n const workerUrl = sharedResourceManager.getWorkerUrl();\n if (workerUrl) {\n URL.revokeObjectURL(workerUrl);\n }\n resolutionCb?.();\n }\n };\n\n const workerConfig: PipelineConfig = {\n baseUrl: config.baseUrl,\n input: config.input,\n mask: config.mask,\n wasmUri: config.wasmUri,\n render: { type: 'passthrough' },\n };\n\n this.worker.postMessage({ type: 'init', config: workerConfig });\n\n let resolutionCb: () => void;\n const result = new Promise<void>((resolve) => {\n resolutionCb = resolve;\n });\n\n return result;\n }\n\n public isLoaded(): boolean {\n return !!this.worker;\n }\n\n public async postRender(input: Uint8ClampedArray, timestamp: number): Promise<void> {\n // claim ownership of the input tensor's buffer and forward to worker\n\n if (!this.worker) {\n throw new Error('[ladon-ts] - worker is not defined.');\n }\n\n this.worker.postMessage(\n {\n type: 'generate',\n image: input,\n timestamp,\n },\n [input.buffer]\n );\n }\n\n public destroy(): void {\n sharedResourceManager.terminateWorker();\n }\n}\n"],"names":["LocalGenerator","config","height","width","ort","input","alpha","model_rank","input_size","output_size","numImagePixels","numInputPixels","channel","pixel","widthScale","heightScale","x","nearestNeighborX","y","nearestNeighborY","maskIdx","outputIdx","normalizedValue","timestamp","imageTensor","results","_a","_b","_c","_d","modelUrl","sharedResourceManager","_","NullGenerator","WorkerGenerator","toReturn","event","message","severity","msg","workerUrl","resolutionCb","workerConfig","resolve"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { PipelineConfig } from '../config-types';
2
2
  import { FrameData, LadonOutput } from '../generator';
3
3
 
4
- declare type TextureInitializer = () => void;
4
+ type TextureInitializer = () => void;
5
5
  export declare abstract class WebGLRenderer {
6
6
  output_canvas: HTMLCanvasElement;
7
7
  readonly config: PipelineConfig;
@@ -1,6 +1,7 @@
1
- import * as a from "onnxruntime-web";
2
- import { isResolvedUri as d, toAbsoluteURI as m } from "./util.js";
3
- class c {
1
+ import * as i from "onnxruntime-web";
2
+ import { loadAndCacheFile as h, isResolvedUri as c, toAbsoluteURI as m } from "./util.js";
3
+ const k = "ort-wasm-simd-threaded.wasm";
4
+ class U {
4
5
  constructor() {
5
6
  this.modelSessions = {}, this.resolvedUriCache = /* @__PURE__ */ new Map();
6
7
  }
@@ -13,8 +14,8 @@ class c {
13
14
  async initializeWorker(e) {
14
15
  if (typeof Worker > "u")
15
16
  throw new Error("[ladon-ts] web workers are not supported in this environment");
16
- const r = await this.resolveUri(e, e.mask.workerUri), o = await (await fetch(r, { cache: "force-cache" })).text();
17
- return this.workerUrl = URL.createObjectURL(new Blob([o], { type: "text/javascript" })), new Worker(this.workerUrl, { type: "module" });
17
+ const r = await this.resolveUri(e, e.mask.workerUri), t = await (await fetch(r, { cache: "force-cache" })).text();
18
+ return this.workerUrl = URL.createObjectURL(new Blob([t], { type: "text/javascript" })), new Worker(this.workerUrl, { type: "module" });
18
19
  }
19
20
  /**
20
21
  * Terminate the worker.
@@ -30,13 +31,28 @@ class c {
30
31
  * @returns A promise that resolves when the model is preloaded.
31
32
  */
32
33
  async loadModel(e) {
33
- var i;
34
- const { mask: r, executionProviders: s } = e, o = await this.resolveUri(e, e.wasmUri);
35
- o && (a.env.wasm.wasmPaths = o), a.env.wasm.numThreads = 1;
36
- const t = await this.resolveUri(e, r.modelUri), n = s != null && s.length ? s : ["wasm"];
37
- return (i = this.modelSessions)[t] || (i[t] = await a.InferenceSession.create(t, {
38
- executionProviders: n
39
- })), await this.warmupModel(this.modelSessions[t], r.inputSize, r.modelRank), this.modelSessions[t];
34
+ const { mask: r, executionProviders: s } = e;
35
+ i.env.wasm.numThreads = 1;
36
+ const t = await this.resolveUri(e, e.wasmUri);
37
+ if (t)
38
+ try {
39
+ i.env.wasm.wasmBinary = await h(t + k);
40
+ } catch (w) {
41
+ console.warn("Failed to load or cache WASM file. Using WASM paths.", w), i.env.wasm.wasmPaths = t;
42
+ }
43
+ const a = await this.resolveUri(e, r.modelUri);
44
+ let o = this.modelSessions[a];
45
+ if (!o) {
46
+ const n = { executionProviders: s != null && s.length ? s : ["wasm"] };
47
+ try {
48
+ const l = await h(a);
49
+ o = await i.InferenceSession.create(l, n);
50
+ } catch (l) {
51
+ console.warn("Failed to load or cache model file. Using model URL.", l), o = await i.InferenceSession.create(a, n);
52
+ }
53
+ o = await i.InferenceSession.create(a, n);
54
+ }
55
+ return this.modelSessions[a] = o, await this.warmupModel(o, r.inputSize, r.modelRank), o;
40
56
  }
41
57
  /**
42
58
  * Preload the worker using the provided configuration.
@@ -59,23 +75,23 @@ class c {
59
75
  * @example
60
76
  * await warmupModel(session, inputSize, inputChannels, inputType);
61
77
  */
62
- async warmupModel(e, r = { width: 1280, height: 720 }, s = 3, o = "float32") {
63
- const t = r.height * r.width, n = new Float32Array(s * t).fill(0), i = new a.Tensor(o, n, [
78
+ async warmupModel(e, r = { width: 1280, height: 720 }, s = 3, t = "float32") {
79
+ const a = r.height * r.width, o = new Float32Array(s * a).fill(0), w = new i.Tensor(t, o, [
64
80
  1,
65
81
  s,
66
82
  r.height,
67
83
  r.width
68
- ]), l = { [e.inputNames[0]]: i };
84
+ ]), n = { [e.inputNames[0]]: w };
69
85
  if (s === 3) {
70
- const w = new Float32Array(t).fill(0), h = new a.Tensor(o, w, [
86
+ const l = new Float32Array(a).fill(0), d = new i.Tensor(t, l, [
71
87
  1,
72
88
  1,
73
89
  r.height,
74
90
  r.width
75
91
  ]);
76
- l[e.inputNames[1]] = h;
92
+ n[e.inputNames[1]] = d;
77
93
  }
78
- await e.run(l);
94
+ await e.run(n);
79
95
  }
80
96
  /**
81
97
  * Get the model session for the provided model URL.
@@ -113,7 +129,7 @@ class c {
113
129
  if (this.resolvedUriCache.has(r))
114
130
  return this.resolvedUriCache.get(r);
115
131
  let s;
116
- if (d(r) ? s = r : r.match(/\.[a-z0-9]+$/i) ? typeof e.assetUrlResolver == "function" && (s = await e.assetUrlResolver(r, e)) : s = m(r, e.baseUrl), !s)
132
+ if (c(r) ? s = r : r.match(/\.[a-z0-9]+$/i) ? typeof e.assetUrlResolver == "function" && (s = await e.assetUrlResolver(r, e)) : s = m(r, e.baseUrl), !s)
117
133
  throw new Error(`Failed to resolve asset URI: ${r}`);
118
134
  return this.resolvedUriCache.set(r, s), s;
119
135
  }
@@ -144,8 +160,8 @@ class c {
144
160
  return JSON.parse(JSON.stringify(s));
145
161
  }
146
162
  }
147
- const U = new c();
163
+ const f = new U();
148
164
  export {
149
- U as sharedResourceManager
165
+ f as sharedResourceManager
150
166
  };
151
167
  //# sourceMappingURL=shared-resource-manager.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"shared-resource-manager.js","sources":["../../../src/lib/shared-resource-manager.ts"],"sourcesContent":["import * as ort from 'onnxruntime-web';\n\nimport { PreloadConfig, ResolutionConfig, WorkerConfig } from './config-types';\nimport { isResolvedUri, toAbsoluteURI } from './util';\n\n/**\n * Shared resource manager used to preload and share resources across different pipelines.\n * This is useful when multiple pipelines are using the same model or when the model needs\n * to be preloaded before the pipeline is created.\n */\nclass SharedResourceManager {\n private modelSessions: Record<string, ort.InferenceSession> = {};\n private worker?: Worker;\n private workerUrl?: string;\n\n // In-memory cache for resolved URLs\n private resolvedUriCache: Map<string, string> = new Map();\n\n /**\n * Initialize the worker using the provided configuration.\n *\n * @param config - The configuration object.\n * @returns A promise that resolves when the worker is initialized.\n */\n public async initializeWorker(config: WorkerConfig): Promise<Worker> {\n if (typeof Worker === 'undefined') {\n throw new Error('[ladon-ts] web workers are not supported in this environment');\n }\n\n const scriptUri = await this.resolveUri(config, config.mask.workerUri);\n const response = await fetch(scriptUri, { cache: 'force-cache' });\n const workerSource = await response.text();\n\n this.workerUrl = URL.createObjectURL(new Blob([workerSource], { type: 'text/javascript' }));\n\n return new Worker(this.workerUrl, { type: 'module' });\n }\n\n /**\n * Terminate the worker.\n */\n public terminateWorker() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = undefined;\n }\n }\n\n /**\n * Load the model using the provided configuration. This gets called by the worker when using\n * the worker generator.\n *\n * @param config - The configuration object.\n * @returns A promise that resolves when the model is preloaded.\n */\n public async loadModel(config: PreloadConfig) {\n const { mask, executionProviders: providers } = config;\n\n const wasmPaths = await this.resolveUri(config, config.wasmUri);\n if (wasmPaths) {\n ort.env.wasm.wasmPaths = wasmPaths;\n }\n\n // Lock to a single thread to avoid performance issues.\n ort.env.wasm.numThreads = 1;\n\n const modelUrl = await this.resolveUri(config, mask.modelUri);\n const executionProviders = providers?.length ? providers : ['wasm'];\n\n // Use the model session cache to avoid creating multiple sessions for the same model.\n this.modelSessions[modelUrl] ||= await ort.InferenceSession.create(modelUrl, {\n executionProviders,\n });\n\n // Warmup the model with a dummy input to avoid latency when running the model for the first time.\n await this.warmupModel(this.modelSessions[modelUrl], mask.inputSize, mask.modelRank);\n\n return this.modelSessions[modelUrl];\n }\n\n /**\n * Preload the worker using the provided configuration.\n *\n * @param config - The configuration object.\n * @returns A promise that resolves when the worker is preloaded.\n */\n public async preloadWorker(config: PreloadConfig) {\n const workerConfig = await this.prepareWorkerConfig(config);\n\n this.worker = await this.initializeWorker(workerConfig);\n this.worker.postMessage({ type: 'preload', config: workerConfig });\n }\n\n /**\n * Warmup the model session with a dummy input to avoid latency when running the model for the first time.\n *\n * @param {ort.InferenceSession} session The model session.\n * @param {ResolutionConfig} inputSize The input size of the model.\n * @param {number} inputChannels The number of input channels (e.g., RGB is 3).\n * @param {ort.Tensor.Type} inputType The input tensor type.\n * @returns {Promise<void>} A promise that resolves when the model is warmed up.\n * @example\n * await warmupModel(session, inputSize, inputChannels, inputType);\n */\n public async warmupModel(\n session: ort.InferenceSession,\n inputSize: ResolutionConfig = { width: 1280, height: 720 },\n inputChannels = 3,\n inputType: ort.Tensor.Type = 'float32'\n ): Promise<void> {\n const numPixels = inputSize.height * inputSize.width;\n const dummyInputData = new Float32Array(inputChannels * numPixels).fill(0);\n const dummyInput = new ort.Tensor(inputType, dummyInputData, [\n 1,\n inputChannels,\n inputSize.height,\n inputSize.width,\n ]);\n const feed = { [session.inputNames[0]]: dummyInput };\n\n // Use an additional dummy tensor if the model expects a previous mask.\n if (inputChannels === 3) {\n const dummyMaskData = new Float32Array(numPixels).fill(0);\n const prevMaskTensor = new ort.Tensor(inputType, dummyMaskData, [\n 1,\n 1,\n inputSize.height,\n inputSize.width,\n ]);\n feed[session.inputNames[1]] = prevMaskTensor;\n }\n\n // Run the model with the dummy input to warm it up.\n await session.run(feed);\n }\n\n /**\n * Get the model session for the provided model URL.\n *\n * @param {string} modelUrl The model URL.\n * @returns {ort.InferenceSession} The model session.\n * @example\n * const session = getModelSession(modelUrl);\n */\n public getModelSession(modelUrl: string) {\n return this.modelSessions[modelUrl];\n }\n\n /**\n * Resolves the full URL for a given asset. Non-file URIs are treated as paths\n * and resolved using the `toAbsoluteURI` method.\n *\n * @param config - The preload configuration.\n * @param assetUri - The asset URI from the config.\n * @returns The resolved full URL.\n */\n /**\n * Resolves the full URL for a given asset. Non-file URIs are treated as paths and resolved\n * using the `toAbsoluteURI` method. If the assetUri is already resolved, or if it's found in\n * cache, it will be returned directly. If an assetUrlResolver function is provided in the\n * configuration, it will be used to resolve the URL if the assetUri is not fully qualified,\n * a blob URL, or in the cache.\n *\n * @param config - The preload configuration.\n * @param assetUri - The asset URI from the config.\n * @returns The resolved full URL.\n */\n public async resolveUri(config: PreloadConfig, assetUri?: string): Promise<string> {\n if (!assetUri) {\n throw new Error('Asset URI is undefined.');\n }\n\n // Check if the URL is already cached\n if (this.resolvedUriCache.has(assetUri)) {\n return this.resolvedUriCache.get(assetUri) as string;\n }\n\n let resolvedUrl: string | undefined;\n\n if (isResolvedUri(assetUri)) {\n // If the assetUri is fully qualified or a blob URL, return it directly.\n // (Assets uris are resolved before being sent to the worker.)\n resolvedUrl = assetUri;\n } else if (!assetUri.match(/\\.[a-z0-9]+$/i)) {\n // Resolve as an absolute path to a non-file endpoint (e.g., wasmPaths).\n resolvedUrl = toAbsoluteURI(assetUri, config.baseUrl);\n } else if (typeof config.assetUrlResolver === 'function') {\n // Resolve via assetUrlResolver. This delegates the resolution logic to the caller.\n resolvedUrl = await config.assetUrlResolver(assetUri, config);\n }\n\n if (!resolvedUrl) {\n throw new Error(`Failed to resolve asset URI: ${assetUri}`);\n }\n\n // Cache the resolved URL\n this.resolvedUriCache.set(assetUri, resolvedUrl);\n\n return resolvedUrl;\n }\n\n public getWorker() {\n return this.worker;\n }\n\n public getWorkerUrl() {\n return this.workerUrl;\n }\n\n /**\n * Prepare the worker configuration by resolving the final URLs and paths to send to the\n * worker. This is necessary because we can't send functions to the worker. We also need to\n * remove the assetUrlResolver function from the configuration.\n *\n * @param config - The preload configuration.\n * @returns The worker configuration.\n */\n public async prepareWorkerConfig(config: PreloadConfig) {\n // Resolve and cache the URIs before sending the config to the worker. Future calls to the\n // resolveUri method will use the cache.\n const resolvedConfig: PreloadConfig = {\n ...config,\n mask: {\n ...config.mask,\n modelUri: await this.resolveUri(config, config.mask.modelUri),\n workerUri: await this.resolveUri(config, config.mask.workerUri),\n },\n wasmUri: await this.resolveUri(config, config.wasmUri),\n };\n\n // We can't send the assetUrlResolver function to the worker so we remove it from the config.\n const workerConfig = { ...resolvedConfig, assetUrlResolver: undefined };\n\n // This is a workaround to ensure the worker configuration can be sent to the worker.\n return JSON.parse(JSON.stringify(workerConfig));\n }\n}\n\n// Global instance of the shared resource manager.\nexport const sharedResourceManager = new SharedResourceManager();\n"],"names":["SharedResourceManager","config","scriptUri","workerSource","mask","providers","wasmPaths","ort","modelUrl","executionProviders","_a","workerConfig","session","inputSize","inputChannels","inputType","numPixels","dummyInputData","dummyInput","feed","dummyMaskData","prevMaskTensor","assetUri","resolvedUrl","isResolvedUri","toAbsoluteURI","sharedResourceManager"],"mappings":"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"}
1
+ {"version":3,"file":"shared-resource-manager.js","sources":["../../../src/lib/shared-resource-manager.ts"],"sourcesContent":["import * as ort from 'onnxruntime-web';\n\nimport { PreloadConfig, ResolutionConfig, WorkerConfig } from './config-types';\nimport { isResolvedUri, loadAndCacheFile, toAbsoluteURI } from './util';\n\n// There is only a single WASM file for all WebAssembly binaries now.\nconst ONNX_WASM_FILENAME = 'ort-wasm-simd-threaded.wasm';\n\n/**\n * Shared resource manager used to preload and share resources across different pipelines.\n * This is useful when multiple pipelines are using the same model or when the model needs\n * to be preloaded before the pipeline is created.\n */\nclass SharedResourceManager {\n private modelSessions: Record<string, ort.InferenceSession> = {};\n private worker?: Worker;\n private workerUrl?: string;\n\n // In-memory cache for resolved URLs\n private resolvedUriCache: Map<string, string> = new Map();\n\n /**\n * Initialize the worker using the provided configuration.\n *\n * @param config - The configuration object.\n * @returns A promise that resolves when the worker is initialized.\n */\n public async initializeWorker(config: WorkerConfig): Promise<Worker> {\n if (typeof Worker === 'undefined') {\n throw new Error('[ladon-ts] web workers are not supported in this environment');\n }\n\n const scriptUri = await this.resolveUri(config, config.mask.workerUri);\n const response = await fetch(scriptUri, { cache: 'force-cache' });\n const workerSource = await response.text();\n\n this.workerUrl = URL.createObjectURL(new Blob([workerSource], { type: 'text/javascript' }));\n\n return new Worker(this.workerUrl, { type: 'module' });\n }\n\n /**\n * Terminate the worker.\n */\n public terminateWorker() {\n if (this.worker) {\n this.worker.terminate();\n this.worker = undefined;\n }\n }\n\n /**\n * Load the model using the provided configuration. This gets called by the worker when using\n * the worker generator.\n *\n * @param config - The configuration object.\n * @returns A promise that resolves when the model is preloaded.\n */\n public async loadModel(config: PreloadConfig) {\n const { mask, executionProviders: providers } = config;\n\n // Lock to a single thread to avoid performance issues.\n ort.env.wasm.numThreads = 1;\n\n // Get the resolved paths for the WASM binary.\n const wasmPaths = await this.resolveUri(config, config.wasmUri);\n\n if (wasmPaths) {\n try {\n ort.env.wasm.wasmBinary = await loadAndCacheFile(wasmPaths + ONNX_WASM_FILENAME);\n } catch (error) {\n console.warn('Failed to load or cache WASM file. Using WASM paths.', error);\n ort.env.wasm.wasmPaths = wasmPaths;\n }\n }\n\n // Resolve the model URL.\n const modelUrl = await this.resolveUri(config, mask.modelUri);\n let modelSession = this.modelSessions[modelUrl];\n\n // If the model session is not already cached, create a new session and cache.\n if (!modelSession) {\n // Allows the user to specify the execution providers to use. The default is the WASM provider.\n // TODO: Add and test support for other execution providers.\n const executionProviders = providers?.length ? providers : ['wasm'];\n const sessionOptions = { executionProviders };\n\n // First try to get the model binary either from cache or by fetching and cacheing it.\n try {\n const modelBinary = await loadAndCacheFile(modelUrl);\n modelSession = await ort.InferenceSession.create(modelBinary, sessionOptions);\n } catch (error) {\n console.warn('Failed to load or cache model file. Using model URL.', error);\n modelSession = await ort.InferenceSession.create(modelUrl, sessionOptions);\n }\n modelSession = await ort.InferenceSession.create(modelUrl, sessionOptions);\n }\n\n // Cache the model session.\n this.modelSessions[modelUrl] = modelSession;\n\n // Warmup the model with a dummy input to avoid latency when running the model for the first time.\n await this.warmupModel(modelSession, mask.inputSize, mask.modelRank);\n\n return modelSession;\n }\n\n /**\n * Preload the worker using the provided configuration.\n *\n * @param config - The configuration object.\n * @returns A promise that resolves when the worker is preloaded.\n */\n public async preloadWorker(config: PreloadConfig) {\n const workerConfig = await this.prepareWorkerConfig(config);\n\n this.worker = await this.initializeWorker(workerConfig);\n this.worker.postMessage({ type: 'preload', config: workerConfig });\n }\n\n /**\n * Warmup the model session with a dummy input to avoid latency when running the model for the first time.\n *\n * @param {ort.InferenceSession} session The model session.\n * @param {ResolutionConfig} inputSize The input size of the model.\n * @param {number} inputChannels The number of input channels (e.g., RGB is 3).\n * @param {ort.Tensor.Type} inputType The input tensor type.\n * @returns {Promise<void>} A promise that resolves when the model is warmed up.\n * @example\n * await warmupModel(session, inputSize, inputChannels, inputType);\n */\n public async warmupModel(\n session: ort.InferenceSession,\n inputSize: ResolutionConfig = { width: 1280, height: 720 },\n inputChannels = 3,\n inputType: ort.Tensor.Type = 'float32'\n ): Promise<void> {\n const numPixels = inputSize.height * inputSize.width;\n const dummyInputData = new Float32Array(inputChannels * numPixels).fill(0);\n const dummyInput = new ort.Tensor(inputType, dummyInputData, [\n 1,\n inputChannels,\n inputSize.height,\n inputSize.width,\n ]);\n const feed = { [session.inputNames[0]]: dummyInput };\n\n // Use an additional dummy tensor if the model expects a previous mask.\n if (inputChannels === 3) {\n const dummyMaskData = new Float32Array(numPixels).fill(0);\n const prevMaskTensor = new ort.Tensor(inputType, dummyMaskData, [\n 1,\n 1,\n inputSize.height,\n inputSize.width,\n ]);\n feed[session.inputNames[1]] = prevMaskTensor;\n }\n\n // Run the model with the dummy input to warm it up.\n await session.run(feed);\n }\n\n /**\n * Get the model session for the provided model URL.\n *\n * @param {string} modelUrl The model URL.\n * @returns {ort.InferenceSession} The model session.\n * @example\n * const session = getModelSession(modelUrl);\n */\n public getModelSession(modelUrl: string) {\n return this.modelSessions[modelUrl];\n }\n\n /**\n * Resolves the full URL for a given asset. Non-file URIs are treated as paths\n * and resolved using the `toAbsoluteURI` method.\n *\n * @param config - The preload configuration.\n * @param assetUri - The asset URI from the config.\n * @returns The resolved full URL.\n */\n /**\n * Resolves the full URL for a given asset. Non-file URIs are treated as paths and resolved\n * using the `toAbsoluteURI` method. If the assetUri is already resolved, or if it's found in\n * cache, it will be returned directly. If an assetUrlResolver function is provided in the\n * configuration, it will be used to resolve the URL if the assetUri is not fully qualified,\n * a blob URL, or in the cache.\n *\n * @param config - The preload configuration.\n * @param assetUri - The asset URI from the config.\n * @returns The resolved full URL.\n */\n public async resolveUri(config: PreloadConfig, assetUri?: string): Promise<string> {\n if (!assetUri) {\n throw new Error('Asset URI is undefined.');\n }\n\n // Check if the URL is already cached\n if (this.resolvedUriCache.has(assetUri)) {\n return this.resolvedUriCache.get(assetUri) as string;\n }\n\n let resolvedUrl: string | undefined;\n\n if (isResolvedUri(assetUri)) {\n // If the assetUri is fully qualified or a blob URL, return it directly.\n // (Assets uris are resolved before being sent to the worker.)\n resolvedUrl = assetUri;\n } else if (!assetUri.match(/\\.[a-z0-9]+$/i)) {\n // Resolve as an absolute path to a non-file endpoint (e.g., wasmPaths).\n resolvedUrl = toAbsoluteURI(assetUri, config.baseUrl);\n } else if (typeof config.assetUrlResolver === 'function') {\n // Resolve via assetUrlResolver. This delegates the resolution logic to the caller.\n resolvedUrl = await config.assetUrlResolver(assetUri, config);\n }\n\n if (!resolvedUrl) {\n throw new Error(`Failed to resolve asset URI: ${assetUri}`);\n }\n\n // Cache the resolved URL\n this.resolvedUriCache.set(assetUri, resolvedUrl);\n\n return resolvedUrl;\n }\n\n public getWorker() {\n return this.worker;\n }\n\n public getWorkerUrl() {\n return this.workerUrl;\n }\n\n /**\n * Prepare the worker configuration by resolving the final URLs and paths to send to the\n * worker. This is necessary because we can't send functions to the worker. We also need to\n * remove the assetUrlResolver function from the configuration.\n *\n * @param config - The preload configuration.\n * @returns The worker configuration.\n */\n public async prepareWorkerConfig(config: PreloadConfig) {\n // Resolve and cache the URIs before sending the config to the worker. Future calls to the\n // resolveUri method will use the cache.\n const resolvedConfig: PreloadConfig = {\n ...config,\n mask: {\n ...config.mask,\n modelUri: await this.resolveUri(config, config.mask.modelUri),\n workerUri: await this.resolveUri(config, config.mask.workerUri),\n },\n wasmUri: await this.resolveUri(config, config.wasmUri),\n };\n\n // We can't send the assetUrlResolver function to the worker so we remove it from the config.\n const workerConfig = { ...resolvedConfig, assetUrlResolver: undefined };\n\n // This is a workaround to ensure the worker configuration can be sent to the worker.\n return JSON.parse(JSON.stringify(workerConfig));\n }\n}\n\n// Global instance of the shared resource manager.\nexport const sharedResourceManager = new SharedResourceManager();\n"],"names":["ONNX_WASM_FILENAME","SharedResourceManager","config","scriptUri","workerSource","mask","providers","ort","wasmPaths","loadAndCacheFile","error","modelUrl","modelSession","sessionOptions","modelBinary","workerConfig","session","inputSize","inputChannels","inputType","numPixels","dummyInputData","dummyInput","feed","dummyMaskData","prevMaskTensor","assetUri","resolvedUrl","isResolvedUri","toAbsoluteURI","sharedResourceManager"],"mappings":"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"}
@@ -61,3 +61,4 @@ export declare function linkProgram(gl: WebGL2RenderingContext, vertex_shader: W
61
61
  * @returns Whether the URI is already resolved.
62
62
  */
63
63
  export declare function isResolvedUri(uri: string): boolean;
64
+ export declare function loadAndCacheFile(fileUrl: string): Promise<ArrayBufferLike | Uint8Array>;