@jaak.ai/stamps 2.0.0-dev.23 → 2.0.0-dev.24

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.
@@ -48,6 +48,8 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
48
48
  animationId;
49
49
  hasScreenshotTaken = false;
50
50
  lastDetectedBox;
51
+ mobileNetSession;
52
+ mobileNetClassMap;
51
53
  // Performance optimization properties
52
54
  frameSkipCounter = 0;
53
55
  FRAME_SKIP = 2; // Process every 3rd frame (reduces CPU by ~66%)
@@ -60,7 +62,9 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
60
62
  preprocessCtx;
61
63
  captureCanvas;
62
64
  captureCtx;
63
- MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/detector-nano.onnx";
65
+ MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/ddmyp-v1.onnx";
66
+ MOBILENET_MODEL_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.onnx";
67
+ MOBILENET_CLASSES_PATH = "https://storage.googleapis.com/jaak-static/web/component/stamps/cdmmp-v1.json";
64
68
  INPUT_SIZE = 320;
65
69
  CONFIDENCE_THRESHOLD = 0.6;
66
70
  // ISO/IEC 7810 ID-1 standard dimensions (85.60mm x 53.98mm)
@@ -266,25 +270,27 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
266
270
  }
267
271
  try {
268
272
  this.isLoading = true;
269
- this.statusMessage = "Precargando modelo de detección...";
273
+ this.statusMessage = "Precargando modelos...";
270
274
  this.statusColor = "#007bff";
271
275
  const modelPath = this.MODEL_PATH;
272
- this.debugLog('🤖 Preloading model:', modelPath);
276
+ this.debugLog('🤖 Preloading detection model:', modelPath);
273
277
  // Configure ONNX Runtime with device-specific optimizations
274
278
  const sessionOptions = this.getSessionOptions();
275
279
  this.session = await window.ort.InferenceSession.create(modelPath, sessionOptions);
280
+ // Preload MobileNet model and classes
281
+ await this.loadMobileNetModel();
276
282
  this.isModelPreloaded = true;
277
283
  this.isLoading = false;
278
- this.statusMessage = "Modelo precargado. Listo para comenzar detección";
284
+ this.statusMessage = "Modelos precargados. Listo para comenzar detección";
279
285
  this.statusColor = "#28a745";
280
286
  this.emitReadyEvent();
281
- this.debugLog('✅ Model preloaded successfully');
282
- return { success: true, message: 'Model preloaded successfully' };
287
+ this.debugLog('✅ Models preloaded successfully');
288
+ return { success: true, message: 'Models preloaded successfully' };
283
289
  }
284
290
  catch (error) {
285
- this.debugLog('❌ Error preloading model:', error);
291
+ this.debugLog('❌ Error preloading models:', error);
286
292
  this.isLoading = false;
287
- this.statusMessage = "Error al precargar el modelo";
293
+ this.statusMessage = "Error al precargar los modelos";
288
294
  this.statusColor = "#ff6b6b";
289
295
  return { success: false, error: error.message };
290
296
  }
@@ -294,6 +300,80 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
294
300
  this.completeProcess(true);
295
301
  }
296
302
  }
303
+ async loadMobileNetModel() {
304
+ try {
305
+ this.debugLog('🤖 Loading MobileNet model...');
306
+ // Load class map
307
+ const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
308
+ if (!classResponse.ok) {
309
+ throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
310
+ }
311
+ this.mobileNetClassMap = await classResponse.json();
312
+ this.debugLog('📋 MobileNet classes loaded:', this.mobileNetClassMap);
313
+ // Load model
314
+ const sessionOptions = this.getSessionOptions();
315
+ this.mobileNetSession = await window.ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);
316
+ this.debugLog('✅ MobileNet model loaded successfully');
317
+ }
318
+ catch (error) {
319
+ this.debugLog('❌ Error loading MobileNet model:', error);
320
+ throw error;
321
+ }
322
+ }
323
+ preprocessMobileNet(canvas) {
324
+ // Create a temporary canvas for MobileNet preprocessing (224x224)
325
+ const tempCanvas = document.createElement('canvas');
326
+ tempCanvas.width = 224;
327
+ tempCanvas.height = 224;
328
+ const tempCtx = tempCanvas.getContext('2d');
329
+ // Draw the cropped image onto the 224x224 canvas
330
+ tempCtx.drawImage(canvas, 0, 0, 224, 224);
331
+ // Get image data and preprocess for MobileNet
332
+ const imageData = tempCtx.getImageData(0, 0, 224, 224);
333
+ const data = imageData.data;
334
+ const hw = 224 * 224;
335
+ const arr = new Float32Array(3 * hw);
336
+ // Normalize pixels: (pixel/255 - 0.5) / 0.5 = (pixel - 127.5) / 127.5
337
+ for (let i = 0; i < hw; i++) {
338
+ arr[i] = (data[i * 4 + 0] / 255 - 0.5) / 0.5; // R
339
+ arr[hw + i] = (data[i * 4 + 1] / 255 - 0.5) / 0.5; // G
340
+ arr[2 * hw + i] = (data[i * 4 + 2] / 255 - 0.5) / 0.5; // B
341
+ }
342
+ return new window.ort.Tensor('float32', arr, [1, 3, 224, 224]);
343
+ }
344
+ async classifyDocument(canvas) {
345
+ if (!this.mobileNetSession || !this.mobileNetClassMap) {
346
+ this.debugLog('⚠️ MobileNet model not loaded');
347
+ return null;
348
+ }
349
+ try {
350
+ this.debugLog('🔍 Classifying document...');
351
+ // Preprocess image for MobileNet
352
+ const inputTensor = this.preprocessMobileNet(canvas);
353
+ // Run inference
354
+ const feeds = { input: inputTensor };
355
+ const results = await this.mobileNetSession.run(feeds);
356
+ const output = results[Object.keys(results)[0]].data;
357
+ // Find the class with highest confidence
358
+ const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
359
+ const confidence = output[maxIdx];
360
+ const className = this.mobileNetClassMap[maxIdx.toString()] || "unknown";
361
+ this.debugLog('📄 Document classification result:', {
362
+ class: className,
363
+ confidence: confidence.toFixed(3),
364
+ classIndex: maxIdx
365
+ });
366
+ return {
367
+ class: className,
368
+ confidence: confidence,
369
+ classIndex: maxIdx
370
+ };
371
+ }
372
+ catch (error) {
373
+ this.debugLog('❌ Error classifying document:', error);
374
+ return null;
375
+ }
376
+ }
297
377
  cleanup() {
298
378
  if (this.animationId) {
299
379
  cancelAnimationFrame(this.animationId);
@@ -321,11 +401,16 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
321
401
  this.captureCtx = undefined;
322
402
  this.captureCanvas = undefined;
323
403
  }
324
- // Disposed ONNX session
404
+ // Disposed ONNX sessions
325
405
  if (this.session) {
326
406
  this.session.release?.();
327
407
  this.session = undefined;
328
408
  }
409
+ if (this.mobileNetSession) {
410
+ this.mobileNetSession.release?.();
411
+ this.mobileNetSession = undefined;
412
+ }
413
+ this.mobileNetClassMap = undefined;
329
414
  this.isModelPreloaded = false;
330
415
  this.debugLog('🧹 Canvas pool cleaned up');
331
416
  }
@@ -456,18 +541,22 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
456
541
  // Check if model is already preloaded
457
542
  if (!this.session) {
458
543
  this.isLoading = true;
459
- this.statusMessage = "Cargando modelo de detección...";
544
+ this.statusMessage = "Cargando modelos...";
460
545
  this.statusColor = "#007bff";
461
546
  const modelPath = this.MODEL_PATH;
462
- this.debugLog('🤖 Loading model:', modelPath);
547
+ this.debugLog('🤖 Loading detection model:', modelPath);
463
548
  const sessionOptions = this.getSessionOptions();
464
549
  this.session = await window.ort.InferenceSession.create(modelPath, sessionOptions);
550
+ // Load MobileNet model if not already loaded
551
+ if (!this.mobileNetSession) {
552
+ await this.loadMobileNetModel();
553
+ }
465
554
  this.isModelPreloaded = true;
466
555
  this.emitReadyEvent();
467
556
  }
468
557
  else {
469
- this.debugLog('🚀 Using preloaded model');
470
- this.statusMessage = "Usando modelo precargado...";
558
+ this.debugLog('🚀 Using preloaded models');
559
+ this.statusMessage = "Usando modelos precargados...";
471
560
  this.statusColor = "#007bff";
472
561
  }
473
562
  this.statusMessage = "Configurando cámara...";
@@ -686,7 +775,9 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
686
775
  corners?.forEach(corner => corner.classList.add('perfect-match'));
687
776
  if (!this.hasScreenshotTaken) {
688
777
  this.lastDetectedBox = bestBox;
689
- this.takeScreenshot();
778
+ this.takeScreenshot().catch(error => {
779
+ this.debugLog('❌ Error taking screenshot:', error);
780
+ });
690
781
  this.hasScreenshotTaken = true;
691
782
  // Reset para permitir segunda captura
692
783
  setTimeout(() => {
@@ -769,7 +860,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
769
860
  ctx.strokeRect(x, y, w, h);
770
861
  });
771
862
  }
772
- takeScreenshot() {
863
+ async takeScreenshot() {
773
864
  if (!this.videoRef || !this.lastDetectedBox)
774
865
  return;
775
866
  // Activar animación
@@ -803,6 +894,15 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
803
894
  // Captura del frente usando canvas reutilizado
804
895
  this.capturedFullFrame = this.captureCanvas.toDataURL('image/png');
805
896
  this.capturedCroppedId = croppedCanvas.toDataURL('image/png');
897
+ // Classify the cropped document
898
+ const classification = await this.classifyDocument(croppedCanvas);
899
+ if (classification && classification.class === 'passport') {
900
+ // If it's a passport, skip back capture since passports don't have a back side
901
+ this.debugLog('📄 Passport detected - skipping back capture');
902
+ this.completeProcess(true);
903
+ return;
904
+ }
905
+ // For other IDs, continue with normal flow (back capture)
806
906
  this.captureStep = 'back';
807
907
  this.statusMessage = "Voltee la identificación y muestre la parte trasera";
808
908
  this.statusColor = "#007bff";
@@ -932,7 +1032,7 @@ const JaakStamps$1 = /*@__PURE__*/ proxyCustomElement(class JaakStamps extends H
932
1032
  this.cleanup();
933
1033
  }
934
1034
  render() {
935
- return (h("div", { key: '7cd80970b12ba60949ff34b5a9405b9782267918', class: "detector-container" }, h("div", { key: '0e66e46a524bd37f60f30504a270f72b64a97fc1', class: "video-container" }, h("video", { key: '0c1b0719c626659e54bec8ce3383f50d990c32c1', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: this.isVideoActive ? 'block' : 'none' } }), h("canvas", { key: '09fc3a2d511e48186099a0ff5d3d6378f15fe1c4', ref: el => this.canvasRef = el, class: this.shouldMirrorVideo ? 'mirror' : '' }), this.isMaskReady && (h("div", { key: '70a31b04c9543fc0834a848013daf06c654e4194', class: "overlay-mask" }, h("div", { key: '050dcdaa59b028b5c379de310a80ca7191bf8af8', class: "card-outline" }, h("div", { key: 'adef93f2e6b16b308dc5d67469f35c2025ca160f', class: "side side-top" }), h("div", { key: '4900bed8cc2607f92163a25bbf3c0d3a272b9840', class: "side side-right" }), h("div", { key: '11fc9da6cfe04b993bf4a72413da2344122b21e4', class: "side side-bottom" }), h("div", { key: 'ed95ac2578ba045e003d61144aecd09ef4f01561', class: "side side-left" }), h("div", { key: '37eec8aad0a0d449174d52caab7aec5a25d11731', class: "corner corner-tl" }), h("div", { key: 'c7247e71d8936d0a30f415f73377713a8c457420', class: "corner corner-tr" }), h("div", { key: 'e131e0c3bd66068ae1d33cd7211edafd92dfbe62', class: "corner corner-bl" }), h("div", { key: '89234ddcde735501907276e10287af983033ec85', class: "corner corner-br" }), !this.showFlipAnimation && !this.showSuccessAnimation && (h("div", { key: '4b2543dd05f173b3ee4e3053ed7b62d4e7b75e63', class: "guide-text" }, this.statusMessage))), this.captureStep === 'back' && !this.showFlipAnimation && !this.showSuccessAnimation && (h("button", { key: 'e7e2b2b1486f7024fc2d42073313833bca88e315', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")))), this.isCapturing && (h("div", { key: '6ca8283fe3eb1c5b2700c0d313afb51c2db3ea7f', class: "capture-animation" })), this.showFlipAnimation && (h("div", { key: 'eaed1200385a98a8750cdaef2dad9f8ff63914f3', class: "flip-animation" }, h("div", { key: 'dbe9bfc929fa8b13cadc60cdece603c48dbcbd4c', class: "id-card-icon" }), h("div", { key: '82b9de0910a993b6cf3af7ecdf43de41d495c181', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), this.showSuccessAnimation && (h("div", { key: '92ef47686b0fbf91f6a3f8c3c3f23a78a6fc76f8', class: "success-animation" }, h("div", { key: '35aeb41dce144fc844d7447a958473834f6b0843', class: "check-icon" }), h("div", { key: '2ba06161a8d665394803ce8cc90320b154048c0b', class: "success-text" }, "\u00A1Proceso completado!"))), this.isLoading && (h("div", { key: '8abc4f5724ca6543698f7ca9116ccfc9c042edbd', class: "loading-overlay" }, h("div", { key: '5c8f73bb7c30c6a4c304e96e4db2bf75dc89b89e', class: "loading-spinner" }), h("div", { key: '8f5665f21be98ddccb9d9d2c6412e4edf4571a51', class: "loading-text" }, this.statusMessage))), h("div", { key: '00316bee3c56f07b9771c400f5b84b7e14dca4af', class: "watermark" }, h("img", { key: 'd7f58ffa993405912f8aa26386f39caa72e7a000', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1035
+ return (h("div", { key: 'd6cd4225500c44e5c7fb4f2b3dc453a055467066', class: "detector-container" }, h("div", { key: '6bd49b0bcd686648aeffb8fb95203dc0779f1d8a', class: "video-container" }, h("video", { key: 'd2666ce9d1f5b84703ac86fd4eb901f4298ed7d5', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: this.isVideoActive ? 'block' : 'none' } }), h("canvas", { key: 'e997f063450d81d2a15398f0761c9d06c28a85c9', ref: el => this.canvasRef = el, class: this.shouldMirrorVideo ? 'mirror' : '' }), this.isMaskReady && (h("div", { key: '4ccb8bf05091a7173255181eae1a8699fe512b56', class: "overlay-mask" }, h("div", { key: 'b35defa8c207b05e41d64c8e1eefc905d31fad55', class: "card-outline" }, h("div", { key: '6ed8dad63d6d79c1bb4a64f0b28467f5b29d778a', class: "side side-top" }), h("div", { key: '403d4a5ba681a58ad1870a4339e19b4f037a8795', class: "side side-right" }), h("div", { key: '3cb3276bb184a4b76419b4cb0b4fcb151a4df631', class: "side side-bottom" }), h("div", { key: 'ed7c9bec0e708ab282ba8b24a08d21b8126af27e', class: "side side-left" }), h("div", { key: '157be211355bf9260dc7a73d03831dbb1a2945e3', class: "corner corner-tl" }), h("div", { key: 'b19af5f319333ff05f981063af939d2c4cfc9b5f', class: "corner corner-tr" }), h("div", { key: '6fcd3e2c8842261dcd32c36e6df5b2f3dd0c8fc8', class: "corner corner-bl" }), h("div", { key: '7caab5eaee62f3f9039075b3748083c89c8127e0', class: "corner corner-br" }), !this.showFlipAnimation && !this.showSuccessAnimation && (h("div", { key: 'e3dd42ddb75b22aeef438d8651955f3dc039f00c', class: "guide-text" }, this.statusMessage))), this.captureStep === 'back' && !this.showFlipAnimation && !this.showSuccessAnimation && (h("button", { key: '54b8651817cd52bad2f34ac1413a4b1e21166cee', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")))), this.isCapturing && (h("div", { key: '853707a4fa71eeacbee7985e619fca80d6522cbd', class: "capture-animation" })), this.showFlipAnimation && (h("div", { key: '246ed3f5dc57ee57345105cdebe5f950d5ff4c90', class: "flip-animation" }, h("div", { key: 'f03c6c87c8f5e98a32176cca061d369a521da2e8', class: "id-card-icon" }), h("div", { key: 'e357785b076a9e41ea4f9b3d9c14e847bacc9604', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), this.showSuccessAnimation && (h("div", { key: 'df3adaaecd3d547938638c58ccc0e89f8325fc23', class: "success-animation" }, h("div", { key: 'a023985b8afd6ed72f9e1c2ee63e2c7ba9fb960b', class: "check-icon" }), h("div", { key: '739ff7f329f2131061a6860529c07c8819800aab', class: "success-text" }, "\u00A1Proceso completado!"))), this.isLoading && (h("div", { key: '9b02df640528a19cb15e5dbabf9ecb43afbceffa', class: "loading-overlay" }, h("div", { key: '3652c8e355ea7fe623c478229bf548bdf30e399a', class: "loading-spinner" }), h("div", { key: '334f4469b5672f6af78b8679c15ed8c59ecefa85', class: "loading-text" }, this.statusMessage))), h("div", { key: 'a0b7c9b92771cff96e97bd67da2fd3090b080f8a', class: "watermark" }, h("img", { key: 'b5c8f0de1d8138d4a0c80526fd33b2daefa86b16', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
936
1036
  }
937
1037
  static get style() { return myComponentCss; }
938
1038
  }, [1, "jaak-stamps", {