@jaak.ai/stamps 2.0.0-dev.47 → 2.0.0-dev.48

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.
@@ -9,7 +9,7 @@ export class DetectionService {
9
9
  modelLoaded = false;
10
10
  deviceStrategy;
11
11
  MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx";
12
- MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx";
12
+ MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/squeezenet.onnx";
13
13
  MOBILENET_CLASSES_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json";
14
14
  INPUT_SIZE = 320;
15
15
  CONFIDENCE_THRESHOLD = 0.6;
@@ -71,15 +71,27 @@ export class DetectionService {
71
71
  }
72
72
  try {
73
73
  this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
74
- // Load class map
75
- const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
76
- if (!classResponse.ok) {
77
- throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
74
+ // Try to load class map (optional - SqueezeNet may not need it for basic classification)
75
+ try {
76
+ const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
77
+ if (classResponse.ok) {
78
+ this.mobileNetClassMap = await classResponse.json();
79
+ this.logger.state('CLASES_MOBILENET_CARGADAS', {
80
+ classCount: Object.keys(this.mobileNetClassMap).length
81
+ });
82
+ }
83
+ }
84
+ catch (error) {
85
+ this.logger.warn('No se pudo cargar el mapa de clases de MobileNet, usando clasificación básica');
86
+ // Create a basic class map for document types
87
+ this.mobileNetClassMap = {
88
+ "0": "document",
89
+ "1": "id_card",
90
+ "2": "passport",
91
+ "3": "license",
92
+ "4": "other"
93
+ };
78
94
  }
79
- this.mobileNetClassMap = await classResponse.json();
80
- this.logger.state('CLASES_MOBILENET_CARGADAS', {
81
- classCount: Object.keys(this.mobileNetClassMap).length
82
- });
83
95
  // Load model
84
96
  const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
85
97
  try {
@@ -168,7 +180,7 @@ export class DetectionService {
168
180
  try {
169
181
  this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
170
182
  const inputTensor = this.preprocessMobileNet(canvas);
171
- const feeds = { input: inputTensor };
183
+ const feeds = { [this.mobileNetSession.inputNames[0]]: inputTensor };
172
184
  const results = await this.mobileNetSession.run(feeds);
173
185
  const output = results[Object.keys(results)[0]].data;
174
186
  const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
@@ -178,7 +190,8 @@ export class DetectionService {
178
190
  class: className,
179
191
  confidence: confidence.toFixed(3),
180
192
  classIndex: maxIdx,
181
- timestamp: Date.now()
193
+ timestamp: Date.now(),
194
+ results
182
195
  });
183
196
  return {
184
197
  class: className,
@@ -217,7 +230,7 @@ export class DetectionService {
217
230
  displayedVideoHeight = INPUT_SIZE / videoAspectRatio;
218
231
  }
219
232
  else {
220
- // Video is taller - pillarboxed in display
233
+ // Video is taller - pillarboxed in display
221
234
  displayedVideoHeight = INPUT_SIZE;
222
235
  displayedVideoWidth = INPUT_SIZE * videoAspectRatio;
223
236
  }
@@ -268,7 +281,7 @@ export class DetectionService {
268
281
  const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;
269
282
  return {
270
283
  top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados
271
- right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
284
+ right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
272
285
  bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados
273
286
  left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados
274
287
  };
@@ -353,15 +366,20 @@ export class DetectionService {
353
366
  tempCanvas.width = 224;
354
367
  tempCanvas.height = 224;
355
368
  const tempCtx = tempCanvas.getContext('2d');
369
+ // Resize image to 224x224 for SqueezeNet (using MobileNet interface)
356
370
  tempCtx.drawImage(canvas, 0, 0, 224, 224);
357
371
  const imageData = tempCtx.getImageData(0, 0, 224, 224);
358
372
  const data = imageData.data;
359
373
  const hw = 224 * 224;
360
374
  const arr = new Float32Array(3 * hw);
375
+ // SqueezeNet preprocessing: normalize to [0,1] range and arrange in CHW format
361
376
  for (let i = 0; i < hw; i++) {
362
- arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5;
363
- arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5;
364
- arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5;
377
+ // Red channel
378
+ arr[i] = data[i * 4 + 0] / 255.0;
379
+ // Green channel
380
+ arr[hw + i] = data[i * 4 + 1] / 255.0;
381
+ // Blue channel
382
+ arr[2 * hw + i] = data[i * 4 + 2] / 255.0;
365
383
  }
366
384
  return new window.ort.Tensor('float32', arr, [1, 3, 224, 224]);
367
385
  }
@@ -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 { ILogger } from './interfaces/ILogger';\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/cdmmp-v1.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 constructor(\n private logger: ILogger,\n private debug: boolean = false,\n private useDocumentClassification: boolean = false\n ) {\n this.deviceStrategy = DeviceStrategyFactory.createStrategy();\n this.initializeCanvasPool();\n }\n\n async loadModel(): Promise<void> {\n if (this.modelLoaded || this.session) {\n this.logger.state('MODELO_YA_PRECARGADO', { \n sessionExists: !!this.session, \n modelPreloaded: this.modelLoaded \n });\n return;\n }\n\n try {\n this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath: this.MODEL_PATH });\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 if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');\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 };\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n \n this.modelLoaded = true;\n this.logger.state('MODELO_DETECCION_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.session });\n } catch (error) {\n this.logger.error('Error al precargar modelo de detección:', error);\n throw error;\n }\n }\n\n async loadClassificationModel(): Promise<void> {\n if (!this.useDocumentClassification) {\n return;\n }\n\n try {\n this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });\n \n // Load class map\n const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);\n if (!classResponse.ok) {\n throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);\n }\n this.mobileNetClassMap = await classResponse.json();\n this.logger.state('CLASES_MOBILENET_CARGADAS', { \n classCount: Object.keys(this.mobileNetClassMap).length \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 if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');\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 };\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { \n sessionCreated: !!this.mobileNetSession \n });\n \n } catch (error) {\n this.logger.error('Error al cargar modelo MobileNet:', error);\n throw error;\n }\n }\n\n isModelLoaded(): boolean {\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.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 this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');\n return null;\n }\n\n try {\n this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });\n \n const inputTensor = this.preprocessMobileNet(canvas);\n const feeds = { input: 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 this.logger.state('DOCUMENTO_CLASIFICADO', {\n class: className,\n confidence: confidence.toFixed(3),\n classIndex: maxIdx,\n timestamp: Date.now()\n });\n \n return {\n class: className,\n confidence: confidence,\n classIndex: maxIdx\n };\n \n } catch (error) {\n this.logger.error('Error al clasificar documento:', 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 this.logger.state('DETECCION_SERVICE_LIMPIADO', { timestamp: Date.now() });\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 this.logger.state('CANVAS_POOL_INICIALIZADO', { \n preprocessCanvasSize: this.INPUT_SIZE \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 const tempCanvas = document.createElement('canvas');\n tempCanvas.width = 224;\n tempCanvas.height = 224;\n const tempCtx = tempCanvas.getContext('2d')!;\n \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 for (let i = 0; i < hw; i++) {\n arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5;\n arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5;\n arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5;\n }\n \n return new (window as any).ort.Tensor('float32', arr, [1, 3, 224, 224]);\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 { ILogger } from './interfaces/ILogger';\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.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 constructor(\n private logger: ILogger,\n private debug: boolean = false,\n private useDocumentClassification: boolean = false\n ) {\n this.deviceStrategy = DeviceStrategyFactory.createStrategy();\n this.initializeCanvasPool();\n }\n\n async loadModel(): Promise<void> {\n if (this.modelLoaded || this.session) {\n this.logger.state('MODELO_YA_PRECARGADO', {\n sessionExists: !!this.session,\n modelPreloaded: this.modelLoaded\n });\n return;\n }\n\n try {\n this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath: this.MODEL_PATH });\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 if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');\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 };\n this.session = await (window as any).ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n\n this.modelLoaded = true;\n this.logger.state('MODELO_DETECCION_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.session });\n } catch (error) {\n this.logger.error('Error al precargar modelo de detección:', error);\n throw error;\n }\n }\n\n async loadClassificationModel(): Promise<void> {\n if (!this.useDocumentClassification) {\n return;\n }\n\n try {\n this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });\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 this.logger.state('CLASES_MOBILENET_CARGADAS', {\n classCount: Object.keys(this.mobileNetClassMap).length\n });\n }\n } catch (error) {\n this.logger.warn('No se pudo cargar el mapa de clases de MobileNet, usando clasificación básica');\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 if (error.message.includes('failed to allocate a buffer')) {\n this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');\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 };\n this.mobileNetSession = await (window as any).ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);\n } else {\n throw error;\n }\n }\n this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', {\n sessionCreated: !!this.mobileNetSession\n });\n\n } catch (error) {\n this.logger.error('Error al cargar modelo MobileNet:', error);\n throw error;\n }\n }\n\n isModelLoaded(): boolean {\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.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 this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');\n return null;\n }\n\n try {\n this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });\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 this.logger.state('DOCUMENTO_CLASIFICADO', {\n class: className,\n confidence: confidence.toFixed(3),\n classIndex: maxIdx,\n timestamp: Date.now(),\n results\n });\n\n return {\n class: className,\n confidence: confidence,\n classIndex: maxIdx\n };\n\n } catch (error) {\n this.logger.error('Error al clasificar documento:', 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 this.logger.state('DETECCION_SERVICE_LIMPIADO', { timestamp: Date.now() });\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 this.logger.state('CANVAS_POOL_INICIALIZADO', {\n preprocessCanvasSize: this.INPUT_SIZE\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 const tempCanvas = document.createElement('canvas');\n tempCanvas.width = 224;\n tempCanvas.height = 224;\n const tempCtx = tempCanvas.getContext('2d')!;\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 new (window as any).ort.Tensor('float32', arr, [1, 3, 224, 224]);\n }\n\n}\n"]}
@@ -728,7 +728,7 @@ class DetectionService {
728
728
  modelLoaded = false;
729
729
  deviceStrategy;
730
730
  MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v2.onnx";
731
- MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx";
731
+ MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/squeezenet.onnx";
732
732
  MOBILENET_CLASSES_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json";
733
733
  INPUT_SIZE = 320;
734
734
  CONFIDENCE_THRESHOLD = 0.6;
@@ -790,15 +790,27 @@ class DetectionService {
790
790
  }
791
791
  try {
792
792
  this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
793
- // Load class map
794
- const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
795
- if (!classResponse.ok) {
796
- throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
793
+ // Try to load class map (optional - SqueezeNet may not need it for basic classification)
794
+ try {
795
+ const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
796
+ if (classResponse.ok) {
797
+ this.mobileNetClassMap = await classResponse.json();
798
+ this.logger.state('CLASES_MOBILENET_CARGADAS', {
799
+ classCount: Object.keys(this.mobileNetClassMap).length
800
+ });
801
+ }
802
+ }
803
+ catch (error) {
804
+ this.logger.warn('No se pudo cargar el mapa de clases de MobileNet, usando clasificación básica');
805
+ // Create a basic class map for document types
806
+ this.mobileNetClassMap = {
807
+ "0": "document",
808
+ "1": "id_card",
809
+ "2": "passport",
810
+ "3": "license",
811
+ "4": "other"
812
+ };
797
813
  }
798
- this.mobileNetClassMap = await classResponse.json();
799
- this.logger.state('CLASES_MOBILENET_CARGADAS', {
800
- classCount: Object.keys(this.mobileNetClassMap).length
801
- });
802
814
  // Load model
803
815
  const sessionOptions = this.deviceStrategy.getSessionOptions(this.debug);
804
816
  try {
@@ -887,7 +899,7 @@ class DetectionService {
887
899
  try {
888
900
  this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
889
901
  const inputTensor = this.preprocessMobileNet(canvas);
890
- const feeds = { input: inputTensor };
902
+ const feeds = { [this.mobileNetSession.inputNames[0]]: inputTensor };
891
903
  const results = await this.mobileNetSession.run(feeds);
892
904
  const output = results[Object.keys(results)[0]].data;
893
905
  const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
@@ -897,7 +909,8 @@ class DetectionService {
897
909
  class: className,
898
910
  confidence: confidence.toFixed(3),
899
911
  classIndex: maxIdx,
900
- timestamp: Date.now()
912
+ timestamp: Date.now(),
913
+ results
901
914
  });
902
915
  return {
903
916
  class: className,
@@ -936,7 +949,7 @@ class DetectionService {
936
949
  displayedVideoHeight = INPUT_SIZE / videoAspectRatio;
937
950
  }
938
951
  else {
939
- // Video is taller - pillarboxed in display
952
+ // Video is taller - pillarboxed in display
940
953
  displayedVideoHeight = INPUT_SIZE;
941
954
  displayedVideoWidth = INPUT_SIZE * videoAspectRatio;
942
955
  }
@@ -987,7 +1000,7 @@ class DetectionService {
987
1000
  const leftAligned = Math.abs(docLeft - maskLeft) <= tolerance;
988
1001
  return {
989
1002
  top: topAligned && leftAligned, // Esquina superior izquierda: borde top Y left alineados
990
- right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
1003
+ right: topAligned && rightAligned, // Esquina superior derecha: borde top Y right alineados
991
1004
  bottom: bottomAligned && leftAligned, // Esquina inferior izquierda: borde bottom Y left alineados
992
1005
  left: bottomAligned && rightAligned // Esquina inferior derecha: borde bottom Y right alineados
993
1006
  };
@@ -1072,15 +1085,20 @@ class DetectionService {
1072
1085
  tempCanvas.width = 224;
1073
1086
  tempCanvas.height = 224;
1074
1087
  const tempCtx = tempCanvas.getContext('2d');
1088
+ // Resize image to 224x224 for SqueezeNet (using MobileNet interface)
1075
1089
  tempCtx.drawImage(canvas, 0, 0, 224, 224);
1076
1090
  const imageData = tempCtx.getImageData(0, 0, 224, 224);
1077
1091
  const data = imageData.data;
1078
1092
  const hw = 224 * 224;
1079
1093
  const arr = new Float32Array(3 * hw);
1094
+ // SqueezeNet preprocessing: normalize to [0,1] range and arrange in CHW format
1080
1095
  for (let i = 0; i < hw; i++) {
1081
- arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5;
1082
- arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5;
1083
- arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5;
1096
+ // Red channel
1097
+ arr[i] = data[i * 4 + 0] / 255.0;
1098
+ // Green channel
1099
+ arr[hw + i] = data[i * 4 + 1] / 255.0;
1100
+ // Blue channel
1101
+ arr[2 * hw + i] = data[i * 4 + 2] / 255.0;
1084
1102
  }
1085
1103
  return new window.ort.Tensor('float32', arr, [1, 3, 224, 224]);
1086
1104
  }