@jaak.ai/stamps 2.1.0-dev.7 → 2.1.0-dev.9

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 (27) hide show
  1. package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
  2. package/dist/cjs/jaak-stamps.cjs.entry.js +377 -17
  3. package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
  4. package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
  5. package/dist/cjs/loader.cjs.js +1 -1
  6. package/dist/collection/components/my-component/my-component.js +265 -12
  7. package/dist/collection/components/my-component/my-component.js.map +1 -1
  8. package/dist/collection/services/DetectionService.js +148 -7
  9. package/dist/collection/services/DetectionService.js.map +1 -1
  10. package/dist/collection/services/interfaces/IDetectionService.js.map +1 -1
  11. package/dist/components/jaak-stamps.js +380 -18
  12. package/dist/components/jaak-stamps.js.map +1 -1
  13. package/dist/esm/jaak-stamps-webcomponent.js +1 -1
  14. package/dist/esm/jaak-stamps.entry.js +377 -17
  15. package/dist/esm/jaak-stamps.entry.js.map +1 -1
  16. package/dist/esm/loader.js +1 -1
  17. package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
  18. package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
  19. package/dist/jaak-stamps-webcomponent/p-c115e01a.entry.js +2 -0
  20. package/dist/jaak-stamps-webcomponent/p-c115e01a.entry.js.map +1 -0
  21. package/dist/types/components/my-component/my-component.d.ts +27 -0
  22. package/dist/types/components.d.ts +3 -1
  23. package/dist/types/services/DetectionService.d.ts +9 -1
  24. package/dist/types/services/interfaces/IDetectionService.d.ts +6 -0
  25. package/package.json +1 -1
  26. package/dist/jaak-stamps-webcomponent/p-be6b6ca3.entry.js +0 -2
  27. package/dist/jaak-stamps-webcomponent/p-be6b6ca3.entry.js.map +0 -1
@@ -20,6 +20,10 @@ export class DetectionService {
20
20
  // Static canvas pool for reuse across instances
21
21
  static canvasPool = new Map();
22
22
  static MAX_POOL_SIZE = 5;
23
+ // Resource management for optimization
24
+ modelLoadController;
25
+ classificationLoadController;
26
+ modelBlobUrls = new Set();
23
27
  constructor(debug = false, useDocumentClassification = false, useDocumentDetector = true) {
24
28
  this.debug = debug;
25
29
  this.useDocumentClassification = useDocumentClassification;
@@ -37,11 +41,28 @@ export class DetectionService {
37
41
  return;
38
42
  }
39
43
  try {
44
+ if (typeof window.ort === 'undefined') {
45
+ throw new Error('ONNX Runtime not available in window object');
46
+ }
47
+ // Create AbortController for this load operation
48
+ this.modelLoadController = new AbortController();
40
49
  const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
41
50
  try {
42
- this.session = await window.ort.InferenceSession.create(this.MODEL_PATH, sessionOptions);
51
+ // Load model with abort signal support
52
+ const response = await fetch(this.MODEL_PATH, {
53
+ signal: this.modelLoadController.signal
54
+ });
55
+ if (!response.ok) {
56
+ throw new Error(`Failed to fetch model: ${response.status}`);
57
+ }
58
+ const modelBuffer = await response.arrayBuffer();
59
+ this.session = await window.ort.InferenceSession.create(modelBuffer, sessionOptions);
43
60
  }
44
61
  catch (error) {
62
+ // Handle abort signal
63
+ if (error.name === 'AbortError') {
64
+ return;
65
+ }
45
66
  // Múltiples tipos de errores de memoria que pueden ocurrir
46
67
  const isMemoryError = error.message.includes('failed to allocate a buffer') ||
47
68
  error.message.includes('Out of memory') ||
@@ -63,7 +84,15 @@ export class DetectionService {
63
84
  sessionLogVerbosityLevel: 0,
64
85
  };
65
86
  try {
66
- this.session = await window.ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);
87
+ // Retry with fallback options and abort signal
88
+ const fallbackResponse = await fetch(this.MODEL_PATH, {
89
+ signal: this.modelLoadController.signal
90
+ });
91
+ if (!fallbackResponse.ok) {
92
+ throw new Error(`Failed to fetch model with fallback: ${fallbackResponse.status}`);
93
+ }
94
+ const fallbackBuffer = await fallbackResponse.arrayBuffer();
95
+ this.session = await window.ort.InferenceSession.create(fallbackBuffer, fallbackOptions);
67
96
  }
68
97
  catch (fallbackError) {
69
98
  throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);
@@ -84,9 +113,13 @@ export class DetectionService {
84
113
  return;
85
114
  }
86
115
  try {
116
+ // Create AbortController for classification model loading
117
+ this.classificationLoadController = new AbortController();
87
118
  // Try to load class map (optional - SqueezeNet may not need it for basic classification)
88
119
  try {
89
- const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
120
+ const classResponse = await fetch(this.MOBILENET_CLASSES_PATH, {
121
+ signal: this.classificationLoadController.signal
122
+ });
90
123
  if (classResponse.ok) {
91
124
  this.mobileNetClassMap = await classResponse.json();
92
125
  }
@@ -104,9 +137,22 @@ export class DetectionService {
104
137
  // Load model
105
138
  const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
106
139
  try {
107
- this.mobileNetSession = await window.ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);
140
+ // Load classification model with abort signal support
141
+ const response = await fetch(this.MOBILENET_MODEL_PATH, {
142
+ signal: this.classificationLoadController.signal
143
+ });
144
+ if (!response.ok) {
145
+ throw new Error(`Failed to fetch classification model: ${response.status}`);
146
+ }
147
+ const modelBuffer = await response.arrayBuffer();
148
+ this.mobileNetSession = await window.ort.InferenceSession.create(modelBuffer, sessionOptions);
108
149
  }
109
150
  catch (error) {
151
+ // Handle abort signal
152
+ if (error.name === 'AbortError') {
153
+ console.log('Classification model loading was cancelled');
154
+ return;
155
+ }
110
156
  // Múltiples tipos de errores de memoria que pueden ocurrir
111
157
  const isMemoryError = error.message.includes('failed to allocate a buffer') ||
112
158
  error.message.includes('Out of memory') ||
@@ -128,7 +174,15 @@ export class DetectionService {
128
174
  sessionLogVerbosityLevel: 0,
129
175
  };
130
176
  try {
131
- this.mobileNetSession = await window.ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);
177
+ // Retry with fallback options and abort signal
178
+ const fallbackResponse = await fetch(this.MOBILENET_MODEL_PATH, {
179
+ signal: this.classificationLoadController.signal
180
+ });
181
+ if (!fallbackResponse.ok) {
182
+ throw new Error(`Failed to fetch classification model with fallback: ${fallbackResponse.status}`);
183
+ }
184
+ const fallbackBuffer = await fallbackResponse.arrayBuffer();
185
+ this.mobileNetSession = await window.ort.InferenceSession.create(fallbackBuffer, fallbackOptions);
132
186
  }
133
187
  catch (fallbackError) {
134
188
  throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);
@@ -318,6 +372,9 @@ export class DetectionService {
318
372
  return alignment.top && alignment.right && alignment.bottom && alignment.left;
319
373
  }
320
374
  cleanup() {
375
+ // Cancel any ongoing requests
376
+ this.abortPendingRequests();
377
+ // Cleanup ONNX resources
321
378
  this.cleanupCanvasPool();
322
379
  if (this.session) {
323
380
  this.session.release?.();
@@ -329,6 +386,8 @@ export class DetectionService {
329
386
  }
330
387
  this.mobileNetClassMap = undefined;
331
388
  this.modelLoaded = false;
389
+ // Cleanup blob URLs
390
+ this.revokeModelBlobUrls();
332
391
  }
333
392
  initializeCanvasPool() {
334
393
  this.preprocessCanvas = document.createElement('canvas');
@@ -426,11 +485,93 @@ export class DetectionService {
426
485
  const pool = DetectionService.canvasPool.get(key);
427
486
  // Only return to pool if not at max capacity
428
487
  if (pool.length < DetectionService.MAX_POOL_SIZE) {
488
+ const ctx = canvas.getContext('2d');
489
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
429
490
  pool.push(canvas);
430
491
  }
492
+ // If pool is full, let the canvas be garbage collected
493
+ }
494
+ // Resource management methods for cache and browser optimization
495
+ async clearModelCache() {
496
+ try {
497
+ // Clear cache specific to models
498
+ const cacheNames = await caches.keys();
499
+ const modelCaches = cacheNames.filter(name => name.includes('onnx') ||
500
+ name.includes('jaak-static') ||
501
+ name.includes('squeezenet') ||
502
+ name.includes('ddmyp'));
503
+ await Promise.all(modelCaches.map(cacheName => caches.delete(cacheName)));
504
+ if (this.debug) {
505
+ console.log(`🧹 Cleared ${modelCaches.length} model caches`);
506
+ }
507
+ }
508
+ catch (error) {
509
+ console.warn('Error clearing model cache:', error);
510
+ }
511
+ }
512
+ abortPendingRequests() {
513
+ // Cancel any fetch in progress
514
+ if (this.modelLoadController) {
515
+ this.modelLoadController.abort();
516
+ this.modelLoadController = undefined;
517
+ }
518
+ if (this.classificationLoadController) {
519
+ this.classificationLoadController.abort();
520
+ this.classificationLoadController = undefined;
521
+ }
522
+ }
523
+ revokeModelBlobUrls() {
524
+ // Revoke any blob URLs created for models
525
+ this.modelBlobUrls.forEach(url => URL.revokeObjectURL(url));
526
+ this.modelBlobUrls.clear();
431
527
  }
432
- // Static method to clear all canvas pools (useful for memory management)
433
- static clearCanvasPools() {
528
+ // Progressive resource release for optimization
529
+ async releaseMobileNetResources() {
530
+ if (this.mobileNetSession) {
531
+ this.mobileNetSession.release?.();
532
+ this.mobileNetSession = undefined;
533
+ }
534
+ this.mobileNetClassMap = undefined;
535
+ if (this.classificationLoadController) {
536
+ this.classificationLoadController.abort();
537
+ this.classificationLoadController = undefined;
538
+ }
539
+ if (this.debug) {
540
+ console.log('🧹 Released MobileNet classification resources');
541
+ }
542
+ }
543
+ // Optimize canvas pool by reducing to specific size
544
+ optimizeCanvasPool(maxSize) {
545
+ DetectionService.canvasPool.forEach((pool, key) => {
546
+ while (pool.length > maxSize) {
547
+ const canvas = pool.pop();
548
+ // Explicitly clear and nullify for garbage collection
549
+ if (canvas) {
550
+ const ctx = canvas.getContext('2d');
551
+ if (ctx) {
552
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
553
+ }
554
+ }
555
+ }
556
+ if (pool.length === 0) {
557
+ DetectionService.canvasPool.delete(key);
558
+ }
559
+ });
560
+ if (this.debug) {
561
+ console.log(`🧹 Optimized canvas pool to max size: ${maxSize}`);
562
+ }
563
+ }
564
+ // Clear all static canvas pools
565
+ static clearAllCanvasPools() {
566
+ DetectionService.canvasPool.forEach((pool) => {
567
+ pool.forEach(canvas => {
568
+ const ctx = canvas.getContext('2d');
569
+ if (ctx) {
570
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
571
+ }
572
+ });
573
+ pool.length = 0;
574
+ });
434
575
  DetectionService.canvasPool.clear();
435
576
  }
436
577
  // Method to get pool statistics for debugging
@@ -1 +1 @@
1
- {"version":3,"file":"DetectionService.js","sourceRoot":"","sources":["../../src/services/DetectionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { IDetectionService, DetectionBox, SideAlignment, ClassificationResult } from './interfaces/IDetectionService';\nimport { IDeviceStrategy } from './strategies/IDeviceStrategy';\nimport { DeviceStrategyFactory } from './factories/DeviceStrategyFactory';\n\nexport class DetectionService implements IDetectionService {\n private session?: any;\n private mobileNetSession?: any;\n private mobileNetClassMap?: any;\n private modelLoaded: boolean = false;\n private deviceStrategy: IDeviceStrategy;\n\n private readonly MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx\";\n private readonly MOBILENET_MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/squeezenet_new_fp32.onnx\";\n private readonly MOBILENET_CLASSES_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json\";\n private readonly INPUT_SIZE = 320;\n private readonly CONFIDENCE_THRESHOLD = 0.6;\n\n // Canvas pool for optimization\n private preprocessCanvas?: HTMLCanvasElement;\n private preprocessCtx?: CanvasRenderingContext2D;\n private captureCanvas?: HTMLCanvasElement;\n \n // Static canvas pool for reuse across instances\n private static canvasPool = new Map<string, HTMLCanvasElement[]>();\n private static readonly MAX_POOL_SIZE = 5;\n\n constructor(\n private debug: boolean = false,\n private useDocumentClassification: boolean = false,\n private useDocumentDetector: boolean = true\n ) {\n this.deviceStrategy = DeviceStrategyFactory.createStrategy();\n this.initializeCanvasPool();\n }\n\n async loadModel(): Promise<void> {\n if (this.modelLoaded || this.session) {\n return;\n }\n\n if (!this.useDocumentDetector) {\n // Skip loading the detection model but mark as \"loaded\" for compatibility\n this.modelLoaded = true;\n return;\n }\n\n try {\n\n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n\n try {\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, sessionOptions);\n } catch (error) {\n // Múltiples tipos de errores de memoria que pueden ocurrir\n const isMemoryError = error.message.includes('failed to allocate a buffer') ||\n error.message.includes('Out of memory') ||\n error.message.includes('RangeError: Out of memory') ||\n error.message.includes('no available backend found');\n \n if (isMemoryError) {\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n // Configuraciones adicionales para dispositivos con poca memoria\n enableProfiling: false,\n sessionLogSeverityLevel: 4,\n sessionLogVerbosityLevel: 0,\n };\n \n try {\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);\n } catch (fallbackError) {\n throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);\n }\n } else {\n throw error;\n }\n }\n\n this.modelLoaded = true;\n } catch (error) {\n throw error;\n }\n }\n\n async loadClassificationModel(): Promise<void> {\n if (!this.useDocumentClassification) {\n return;\n }\n\n try {\n\n // Try to load class map (optional - SqueezeNet may not need it for basic classification)\n try {\n const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);\n if (classResponse.ok) {\n this.mobileNetClassMap = await classResponse.json();\n }\n } catch (error) {\n // Create a basic class map for document types\n this.mobileNetClassMap = {\n \"0\": \"document\",\n \"1\": \"id_card\",\n \"2\": \"passport\",\n \"3\": \"license\",\n \"4\": \"other\"\n };\n }\n\n // Load model\n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n try {\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);\n } catch (error) {\n // Múltiples tipos de errores de memoria que pueden ocurrir\n const isMemoryError = error.message.includes('failed to allocate a buffer') ||\n error.message.includes('Out of memory') ||\n error.message.includes('RangeError: Out of memory') ||\n error.message.includes('no available backend found');\n \n if (isMemoryError) {\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n // Configuraciones adicionales para dispositivos con poca memoria\n enableProfiling: false,\n sessionLogSeverityLevel: 4,\n sessionLogVerbosityLevel: 0,\n };\n \n try {\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);\n } catch (fallbackError) {\n throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);\n }\n } else {\n throw error;\n }\n }\n\n } catch (error) {\n throw error;\n }\n }\n\n isModelLoaded(): boolean {\n if (!this.useDocumentDetector) {\n // If detector is disabled, consider it \"loaded\" for compatibility\n return this.modelLoaded;\n }\n return this.modelLoaded && !!this.session;\n }\n\n preprocess(video: HTMLVideoElement): any {\n if (!this.preprocessCanvas || !this.preprocessCtx) {\n this.initializeCanvasPool();\n }\n\n this.preprocessCtx!.clearRect(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n this.preprocessCtx!.drawImage(video, 0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n\n const imageData = this.preprocessCtx!.getImageData(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n const [R, G, B] = [[], [], []] as number[][];\n const { data } = imageData;\n\n for (let i = 0; i < data.length; i += 4) {\n R.push(data[i] / 255);\n G.push(data[i + 1] / 255);\n B.push(data[i + 2] / 255);\n }\n\n const transposedData = new Float32Array(R.concat(G, B));\n const float16Data = new Uint16Array(transposedData.length);\n for (let i = 0; i < transposedData.length; i++) {\n float16Data[i] = this.float32ToFloat16(transposedData[i]);\n }\n return new (window as any).ort.Tensor(\"float16\", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);\n }\n\n async runInference(inputTensor: any): Promise<DetectionBox[]> {\n if (!this.useDocumentDetector) {\n // Return empty array when document detector is disabled\n return [];\n }\n\n if (!this.session) {\n throw new Error('Detection model not loaded');\n }\n\n const feeds = { [this.session.inputNames[0]]: inputTensor };\n const results = await this.session.run(feeds);\n const output = results[this.session.outputNames[0]].data;\n\n const detections: DetectionBox[] = [];\n for (let i = 0; i < output.length; i += 6) {\n const [x1, y1, x2, y2, score, classId] = output.slice(i, i + 6);\n if (score > this.CONFIDENCE_THRESHOLD) {\n detections.push({\n x: x1,\n y: y1,\n w: x2 - x1,\n h: y2 - y1,\n score,\n classId\n });\n }\n }\n\n return detections;\n }\n\n async classifyDocument(canvas: HTMLCanvasElement): Promise<ClassificationResult | null> {\n if (!this.mobileNetSession || !this.mobileNetClassMap) {\n return null;\n }\n\n try {\n\n const inputTensor = this.preprocessMobileNet(canvas);\n const feeds = { [this.mobileNetSession.inputNames[0]]: inputTensor };\n const results = await this.mobileNetSession.run(feeds);\n const output = results[Object.keys(results)[0]].data;\n\n const maxIdx = output.reduce((bestIdx: number, val: number, idx: number, arr: number[]) =>\n val > arr[bestIdx] ? idx : bestIdx, 0);\n const confidence = output[maxIdx];\n\n const className = this.mobileNetClassMap[maxIdx.toString()] || \"unknown\";\n\n\n return {\n class: className,\n confidence: confidence,\n classIndex: maxIdx\n };\n\n } catch (error) {\n return null;\n }\n }\n\n checkSideAlignment(box: DetectionBox, maskConfig: any): SideAlignment {\n const { INPUT_SIZE, ID1_ASPECT_RATIO, shouldMirrorVideo, alignmentTolerance, maskSize, videoRef } = maskConfig;\n\n if (!videoRef) {\n return { top: false, right: false, bottom: false, left: false };\n }\n\n // Get video dimensions to calculate actual mask boundaries in model space\n const videoWidth = videoRef.videoWidth;\n const videoHeight = videoRef.videoHeight;\n\n if (videoWidth === 0 || videoHeight === 0) {\n return { top: false, right: false, bottom: false, left: false };\n }\n\n // Calculate video aspect ratio\n const videoAspectRatio = videoWidth / videoHeight;\n\n // The model sees video stretched to 320x320, but we need to calculate where\n // the mask should be in this distorted space to match the visual mask\n\n // In the visual display, we calculate mask size based on the limiting dimension\n // We need to replicate this logic but account for the distortion in model space\n\n // Calculate the \"display\" dimensions (what the visual mask calculations use)\n const containerAspectRatio = 1; // Assume square container for simplicity\n let displayedVideoWidth, displayedVideoHeight;\n\n if (videoAspectRatio > containerAspectRatio) {\n // Video is wider - letterboxed in display\n displayedVideoWidth = INPUT_SIZE;\n displayedVideoHeight = INPUT_SIZE / videoAspectRatio;\n } else {\n // Video is taller - pillarboxed in display\n displayedVideoHeight = INPUT_SIZE;\n displayedVideoWidth = INPUT_SIZE * videoAspectRatio;\n }\n\n // Calculate mask dimensions using the same logic as updateMaskDimensions\n const maxWidthByHeight = displayedVideoHeight * ID1_ASPECT_RATIO;\n\n let visualMaskWidth, visualMaskHeight;\n const sizeRatio = maskSize / 100;\n\n if (maxWidthByHeight <= displayedVideoWidth) {\n // Video height is the limiting factor\n visualMaskHeight = displayedVideoHeight * sizeRatio;\n visualMaskWidth = visualMaskHeight * ID1_ASPECT_RATIO;\n } else {\n // Video width is the limiting factor\n visualMaskWidth = displayedVideoWidth * sizeRatio;\n visualMaskHeight = visualMaskWidth / ID1_ASPECT_RATIO;\n }\n\n // Now map these visual mask dimensions to the distorted model space\n // The model stretches video to 320x320, so we need to apply the inverse transformation\n const modelMaskWidth = visualMaskWidth * (INPUT_SIZE / displayedVideoWidth);\n const modelMaskHeight = visualMaskHeight * (INPUT_SIZE / displayedVideoHeight);\n\n // Calculate mask boundaries in model coordinate system (always centered in 320x320)\n const maskCenterX = INPUT_SIZE / 2;\n const maskCenterY = INPUT_SIZE / 2;\n const maskLeft = maskCenterX - (modelMaskWidth / 2);\n const maskRight = maskCenterX + (modelMaskWidth / 2);\n const maskTop = maskCenterY - (modelMaskHeight / 2);\n const maskBottom = maskCenterY + (modelMaskHeight / 2);\n\n // Obtener las coordenadas del documento detectado\n let docLeft = box.x;\n let docRight = box.x + box.w;\n const docTop = box.y;\n const docBottom = box.y + box.h;\n\n // Si el video está en modo mirror, invertir las coordenadas horizontales\n if (shouldMirrorVideo) {\n const originalDocLeft = docLeft;\n const originalDocRight = docRight;\n docLeft = INPUT_SIZE - originalDocRight;\n docRight = INPUT_SIZE - originalDocLeft;\n }\n\n // Tolerancia para considerar que un lado está alineado (en píxeles)\n const tolerance = alignmentTolerance;\n\n // Verificar alineación de esquinas más estricta\n // Una esquina está alineada solo si AMBOS bordes que la forman están alineados\n const topAligned = Math.abs(docTop - maskTop) <= tolerance;\n const rightAligned = Math.abs(docRight - maskRight) <= tolerance;\n const bottomAligned = Math.abs(docBottom - maskBottom) <= tolerance;\n const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;\n\n return {\n top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados\n right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados\n bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados\n left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados\n };\n }\n\n isCardInFrame(box: DetectionBox): boolean {\n const cardCenterX = box.x + box.w / 2;\n const cardCenterY = box.y + box.h / 2;\n const frameCenterX = this.INPUT_SIZE / 2;\n const frameCenterY = this.INPUT_SIZE / 2;\n const toleranceX = 40;\n const toleranceY = 30;\n\n const isCentered = Math.abs(cardCenterX - frameCenterX) < toleranceX &&\n Math.abs(cardCenterY - frameCenterY) < toleranceY;\n const isGoodSize = box.w > 150 && box.w < 300 && box.h > 90 && box.h < 200;\n\n return isCentered && isGoodSize;\n }\n\n areAllSidesAligned(alignment: SideAlignment): boolean {\n return alignment.top && alignment.right && alignment.bottom && alignment.left;\n }\n\n cleanup(): void {\n this.cleanupCanvasPool();\n\n if (this.session) {\n this.session.release?.();\n this.session = undefined;\n }\n if (this.mobileNetSession) {\n this.mobileNetSession.release?.();\n this.mobileNetSession = undefined;\n }\n this.mobileNetClassMap = undefined;\n this.modelLoaded = false;\n\n }\n\n private initializeCanvasPool(): void {\n this.preprocessCanvas = document.createElement('canvas');\n this.preprocessCanvas.width = this.INPUT_SIZE;\n this.preprocessCanvas.height = this.INPUT_SIZE;\n this.preprocessCtx = this.preprocessCanvas.getContext('2d', {\n alpha: false,\n willReadFrequently: true\n })!;\n\n this.captureCanvas = document.createElement('canvas');\n\n }\n\n private cleanupCanvasPool(): void {\n if (this.preprocessCanvas) {\n this.preprocessCtx = undefined;\n this.preprocessCanvas = undefined;\n }\n if (this.captureCanvas) {\n this.captureCanvas = undefined;\n }\n }\n\n private float32ToFloat16(value: number): number {\n const buffer = new ArrayBuffer(4);\n const view = new DataView(buffer);\n view.setFloat32(0, value, true);\n\n const f = view.getUint32(0, true);\n const sign = (f >> 31) & 0x1;\n const exp = (f >> 23) & 0xFF;\n const frac = f & 0x7FFFFF;\n\n let newExp = exp - 127 + 15;\n\n if (exp === 0) {\n newExp = 0;\n } else if (exp === 0xFF) {\n newExp = 0x1F;\n } else if (newExp >= 0x1F) {\n newExp = 0x1F;\n return (sign << 15) | (newExp << 10);\n } else if (newExp <= 0) {\n return (sign << 15);\n }\n\n return (sign << 15) | (newExp << 10) | (frac >> 13);\n }\n\n private preprocessMobileNet(canvas: HTMLCanvasElement): any {\n // Use pooled canvas instead of creating new one\n const tempCanvas = this.getCanvas(224, 224);\n const tempCtx = tempCanvas.getContext('2d')!;\n\n // Clear canvas before use\n tempCtx.clearRect(0, 0, 224, 224);\n \n // Resize image to 224x224 for SqueezeNet (using MobileNet interface)\n tempCtx.drawImage(canvas, 0, 0, 224, 224);\n\n const imageData = tempCtx.getImageData(0, 0, 224, 224);\n const data = imageData.data;\n const hw = 224 * 224;\n const arr = new Float32Array(3 * hw);\n\n // SqueezeNet preprocessing: normalize to [0,1] range and arrange in CHW format\n for (let i = 0; i < hw; i++) {\n // Red channel\n arr[i] = data[i * 4 + 0] / 255.0;\n // Green channel\n arr[hw + i] = data[i * 4 + 1] / 255.0;\n // Blue channel\n arr[2 * hw + i] = data[i * 4 + 2] / 255.0;\n }\n\n // Return canvas to pool after use\n this.returnCanvas(tempCanvas);\n\n return new (window as any).ort.Tensor('float32', arr, [1, 3, 224, 224]);\n }\n\n // Canvas pool management methods for optimization\n private getCanvas(width: number, height: number): HTMLCanvasElement {\n const key = `${width}x${height}`;\n if (!DetectionService.canvasPool.has(key)) {\n DetectionService.canvasPool.set(key, []);\n }\n const pool = DetectionService.canvasPool.get(key)!;\n \n let canvas = pool.pop();\n if (!canvas) {\n canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n } else {\n // Clear the canvas before reuse\n const ctx = canvas.getContext('2d')!;\n ctx.clearRect(0, 0, width, height);\n }\n \n return canvas;\n }\n\n private returnCanvas(canvas: HTMLCanvasElement): void {\n const key = `${canvas.width}x${canvas.height}`;\n if (!DetectionService.canvasPool.has(key)) {\n DetectionService.canvasPool.set(key, []);\n }\n const pool = DetectionService.canvasPool.get(key)!;\n \n // Only return to pool if not at max capacity\n if (pool.length < DetectionService.MAX_POOL_SIZE) {\n pool.push(canvas);\n }\n }\n\n // Static method to clear all canvas pools (useful for memory management)\n public static clearCanvasPools(): void {\n DetectionService.canvasPool.clear();\n }\n\n // Method to get pool statistics for debugging\n public getPoolStats(): { [key: string]: number } {\n const stats: { [key: string]: number } = {};\n DetectionService.canvasPool.forEach((pool, key) => {\n stats[key] = pool.length;\n });\n return stats;\n }\n\n}\n"]}
1
+ {"version":3,"file":"DetectionService.js","sourceRoot":"","sources":["../../src/services/DetectionService.ts"],"names":[],"mappings":"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","sourcesContent":["import { IDetectionService, DetectionBox, SideAlignment, ClassificationResult } from './interfaces/IDetectionService';\nimport { IDeviceStrategy } from './strategies/IDeviceStrategy';\nimport { DeviceStrategyFactory } from './factories/DeviceStrategyFactory';\n\nexport class DetectionService implements IDetectionService {\n private session?: any;\n private mobileNetSession?: any;\n private mobileNetClassMap?: any;\n private modelLoaded: boolean = false;\n private deviceStrategy: IDeviceStrategy;\n\n private readonly MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx\";\n private readonly MOBILENET_MODEL_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/squeezenet_new_fp32.onnx\";\n private readonly MOBILENET_CLASSES_PATH = \"https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json\";\n private readonly INPUT_SIZE = 320;\n private readonly CONFIDENCE_THRESHOLD = 0.6;\n\n // Canvas pool for optimization\n private preprocessCanvas?: HTMLCanvasElement;\n private preprocessCtx?: CanvasRenderingContext2D;\n private captureCanvas?: HTMLCanvasElement;\n \n // Static canvas pool for reuse across instances\n private static canvasPool = new Map<string, HTMLCanvasElement[]>();\n private static readonly MAX_POOL_SIZE = 5;\n\n // Resource management for optimization\n private modelLoadController?: AbortController;\n private classificationLoadController?: AbortController;\n private modelBlobUrls = new Set<string>();\n\n constructor(\n private debug: boolean = false,\n private useDocumentClassification: boolean = false,\n private useDocumentDetector: boolean = true\n ) {\n this.deviceStrategy = DeviceStrategyFactory.createStrategy();\n this.initializeCanvasPool();\n }\n\n async loadModel(): Promise<void> {\n if (this.modelLoaded || this.session) {\n return;\n }\n\n if (!this.useDocumentDetector) {\n // Skip loading the detection model but mark as \"loaded\" for compatibility\n this.modelLoaded = true;\n return;\n }\n\n try {\n if (typeof (window as any).ort === 'undefined') {\n throw new Error('ONNX Runtime not available in window object');\n }\n \n // Create AbortController for this load operation\n this.modelLoadController = new AbortController();\n\n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n\n try {\n // Load model with abort signal support\n const response = await fetch(this.MODEL_PATH, {\n signal: this.modelLoadController.signal\n });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch model: ${response.status}`);\n }\n \n const modelBuffer = await response.arrayBuffer();\n this.session = await (window as any).ort.InferenceSession.create(modelBuffer, sessionOptions);\n } catch (error) {\n // Handle abort signal\n if (error.name === 'AbortError') {\n return;\n }\n \n // Múltiples tipos de errores de memoria que pueden ocurrir\n const isMemoryError = error.message.includes('failed to allocate a buffer') ||\n error.message.includes('Out of memory') ||\n error.message.includes('RangeError: Out of memory') ||\n error.message.includes('no available backend found');\n \n if (isMemoryError) {\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n // Configuraciones adicionales para dispositivos con poca memoria\n enableProfiling: false,\n sessionLogSeverityLevel: 4,\n sessionLogVerbosityLevel: 0,\n };\n \n try {\n // Retry with fallback options and abort signal\n const fallbackResponse = await fetch(this.MODEL_PATH, {\n signal: this.modelLoadController.signal\n });\n \n if (!fallbackResponse.ok) {\n throw new Error(`Failed to fetch model with fallback: ${fallbackResponse.status}`);\n }\n \n const fallbackBuffer = await fallbackResponse.arrayBuffer();\n this.session = await (window as any).ort.InferenceSession.create(fallbackBuffer, fallbackOptions);\n } catch (fallbackError) {\n throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);\n }\n } else {\n throw error;\n }\n }\n\n this.modelLoaded = true;\n } catch (error) {\n throw error;\n }\n }\n\n async loadClassificationModel(): Promise<void> {\n if (!this.useDocumentClassification) {\n return;\n }\n\n try {\n // Create AbortController for classification model loading\n this.classificationLoadController = new AbortController();\n\n // Try to load class map (optional - SqueezeNet may not need it for basic classification)\n try {\n const classResponse = await fetch(this.MOBILENET_CLASSES_PATH, {\n signal: this.classificationLoadController.signal\n });\n if (classResponse.ok) {\n this.mobileNetClassMap = await classResponse.json();\n }\n } catch (error) {\n // Create a basic class map for document types\n this.mobileNetClassMap = {\n \"0\": \"document\",\n \"1\": \"id_card\",\n \"2\": \"passport\",\n \"3\": \"license\",\n \"4\": \"other\"\n };\n }\n\n // Load model\n const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);\n try {\n // Load classification model with abort signal support\n const response = await fetch(this.MOBILENET_MODEL_PATH, {\n signal: this.classificationLoadController.signal\n });\n \n if (!response.ok) {\n throw new Error(`Failed to fetch classification model: ${response.status}`);\n }\n \n const modelBuffer = await response.arrayBuffer();\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(modelBuffer, sessionOptions);\n } catch (error) {\n // Handle abort signal\n if (error.name === 'AbortError') {\n console.log('Classification model loading was cancelled');\n return;\n }\n \n // Múltiples tipos de errores de memoria que pueden ocurrir\n const isMemoryError = error.message.includes('failed to allocate a buffer') ||\n error.message.includes('Out of memory') ||\n error.message.includes('RangeError: Out of memory') ||\n error.message.includes('no available backend found');\n \n if (isMemoryError) {\n const fallbackOptions = {\n executionProviders: ['wasm'],\n graphOptimizationLevel: 'disabled',\n logSeverityLevel: 4,\n enableCpuMemArena: false,\n enableMemPattern: false,\n executionMode: 'sequential',\n interOpNumThreads: 1,\n intraOpNumThreads: 1,\n // Configuraciones adicionales para dispositivos con poca memoria\n enableProfiling: false,\n sessionLogSeverityLevel: 4,\n sessionLogVerbosityLevel: 0,\n };\n \n try {\n // Retry with fallback options and abort signal\n const fallbackResponse = await fetch(this.MOBILENET_MODEL_PATH, {\n signal: this.classificationLoadController.signal\n });\n \n if (!fallbackResponse.ok) {\n throw new Error(`Failed to fetch classification model with fallback: ${fallbackResponse.status}`);\n }\n \n const fallbackBuffer = await fallbackResponse.arrayBuffer();\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(fallbackBuffer, fallbackOptions);\n } catch (fallbackError) {\n throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);\n }\n } else {\n throw error;\n }\n }\n\n } catch (error) {\n throw error;\n }\n }\n\n isModelLoaded(): boolean {\n if (!this.useDocumentDetector) {\n // If detector is disabled, consider it \"loaded\" for compatibility\n return this.modelLoaded;\n }\n return this.modelLoaded && !!this.session;\n }\n\n preprocess(video: HTMLVideoElement): any {\n if (!this.preprocessCanvas || !this.preprocessCtx) {\n this.initializeCanvasPool();\n }\n\n this.preprocessCtx!.clearRect(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n this.preprocessCtx!.drawImage(video, 0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n\n const imageData = this.preprocessCtx!.getImageData(0, 0, this.INPUT_SIZE, this.INPUT_SIZE);\n const [R, G, B] = [[], [], []] as number[][];\n const { data } = imageData;\n\n for (let i = 0; i < data.length; i += 4) {\n R.push(data[i] / 255);\n G.push(data[i + 1] / 255);\n B.push(data[i + 2] / 255);\n }\n\n const transposedData = new Float32Array(R.concat(G, B));\n const float16Data = new Uint16Array(transposedData.length);\n for (let i = 0; i < transposedData.length; i++) {\n float16Data[i] = this.float32ToFloat16(transposedData[i]);\n }\n return new (window as any).ort.Tensor(\"float16\", float16Data, [1, 3, this.INPUT_SIZE, this.INPUT_SIZE]);\n }\n\n async runInference(inputTensor: any): Promise<DetectionBox[]> {\n if (!this.useDocumentDetector) {\n // Return empty array when document detector is disabled\n return [];\n }\n\n if (!this.session) {\n throw new Error('Detection model not loaded');\n }\n\n const feeds = { [this.session.inputNames[0]]: inputTensor };\n const results = await this.session.run(feeds);\n const output = results[this.session.outputNames[0]].data;\n\n const detections: DetectionBox[] = [];\n for (let i = 0; i < output.length; i += 6) {\n const [x1, y1, x2, y2, score, classId] = output.slice(i, i + 6);\n if (score > this.CONFIDENCE_THRESHOLD) {\n detections.push({\n x: x1,\n y: y1,\n w: x2 - x1,\n h: y2 - y1,\n score,\n classId\n });\n }\n }\n\n return detections;\n }\n\n async classifyDocument(canvas: HTMLCanvasElement): Promise<ClassificationResult | null> {\n if (!this.mobileNetSession || !this.mobileNetClassMap) {\n return null;\n }\n\n try {\n\n const inputTensor = this.preprocessMobileNet(canvas);\n const feeds = { [this.mobileNetSession.inputNames[0]]: inputTensor };\n const results = await this.mobileNetSession.run(feeds);\n const output = results[Object.keys(results)[0]].data;\n\n const maxIdx = output.reduce((bestIdx: number, val: number, idx: number, arr: number[]) =>\n val > arr[bestIdx] ? idx : bestIdx, 0);\n const confidence = output[maxIdx];\n\n const className = this.mobileNetClassMap[maxIdx.toString()] || \"unknown\";\n\n\n return {\n class: className,\n confidence: confidence,\n classIndex: maxIdx\n };\n\n } catch (error) {\n return null;\n }\n }\n\n checkSideAlignment(box: DetectionBox, maskConfig: any): SideAlignment {\n const { INPUT_SIZE, ID1_ASPECT_RATIO, shouldMirrorVideo, alignmentTolerance, maskSize, videoRef } = maskConfig;\n\n if (!videoRef) {\n return { top: false, right: false, bottom: false, left: false };\n }\n\n // Get video dimensions to calculate actual mask boundaries in model space\n const videoWidth = videoRef.videoWidth;\n const videoHeight = videoRef.videoHeight;\n\n if (videoWidth === 0 || videoHeight === 0) {\n return { top: false, right: false, bottom: false, left: false };\n }\n\n // Calculate video aspect ratio\n const videoAspectRatio = videoWidth / videoHeight;\n\n // The model sees video stretched to 320x320, but we need to calculate where\n // the mask should be in this distorted space to match the visual mask\n\n // In the visual display, we calculate mask size based on the limiting dimension\n // We need to replicate this logic but account for the distortion in model space\n\n // Calculate the \"display\" dimensions (what the visual mask calculations use)\n const containerAspectRatio = 1; // Assume square container for simplicity\n let displayedVideoWidth, displayedVideoHeight;\n\n if (videoAspectRatio > containerAspectRatio) {\n // Video is wider - letterboxed in display\n displayedVideoWidth = INPUT_SIZE;\n displayedVideoHeight = INPUT_SIZE / videoAspectRatio;\n } else {\n // Video is taller - pillarboxed in display\n displayedVideoHeight = INPUT_SIZE;\n displayedVideoWidth = INPUT_SIZE * videoAspectRatio;\n }\n\n // Calculate mask dimensions using the same logic as updateMaskDimensions\n const maxWidthByHeight = displayedVideoHeight * ID1_ASPECT_RATIO;\n\n let visualMaskWidth, visualMaskHeight;\n const sizeRatio = maskSize / 100;\n\n if (maxWidthByHeight <= displayedVideoWidth) {\n // Video height is the limiting factor\n visualMaskHeight = displayedVideoHeight * sizeRatio;\n visualMaskWidth = visualMaskHeight * ID1_ASPECT_RATIO;\n } else {\n // Video width is the limiting factor\n visualMaskWidth = displayedVideoWidth * sizeRatio;\n visualMaskHeight = visualMaskWidth / ID1_ASPECT_RATIO;\n }\n\n // Now map these visual mask dimensions to the distorted model space\n // The model stretches video to 320x320, so we need to apply the inverse transformation\n const modelMaskWidth = visualMaskWidth * (INPUT_SIZE / displayedVideoWidth);\n const modelMaskHeight = visualMaskHeight * (INPUT_SIZE / displayedVideoHeight);\n\n // Calculate mask boundaries in model coordinate system (always centered in 320x320)\n const maskCenterX = INPUT_SIZE / 2;\n const maskCenterY = INPUT_SIZE / 2;\n const maskLeft = maskCenterX - (modelMaskWidth / 2);\n const maskRight = maskCenterX + (modelMaskWidth / 2);\n const maskTop = maskCenterY - (modelMaskHeight / 2);\n const maskBottom = maskCenterY + (modelMaskHeight / 2);\n\n // Obtener las coordenadas del documento detectado\n let docLeft = box.x;\n let docRight = box.x + box.w;\n const docTop = box.y;\n const docBottom = box.y + box.h;\n\n // Si el video está en modo mirror, invertir las coordenadas horizontales\n if (shouldMirrorVideo) {\n const originalDocLeft = docLeft;\n const originalDocRight = docRight;\n docLeft = INPUT_SIZE - originalDocRight;\n docRight = INPUT_SIZE - originalDocLeft;\n }\n\n // Tolerancia para considerar que un lado está alineado (en píxeles)\n const tolerance = alignmentTolerance;\n\n // Verificar alineación de esquinas más estricta\n // Una esquina está alineada solo si AMBOS bordes que la forman están alineados\n const topAligned = Math.abs(docTop - maskTop) <= tolerance;\n const rightAligned = Math.abs(docRight - maskRight) <= tolerance;\n const bottomAligned = Math.abs(docBottom - maskBottom) <= tolerance;\n const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;\n\n return {\n top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados\n right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados\n bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados\n left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados\n };\n }\n\n isCardInFrame(box: DetectionBox): boolean {\n const cardCenterX = box.x + box.w / 2;\n const cardCenterY = box.y + box.h / 2;\n const frameCenterX = this.INPUT_SIZE / 2;\n const frameCenterY = this.INPUT_SIZE / 2;\n const toleranceX = 40;\n const toleranceY = 30;\n\n const isCentered = Math.abs(cardCenterX - frameCenterX) < toleranceX &&\n Math.abs(cardCenterY - frameCenterY) < toleranceY;\n const isGoodSize = box.w > 150 && box.w < 300 && box.h > 90 && box.h < 200;\n\n return isCentered && isGoodSize;\n }\n\n areAllSidesAligned(alignment: SideAlignment): boolean {\n return alignment.top && alignment.right && alignment.bottom && alignment.left;\n }\n\n cleanup(): void {\n // Cancel any ongoing requests\n this.abortPendingRequests();\n \n // Cleanup ONNX resources\n this.cleanupCanvasPool();\n\n if (this.session) {\n this.session.release?.();\n this.session = undefined;\n }\n if (this.mobileNetSession) {\n this.mobileNetSession.release?.();\n this.mobileNetSession = undefined;\n }\n this.mobileNetClassMap = undefined;\n this.modelLoaded = false;\n\n // Cleanup blob URLs\n this.revokeModelBlobUrls();\n }\n\n private initializeCanvasPool(): void {\n this.preprocessCanvas = document.createElement('canvas');\n this.preprocessCanvas.width = this.INPUT_SIZE;\n this.preprocessCanvas.height = this.INPUT_SIZE;\n this.preprocessCtx = this.preprocessCanvas.getContext('2d', {\n alpha: false,\n willReadFrequently: true\n })!;\n\n this.captureCanvas = document.createElement('canvas');\n\n }\n\n private cleanupCanvasPool(): void {\n if (this.preprocessCanvas) {\n this.preprocessCtx = undefined;\n this.preprocessCanvas = undefined;\n }\n if (this.captureCanvas) {\n this.captureCanvas = undefined;\n }\n }\n\n private float32ToFloat16(value: number): number {\n const buffer = new ArrayBuffer(4);\n const view = new DataView(buffer);\n view.setFloat32(0, value, true);\n\n const f = view.getUint32(0, true);\n const sign = (f >> 31) & 0x1;\n const exp = (f >> 23) & 0xFF;\n const frac = f & 0x7FFFFF;\n\n let newExp = exp - 127 + 15;\n\n if (exp === 0) {\n newExp = 0;\n } else if (exp === 0xFF) {\n newExp = 0x1F;\n } else if (newExp >= 0x1F) {\n newExp = 0x1F;\n return (sign << 15) | (newExp << 10);\n } else if (newExp <= 0) {\n return (sign << 15);\n }\n\n return (sign << 15) | (newExp << 10) | (frac >> 13);\n }\n\n private preprocessMobileNet(canvas: HTMLCanvasElement): any {\n // Use pooled canvas instead of creating new one\n const tempCanvas = this.getCanvas(224, 224);\n const tempCtx = tempCanvas.getContext('2d')!;\n\n // Clear canvas before use\n tempCtx.clearRect(0, 0, 224, 224);\n \n // Resize image to 224x224 for SqueezeNet (using MobileNet interface)\n tempCtx.drawImage(canvas, 0, 0, 224, 224);\n\n const imageData = tempCtx.getImageData(0, 0, 224, 224);\n const data = imageData.data;\n const hw = 224 * 224;\n const arr = new Float32Array(3 * hw);\n\n // SqueezeNet preprocessing: normalize to [0,1] range and arrange in CHW format\n for (let i = 0; i < hw; i++) {\n // Red channel\n arr[i] = data[i * 4 + 0] / 255.0;\n // Green channel\n arr[hw + i] = data[i * 4 + 1] / 255.0;\n // Blue channel\n arr[2 * hw + i] = data[i * 4 + 2] / 255.0;\n }\n\n // Return canvas to pool after use\n this.returnCanvas(tempCanvas);\n\n return new (window as any).ort.Tensor('float32', arr, [1, 3, 224, 224]);\n }\n\n // Canvas pool management methods for optimization\n private getCanvas(width: number, height: number): HTMLCanvasElement {\n const key = `${width}x${height}`;\n if (!DetectionService.canvasPool.has(key)) {\n DetectionService.canvasPool.set(key, []);\n }\n const pool = DetectionService.canvasPool.get(key)!;\n \n let canvas = pool.pop();\n if (!canvas) {\n canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n } else {\n // Clear the canvas before reuse\n const ctx = canvas.getContext('2d')!;\n ctx.clearRect(0, 0, width, height);\n }\n \n return canvas;\n }\n\n private returnCanvas(canvas: HTMLCanvasElement): void {\n const key = `${canvas.width}x${canvas.height}`;\n if (!DetectionService.canvasPool.has(key)) {\n DetectionService.canvasPool.set(key, []);\n }\n const pool = DetectionService.canvasPool.get(key)!;\n \n // Only return to pool if not at max capacity\n if (pool.length < DetectionService.MAX_POOL_SIZE) {\n const ctx = canvas.getContext('2d')!;\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n pool.push(canvas);\n }\n // If pool is full, let the canvas be garbage collected\n }\n\n // Resource management methods for cache and browser optimization\n async clearModelCache(): Promise<void> {\n try {\n // Clear cache specific to models\n const cacheNames = await caches.keys();\n const modelCaches = cacheNames.filter(name => \n name.includes('onnx') || \n name.includes('jaak-static') ||\n name.includes('squeezenet') ||\n name.includes('ddmyp')\n );\n \n await Promise.all(\n modelCaches.map(cacheName => caches.delete(cacheName))\n );\n \n if (this.debug) {\n console.log(`🧹 Cleared ${modelCaches.length} model caches`);\n }\n } catch (error) {\n console.warn('Error clearing model cache:', error);\n }\n }\n\n private abortPendingRequests(): void {\n // Cancel any fetch in progress\n if (this.modelLoadController) {\n this.modelLoadController.abort();\n this.modelLoadController = undefined;\n }\n \n if (this.classificationLoadController) {\n this.classificationLoadController.abort();\n this.classificationLoadController = undefined;\n }\n }\n\n private revokeModelBlobUrls(): void {\n // Revoke any blob URLs created for models\n this.modelBlobUrls.forEach(url => URL.revokeObjectURL(url));\n this.modelBlobUrls.clear();\n }\n\n // Progressive resource release for optimization\n async releaseMobileNetResources(): Promise<void> {\n if (this.mobileNetSession) {\n this.mobileNetSession.release?.();\n this.mobileNetSession = undefined;\n }\n this.mobileNetClassMap = undefined;\n \n if (this.classificationLoadController) {\n this.classificationLoadController.abort();\n this.classificationLoadController = undefined;\n }\n \n if (this.debug) {\n console.log('🧹 Released MobileNet classification resources');\n }\n }\n\n // Optimize canvas pool by reducing to specific size\n optimizeCanvasPool(maxSize: number): void {\n DetectionService.canvasPool.forEach((pool, key) => {\n while (pool.length > maxSize) {\n const canvas = pool.pop();\n // Explicitly clear and nullify for garbage collection\n if (canvas) {\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n }\n }\n \n if (pool.length === 0) {\n DetectionService.canvasPool.delete(key);\n }\n });\n \n if (this.debug) {\n console.log(`🧹 Optimized canvas pool to max size: ${maxSize}`);\n }\n }\n\n // Clear all static canvas pools\n static clearAllCanvasPools(): void {\n DetectionService.canvasPool.forEach((pool) => {\n pool.forEach(canvas => {\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n });\n pool.length = 0;\n });\n DetectionService.canvasPool.clear();\n }\n\n // Method to get pool statistics for debugging\n public getPoolStats(): { [key: string]: number } {\n const stats: { [key: string]: number } = {};\n DetectionService.canvasPool.forEach((pool, key) => {\n stats[key] = pool.length;\n });\n return stats;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"IDetectionService.js","sourceRoot":"","sources":["../../../src/services/interfaces/IDetectionService.ts"],"names":[],"mappings":"","sourcesContent":["export interface DetectionBox {\n x: number;\n y: number;\n w: number;\n h: number;\n score: number;\n classId?: number;\n}\n\nexport interface SideAlignment {\n top: boolean;\n right: boolean;\n bottom: boolean;\n left: boolean;\n}\n\nexport interface ClassificationResult {\n class: string;\n confidence: number;\n classIndex: number;\n}\n\n\nexport interface IDetectionService {\n loadModel(): Promise<void>;\n loadClassificationModel(): Promise<void>;\n isModelLoaded(): boolean;\n preprocess(video: HTMLVideoElement): any;\n runInference(inputTensor: any): Promise<DetectionBox[]>;\n classifyDocument(canvas: HTMLCanvasElement): Promise<ClassificationResult | null>;\n checkSideAlignment(box: DetectionBox, maskConfig: any): SideAlignment;\n isCardInFrame(box: DetectionBox): boolean;\n areAllSidesAligned(alignment: SideAlignment): boolean;\n cleanup(): void;\n}"]}
1
+ {"version":3,"file":"IDetectionService.js","sourceRoot":"","sources":["../../../src/services/interfaces/IDetectionService.ts"],"names":[],"mappings":"","sourcesContent":["export interface DetectionBox {\n x: number;\n y: number;\n w: number;\n h: number;\n score: number;\n classId?: number;\n}\n\nexport interface SideAlignment {\n top: boolean;\n right: boolean;\n bottom: boolean;\n left: boolean;\n}\n\nexport interface ClassificationResult {\n class: string;\n confidence: number;\n classIndex: number;\n}\n\n\nexport interface IDetectionService {\n loadModel(): Promise<void>;\n loadClassificationModel(): Promise<void>;\n isModelLoaded(): boolean;\n preprocess(video: HTMLVideoElement): any;\n runInference(inputTensor: any): Promise<DetectionBox[]>;\n classifyDocument(canvas: HTMLCanvasElement): Promise<ClassificationResult | null>;\n checkSideAlignment(box: DetectionBox, maskConfig: any): SideAlignment;\n isCardInFrame(box: DetectionBox): boolean;\n areAllSidesAligned(alignment: SideAlignment): boolean;\n cleanup(): void;\n \n // Resource optimization methods\n clearModelCache(): Promise<void>;\n releaseMobileNetResources(): Promise<void>;\n optimizeCanvasPool(maxSize: number): void;\n getPoolStats(): { [key: string]: number };\n}"]}