@jaak.ai/stamps 2.0.0-dev.28 → 2.0.0-dev.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/jaak-stamps.cjs.entry.js +157 -70
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/collection/components/my-component/my-component.js +157 -70
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/components/jaak-stamps.js +157 -70
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps.entry.js +157 -70
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps-webcomponent.esm.js +1 -1
- package/dist/jaak-stamps-webcomponent/jaak-stamps.entry.esm.js.map +1 -1
- package/dist/jaak-stamps-webcomponent/p-28adb830.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-28adb830.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +1 -1
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-67b8e4cf.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-67b8e4cf.entry.js.map +0 -1
|
@@ -76,34 +76,65 @@ const JaakStamps = class {
|
|
|
76
76
|
CONFIDENCE_THRESHOLD = 0.6;
|
|
77
77
|
// ISO/IEC 7810 ID-1 standard dimensions (85.60mm x 53.98mm)
|
|
78
78
|
ID1_ASPECT_RATIO = 85.60 / 53.98; // 1.5863320574...
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
logger = {
|
|
80
|
+
info: (...args) => {
|
|
81
|
+
if (this.debug) {
|
|
82
|
+
console.log(`[JAAK-STAMPS] [INFO] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
warn: (...args) => {
|
|
86
|
+
if (this.debug) {
|
|
87
|
+
console.warn(`[JAAK-STAMPS] [WARN] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
error: (...args) => {
|
|
91
|
+
if (this.debug) {
|
|
92
|
+
console.error(`[JAAK-STAMPS] [ERROR] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
debug: (...args) => {
|
|
96
|
+
if (this.debug) {
|
|
97
|
+
console.debug(`[JAAK-STAMPS] [DEBUG] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
state: (state, data) => {
|
|
101
|
+
if (this.debug) {
|
|
102
|
+
console.log(`[JAAK-STAMPS] [STATE] [${new Date().toLocaleTimeString()}] ${state}`, data || '');
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
performance: (operation, duration) => {
|
|
106
|
+
if (this.debug) {
|
|
107
|
+
console.log(`[JAAK-STAMPS] [PERF] [${new Date().toLocaleTimeString()}] ${operation}: ${duration}ms`);
|
|
108
|
+
}
|
|
82
109
|
}
|
|
83
|
-
}
|
|
110
|
+
};
|
|
84
111
|
validateMaskSize() {
|
|
85
112
|
if (this.maskSize < 50 || this.maskSize > 100) {
|
|
86
|
-
|
|
113
|
+
this.logger.warn(`Propiedad maskSize inválida. Valor: ${this.maskSize}, esperado: 50-100. Usando valor por defecto: 90`);
|
|
87
114
|
this.maskSize = 90;
|
|
88
115
|
}
|
|
89
116
|
}
|
|
90
117
|
validateCropMargin() {
|
|
91
118
|
if (this.cropMargin < 0 || this.cropMargin > 100) {
|
|
92
|
-
|
|
119
|
+
this.logger.warn(`Propiedad cropMargin inválida. Valor: ${this.cropMargin}, esperado: 0-100. Usando valor por defecto: 0`);
|
|
93
120
|
this.cropMargin = 0;
|
|
94
121
|
}
|
|
95
122
|
}
|
|
96
123
|
validatePreferredCamera() {
|
|
97
124
|
const validOptions = ['auto', 'front', 'back'];
|
|
98
125
|
if (!validOptions.includes(this.preferredCamera)) {
|
|
99
|
-
|
|
126
|
+
this.logger.warn(`Propiedad preferredCamera inválida. Valor: ${this.preferredCamera}, esperado: ${validOptions.join(', ')}. Usando valor por defecto: 'auto'`);
|
|
100
127
|
this.preferredCamera = 'auto';
|
|
101
128
|
}
|
|
102
129
|
}
|
|
103
130
|
emitReadyEvent() {
|
|
104
131
|
const isDocumentReady = !!window.ort && this.isModelPreloaded;
|
|
105
132
|
this.isReady.emit(isDocumentReady);
|
|
106
|
-
this.
|
|
133
|
+
this.logger.state('COMPONENTE_LISTO', {
|
|
134
|
+
ortLibraryLoaded: !!window.ort,
|
|
135
|
+
modelPreloaded: this.isModelPreloaded,
|
|
136
|
+
isReady: isDocumentReady
|
|
137
|
+
});
|
|
107
138
|
}
|
|
108
139
|
isRearCamera(stream) {
|
|
109
140
|
const videoTrack = stream.getVideoTracks()[0];
|
|
@@ -126,7 +157,11 @@ const JaakStamps = class {
|
|
|
126
157
|
else {
|
|
127
158
|
this.deviceType = 'desktop';
|
|
128
159
|
}
|
|
129
|
-
this.
|
|
160
|
+
this.logger.state('DISPOSITIVO_DETECTADO', {
|
|
161
|
+
deviceType: this.deviceType,
|
|
162
|
+
userAgent: navigator.userAgent,
|
|
163
|
+
screenDimensions: { width: window.innerWidth, height: window.innerHeight }
|
|
164
|
+
});
|
|
130
165
|
// Enumerate available cameras
|
|
131
166
|
await this.enumerateAndDetectCameras();
|
|
132
167
|
// Load user preference
|
|
@@ -137,7 +172,7 @@ const JaakStamps = class {
|
|
|
137
172
|
// First, check if we have permission to enumerate devices
|
|
138
173
|
const permissionStatus = await this.checkCameraPermission();
|
|
139
174
|
if (permissionStatus === 'denied') {
|
|
140
|
-
this.
|
|
175
|
+
this.logger.error('Permiso de cámara denegado por el usuario');
|
|
141
176
|
this.statusMessage = "Permiso de cámara denegado";
|
|
142
177
|
this.statusColor = "#ff6b6b";
|
|
143
178
|
return;
|
|
@@ -151,7 +186,7 @@ const JaakStamps = class {
|
|
|
151
186
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
152
187
|
this.availableCameras = devices.filter(device => device.kind === 'videoinput');
|
|
153
188
|
this.isMultipleCamerasAvailable = this.availableCameras.length > 1;
|
|
154
|
-
this.
|
|
189
|
+
this.logger.state('CAMARAS_DETECTADAS', {
|
|
155
190
|
count: this.availableCameras.length,
|
|
156
191
|
isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
|
|
157
192
|
cameras: this.availableCameras.map(cam => ({
|
|
@@ -163,7 +198,7 @@ const JaakStamps = class {
|
|
|
163
198
|
this.setInitialCameraPreference();
|
|
164
199
|
}
|
|
165
200
|
catch (error) {
|
|
166
|
-
this.
|
|
201
|
+
this.logger.error('Error al enumerar cámaras disponibles:', error);
|
|
167
202
|
this.handleCameraPermissionError(error);
|
|
168
203
|
}
|
|
169
204
|
}
|
|
@@ -176,7 +211,7 @@ const JaakStamps = class {
|
|
|
176
211
|
return permission.state;
|
|
177
212
|
}
|
|
178
213
|
catch (error) {
|
|
179
|
-
this.
|
|
214
|
+
this.logger.warn('No se pudo verificar permisos de cámara:', error);
|
|
180
215
|
return 'prompt';
|
|
181
216
|
}
|
|
182
217
|
}
|
|
@@ -219,11 +254,11 @@ const JaakStamps = class {
|
|
|
219
254
|
!camera.label.toLowerCase().includes('back') && !camera.label.toLowerCase().includes('rear'));
|
|
220
255
|
if (frontCamera) {
|
|
221
256
|
this.selectedCameraId = frontCamera.deviceId;
|
|
222
|
-
this.
|
|
257
|
+
this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { label: frontCamera.label, deviceId: frontCamera.deviceId });
|
|
223
258
|
}
|
|
224
259
|
else {
|
|
225
260
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
226
|
-
this.
|
|
261
|
+
this.logger.warn('Cámara frontal no encontrada, usando primera disponible:', this.availableCameras[0].label);
|
|
227
262
|
}
|
|
228
263
|
}
|
|
229
264
|
else if (this.preferredCamera === 'back') {
|
|
@@ -234,11 +269,11 @@ const JaakStamps = class {
|
|
|
234
269
|
camera.label.toLowerCase().includes('environment'));
|
|
235
270
|
if (backCamera) {
|
|
236
271
|
this.selectedCameraId = backCamera.deviceId;
|
|
237
|
-
this.
|
|
272
|
+
this.logger.state('CAMARA_TRASERA_SELECCIONADA', { label: backCamera.label, deviceId: backCamera.deviceId });
|
|
238
273
|
}
|
|
239
274
|
else {
|
|
240
275
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
241
|
-
this.
|
|
276
|
+
this.logger.warn('Cámara trasera no encontrada, usando primera disponible:', this.availableCameras[0].label);
|
|
242
277
|
}
|
|
243
278
|
}
|
|
244
279
|
else {
|
|
@@ -251,17 +286,17 @@ const JaakStamps = class {
|
|
|
251
286
|
camera.label.toLowerCase().includes('environment'));
|
|
252
287
|
if (rearCamera) {
|
|
253
288
|
this.selectedCameraId = rearCamera.deviceId;
|
|
254
|
-
this.
|
|
289
|
+
this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear', label: rearCamera.label, deviceId: rearCamera.deviceId });
|
|
255
290
|
}
|
|
256
291
|
else {
|
|
257
292
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
258
|
-
this.
|
|
293
|
+
this.logger.warn('Cámara trasera no encontrada en mobile, usando primera disponible:', this.availableCameras[0].label);
|
|
259
294
|
}
|
|
260
295
|
}
|
|
261
296
|
else {
|
|
262
297
|
// For desktop, use first available camera (usually the only one)
|
|
263
298
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
264
|
-
this.
|
|
299
|
+
this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { label: this.availableCameras[0].label, deviceId: this.availableCameras[0].deviceId });
|
|
265
300
|
}
|
|
266
301
|
}
|
|
267
302
|
}
|
|
@@ -275,12 +310,12 @@ const JaakStamps = class {
|
|
|
275
310
|
if (isStillAvailable) {
|
|
276
311
|
this.selectedCameraId = preference.cameraId;
|
|
277
312
|
this.preferredCameraFacing = preference.facing;
|
|
278
|
-
this.
|
|
313
|
+
this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);
|
|
279
314
|
}
|
|
280
315
|
}
|
|
281
316
|
}
|
|
282
317
|
catch (error) {
|
|
283
|
-
this.
|
|
318
|
+
this.logger.warn('Error al cargar preferencia de cámara:', error);
|
|
284
319
|
}
|
|
285
320
|
}
|
|
286
321
|
saveCameraPreference() {
|
|
@@ -291,10 +326,10 @@ const JaakStamps = class {
|
|
|
291
326
|
timestamp: Date.now()
|
|
292
327
|
};
|
|
293
328
|
localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));
|
|
294
|
-
this.
|
|
329
|
+
this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);
|
|
295
330
|
}
|
|
296
331
|
catch (error) {
|
|
297
|
-
this.
|
|
332
|
+
this.logger.warn('Error al guardar preferencia de cámara:', error);
|
|
298
333
|
}
|
|
299
334
|
}
|
|
300
335
|
async switchCamera(cameraId) {
|
|
@@ -304,7 +339,7 @@ const JaakStamps = class {
|
|
|
304
339
|
// Check if the selected camera is still available
|
|
305
340
|
const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);
|
|
306
341
|
if (!selectedCamera) {
|
|
307
|
-
this.
|
|
342
|
+
this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');
|
|
308
343
|
await this.enumerateAndDetectCameras();
|
|
309
344
|
return;
|
|
310
345
|
}
|
|
@@ -328,10 +363,10 @@ const JaakStamps = class {
|
|
|
328
363
|
this.saveCameraPreference();
|
|
329
364
|
// Setup new camera with error handling
|
|
330
365
|
await this.setupCameraWithRetry();
|
|
331
|
-
this.
|
|
366
|
+
this.logger.state('CAMARA_CAMBIADA', { label: selectedCamera.label, deviceId: selectedCamera.deviceId });
|
|
332
367
|
}
|
|
333
368
|
catch (error) {
|
|
334
|
-
this.
|
|
369
|
+
this.logger.error('Error al cambiar de cámara:', error);
|
|
335
370
|
this.handleCameraPermissionError(error);
|
|
336
371
|
}
|
|
337
372
|
}
|
|
@@ -346,7 +381,7 @@ const JaakStamps = class {
|
|
|
346
381
|
return; // Success
|
|
347
382
|
}
|
|
348
383
|
catch (error) {
|
|
349
|
-
this.
|
|
384
|
+
this.logger.error(`Intento ${attempt} de configuración de cámara fallido:`, error);
|
|
350
385
|
if (attempt === maxRetries) {
|
|
351
386
|
// Last attempt failed, handle the error
|
|
352
387
|
this.statusMessage = "Error al configurar la cámara";
|
|
@@ -366,7 +401,7 @@ const JaakStamps = class {
|
|
|
366
401
|
}
|
|
367
402
|
toggleCameraSelector() {
|
|
368
403
|
this.showCameraSelector = !this.showCameraSelector;
|
|
369
|
-
this.
|
|
404
|
+
this.logger.state('SELECTOR_CAMARA_TOGGLE', {
|
|
370
405
|
showCameraSelector: this.showCameraSelector,
|
|
371
406
|
isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
|
|
372
407
|
availableCameras: this.availableCameras.length,
|
|
@@ -382,6 +417,13 @@ const JaakStamps = class {
|
|
|
382
417
|
await this.switchCamera(nextCamera.deviceId);
|
|
383
418
|
}
|
|
384
419
|
async componentDidLoad() {
|
|
420
|
+
this.logger.state('COMPONENTE_INICIALIZANDO', {
|
|
421
|
+
debug: this.debug,
|
|
422
|
+
maskSize: this.maskSize,
|
|
423
|
+
cropMargin: this.cropMargin,
|
|
424
|
+
useDocumentClassification: this.useDocumentClassification,
|
|
425
|
+
preferredCamera: this.preferredCamera
|
|
426
|
+
});
|
|
385
427
|
if (this.debug) {
|
|
386
428
|
// Show detailed initialization loading state only in debug mode
|
|
387
429
|
this.isLoading = true;
|
|
@@ -446,7 +488,7 @@ const JaakStamps = class {
|
|
|
446
488
|
this.canvasRef.height = rect.height;
|
|
447
489
|
// Update mask positioning based on container and video dimensions
|
|
448
490
|
this.updateMaskDimensions(rect);
|
|
449
|
-
this.
|
|
491
|
+
this.logger.debug('Canvas redimensionado:', { width: rect.width, height: rect.height });
|
|
450
492
|
}
|
|
451
493
|
}
|
|
452
494
|
updateMaskDimensions(containerRect) {
|
|
@@ -506,7 +548,7 @@ const JaakStamps = class {
|
|
|
506
548
|
this.el.style.setProperty('--mask-center-y', `${videoCenterYPercent}%`);
|
|
507
549
|
// Mark mask as ready now that dimensions are calculated
|
|
508
550
|
this.isMaskReady = true;
|
|
509
|
-
this.
|
|
551
|
+
this.logger.state('DIMENSIONES_MASCARA_ACTUALIZADAS', {
|
|
510
552
|
video: { width: videoWidth, height: videoHeight },
|
|
511
553
|
displayed: { width: displayedVideoWidth, height: displayedVideoHeight },
|
|
512
554
|
mask: { widthPercent: maskWidthPercent, heightPercent: maskHeightPercent },
|
|
@@ -528,7 +570,7 @@ const JaakStamps = class {
|
|
|
528
570
|
this.captureCtx = this.captureCanvas.getContext('2d', {
|
|
529
571
|
alpha: false
|
|
530
572
|
});
|
|
531
|
-
this.
|
|
573
|
+
this.logger.state('CANVAS_POOL_INICIALIZADO', { preprocessCanvasSize: this.INPUT_SIZE });
|
|
532
574
|
}
|
|
533
575
|
disconnectedCallback() {
|
|
534
576
|
this.cleanup();
|
|
@@ -576,7 +618,7 @@ const JaakStamps = class {
|
|
|
576
618
|
}
|
|
577
619
|
async preloadModel() {
|
|
578
620
|
if (this.isModelPreloaded || this.session) {
|
|
579
|
-
this.
|
|
621
|
+
this.logger.state('MODELO_YA_PRECARGADO', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
|
|
580
622
|
return { success: true, message: 'Model already loaded' };
|
|
581
623
|
}
|
|
582
624
|
try {
|
|
@@ -584,7 +626,7 @@ const JaakStamps = class {
|
|
|
584
626
|
this.statusMessage = "Precargando modelos...";
|
|
585
627
|
this.statusColor = "#007bff";
|
|
586
628
|
const modelPath = this.MODEL_PATH;
|
|
587
|
-
this.
|
|
629
|
+
this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath });
|
|
588
630
|
// Configure ONNX Runtime with device-specific optimizations
|
|
589
631
|
const sessionOptions = this.getSessionOptions();
|
|
590
632
|
const deviceInfo = this.getDeviceMemoryInfo();
|
|
@@ -593,7 +635,7 @@ const JaakStamps = class {
|
|
|
593
635
|
}
|
|
594
636
|
catch (error) {
|
|
595
637
|
if (error.message.includes('failed to allocate a buffer')) {
|
|
596
|
-
this.
|
|
638
|
+
this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');
|
|
597
639
|
const fallbackOptions = {
|
|
598
640
|
executionProviders: ['wasm'],
|
|
599
641
|
graphOptimizationLevel: 'disabled',
|
|
@@ -614,7 +656,7 @@ const JaakStamps = class {
|
|
|
614
656
|
// For low memory devices, load sequentially to avoid memory pressure
|
|
615
657
|
if (this.useDocumentClassification) {
|
|
616
658
|
if (deviceInfo.isLowMemory) {
|
|
617
|
-
this.
|
|
659
|
+
this.logger.state('CARGA_SECUENCIAL_MODELOS', { reason: 'low memory device' });
|
|
618
660
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
619
661
|
}
|
|
620
662
|
await this.loadMobileNetModel();
|
|
@@ -624,11 +666,15 @@ const JaakStamps = class {
|
|
|
624
666
|
this.statusMessage = "Modelos precargados. Listo para comenzar detección";
|
|
625
667
|
this.statusColor = "#28a745";
|
|
626
668
|
this.emitReadyEvent();
|
|
627
|
-
this.
|
|
669
|
+
this.logger.state('MODELOS_PRECARGADOS_EXITOSAMENTE', {
|
|
670
|
+
detectionModel: !!this.session,
|
|
671
|
+
classificationModel: !!this.mobileNetSession,
|
|
672
|
+
useClassification: this.useDocumentClassification
|
|
673
|
+
});
|
|
628
674
|
return { success: true, message: 'Models preloaded successfully' };
|
|
629
675
|
}
|
|
630
676
|
catch (error) {
|
|
631
|
-
this.
|
|
677
|
+
this.logger.error('Error al precargar modelos:', error);
|
|
632
678
|
this.isLoading = false;
|
|
633
679
|
this.statusMessage = "Error al precargar los modelos";
|
|
634
680
|
this.statusColor = "#ff6b6b";
|
|
@@ -656,7 +702,7 @@ const JaakStamps = class {
|
|
|
656
702
|
}
|
|
657
703
|
async setPreferredCamera(camera) {
|
|
658
704
|
this.preferredCamera = camera;
|
|
659
|
-
this.
|
|
705
|
+
this.logger.state('PREFERENCIA_CAMARA_CAMBIADA', { newPreference: camera });
|
|
660
706
|
// Re-detect and apply new camera preference
|
|
661
707
|
await this.enumerateAndDetectCameras();
|
|
662
708
|
// If video is active, switch to the new preferred camera
|
|
@@ -671,14 +717,14 @@ const JaakStamps = class {
|
|
|
671
717
|
}
|
|
672
718
|
async loadMobileNetModel() {
|
|
673
719
|
try {
|
|
674
|
-
this.
|
|
720
|
+
this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
|
|
675
721
|
// Load class map
|
|
676
722
|
const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
|
|
677
723
|
if (!classResponse.ok) {
|
|
678
724
|
throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
|
|
679
725
|
}
|
|
680
726
|
this.mobileNetClassMap = await classResponse.json();
|
|
681
|
-
this.
|
|
727
|
+
this.logger.state('CLASES_MOBILENET_CARGADAS', { classCount: Object.keys(this.mobileNetClassMap).length });
|
|
682
728
|
// Load model
|
|
683
729
|
const sessionOptions = this.getSessionOptions();
|
|
684
730
|
try {
|
|
@@ -686,7 +732,7 @@ const JaakStamps = class {
|
|
|
686
732
|
}
|
|
687
733
|
catch (error) {
|
|
688
734
|
if (error.message.includes('failed to allocate a buffer')) {
|
|
689
|
-
this.
|
|
735
|
+
this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');
|
|
690
736
|
const fallbackOptions = {
|
|
691
737
|
executionProviders: ['wasm'],
|
|
692
738
|
graphOptimizationLevel: 'disabled',
|
|
@@ -703,10 +749,10 @@ const JaakStamps = class {
|
|
|
703
749
|
throw error;
|
|
704
750
|
}
|
|
705
751
|
}
|
|
706
|
-
this.
|
|
752
|
+
this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.mobileNetSession });
|
|
707
753
|
}
|
|
708
754
|
catch (error) {
|
|
709
|
-
this.
|
|
755
|
+
this.logger.error('Error al cargar modelo MobileNet:', error);
|
|
710
756
|
throw error;
|
|
711
757
|
}
|
|
712
758
|
}
|
|
@@ -733,11 +779,11 @@ const JaakStamps = class {
|
|
|
733
779
|
}
|
|
734
780
|
async classifyDocument(canvas) {
|
|
735
781
|
if (!this.mobileNetSession || !this.mobileNetClassMap) {
|
|
736
|
-
this.
|
|
782
|
+
this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');
|
|
737
783
|
return null;
|
|
738
784
|
}
|
|
739
785
|
try {
|
|
740
|
-
this.
|
|
786
|
+
this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
|
|
741
787
|
// Preprocess image for MobileNet
|
|
742
788
|
const inputTensor = this.preprocessMobileNet(canvas);
|
|
743
789
|
// Run inference
|
|
@@ -748,10 +794,11 @@ const JaakStamps = class {
|
|
|
748
794
|
const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
|
|
749
795
|
const confidence = output[maxIdx];
|
|
750
796
|
const className = this.mobileNetClassMap[maxIdx.toString()] || "unknown";
|
|
751
|
-
this.
|
|
797
|
+
this.logger.state('DOCUMENTO_CLASIFICADO', {
|
|
752
798
|
class: className,
|
|
753
799
|
confidence: confidence.toFixed(3),
|
|
754
|
-
classIndex: maxIdx
|
|
800
|
+
classIndex: maxIdx,
|
|
801
|
+
timestamp: Date.now()
|
|
755
802
|
});
|
|
756
803
|
return {
|
|
757
804
|
class: className,
|
|
@@ -760,7 +807,7 @@ const JaakStamps = class {
|
|
|
760
807
|
};
|
|
761
808
|
}
|
|
762
809
|
catch (error) {
|
|
763
|
-
this.
|
|
810
|
+
this.logger.error('Error al clasificar documento:', error);
|
|
764
811
|
return null;
|
|
765
812
|
}
|
|
766
813
|
}
|
|
@@ -802,7 +849,7 @@ const JaakStamps = class {
|
|
|
802
849
|
}
|
|
803
850
|
this.mobileNetClassMap = undefined;
|
|
804
851
|
this.isModelPreloaded = false;
|
|
805
|
-
this.
|
|
852
|
+
this.logger.state('CANVAS_POOL_LIMPIADO', { timestamp: Date.now() });
|
|
806
853
|
}
|
|
807
854
|
async getMaxResolution() {
|
|
808
855
|
try {
|
|
@@ -851,18 +898,19 @@ const JaakStamps = class {
|
|
|
851
898
|
constraints.width = { ideal: maxWidth };
|
|
852
899
|
constraints.height = { ideal: maxHeight };
|
|
853
900
|
}
|
|
854
|
-
this.
|
|
901
|
+
this.logger.state('CAPACIDADES_RESOLUCION_DETECTADAS', {
|
|
855
902
|
maxWidth: capabilities.width.max,
|
|
856
903
|
maxHeight: capabilities.height.max,
|
|
857
904
|
selectedWidth: constraints.width.ideal,
|
|
858
905
|
selectedHeight: constraints.height.ideal,
|
|
859
|
-
isTablet
|
|
906
|
+
isTablet,
|
|
907
|
+
deviceType: this.deviceType
|
|
860
908
|
});
|
|
861
909
|
}
|
|
862
910
|
return constraints;
|
|
863
911
|
}
|
|
864
912
|
catch (err) {
|
|
865
|
-
this.
|
|
913
|
+
this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');
|
|
866
914
|
// Optimized fallback for tablets
|
|
867
915
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
868
916
|
const fallbackConstraints = {
|
|
@@ -895,8 +943,11 @@ const JaakStamps = class {
|
|
|
895
943
|
// Determine if video should be mirrored
|
|
896
944
|
const isRear = this.isRearCamera(stream);
|
|
897
945
|
this.shouldMirrorVideo = !isRear;
|
|
898
|
-
this.
|
|
899
|
-
|
|
946
|
+
this.logger.state('CAMARA_CONFIGURADA', {
|
|
947
|
+
isRearCamera: isRear,
|
|
948
|
+
shouldMirrorVideo: this.shouldMirrorVideo,
|
|
949
|
+
videoActive: this.isVideoActive
|
|
950
|
+
});
|
|
900
951
|
return new Promise((resolve) => {
|
|
901
952
|
this.videoRef.onloadedmetadata = async () => {
|
|
902
953
|
await this.videoRef.play();
|
|
@@ -913,7 +964,7 @@ const JaakStamps = class {
|
|
|
913
964
|
}
|
|
914
965
|
}
|
|
915
966
|
catch (err) {
|
|
916
|
-
this.
|
|
967
|
+
this.logger.error('No se pudo acceder a la cámara:', err);
|
|
917
968
|
this.handleCameraPermissionError(err);
|
|
918
969
|
}
|
|
919
970
|
}
|
|
@@ -979,6 +1030,12 @@ const JaakStamps = class {
|
|
|
979
1030
|
};
|
|
980
1031
|
}
|
|
981
1032
|
async startDetection() {
|
|
1033
|
+
this.logger.state('INICIANDO_DETECCION', {
|
|
1034
|
+
sessionExists: !!this.session,
|
|
1035
|
+
modelPreloaded: this.isModelPreloaded,
|
|
1036
|
+
videoActive: this.isVideoActive,
|
|
1037
|
+
captureStep: this.captureStep
|
|
1038
|
+
});
|
|
982
1039
|
try {
|
|
983
1040
|
// Check if model is already preloaded
|
|
984
1041
|
if (!this.session) {
|
|
@@ -992,14 +1049,14 @@ const JaakStamps = class {
|
|
|
992
1049
|
this.statusColor = "#007bff";
|
|
993
1050
|
}
|
|
994
1051
|
const modelPath = this.MODEL_PATH;
|
|
995
|
-
this.
|
|
1052
|
+
this.logger.state('CARGANDO_MODELO_DETECCION', { modelPath });
|
|
996
1053
|
const sessionOptions = this.getSessionOptions();
|
|
997
1054
|
try {
|
|
998
1055
|
this.session = await window.ort.InferenceSession.create(modelPath, sessionOptions);
|
|
999
1056
|
}
|
|
1000
1057
|
catch (error) {
|
|
1001
1058
|
if (error.message.includes('failed to allocate a buffer')) {
|
|
1002
|
-
this.
|
|
1059
|
+
this.logger.warn('Fallo en asignación de buffer, intentando con configuración mínima');
|
|
1003
1060
|
const fallbackOptions = {
|
|
1004
1061
|
executionProviders: ['wasm'],
|
|
1005
1062
|
graphOptimizationLevel: 'disabled',
|
|
@@ -1030,7 +1087,7 @@ const JaakStamps = class {
|
|
|
1030
1087
|
this.emitReadyEvent();
|
|
1031
1088
|
}
|
|
1032
1089
|
else {
|
|
1033
|
-
this.
|
|
1090
|
+
this.logger.state('USANDO_MODELOS_PRECARGADOS', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
|
|
1034
1091
|
if (this.debug) {
|
|
1035
1092
|
this.statusMessage = "Usando modelos precargados...";
|
|
1036
1093
|
this.statusColor = "#007bff";
|
|
@@ -1049,7 +1106,7 @@ const JaakStamps = class {
|
|
|
1049
1106
|
this.detectFrame();
|
|
1050
1107
|
}
|
|
1051
1108
|
catch (err) {
|
|
1052
|
-
this.
|
|
1109
|
+
this.logger.error('Error al inicializar detección:', err);
|
|
1053
1110
|
this.statusMessage = "Error al inicializar el detector";
|
|
1054
1111
|
this.statusColor = "#ff6b6b";
|
|
1055
1112
|
this.isLoading = false;
|
|
@@ -1131,7 +1188,7 @@ const JaakStamps = class {
|
|
|
1131
1188
|
}
|
|
1132
1189
|
}
|
|
1133
1190
|
catch (e) {
|
|
1134
|
-
this.
|
|
1191
|
+
this.logger.error('Error en inferencia de modelo:', e);
|
|
1135
1192
|
// Solo continuar si no hemos completado el proceso
|
|
1136
1193
|
if (this.captureStep !== 'completed') {
|
|
1137
1194
|
// On error, wait longer before retrying
|
|
@@ -1259,7 +1316,7 @@ const JaakStamps = class {
|
|
|
1259
1316
|
if (!this.hasScreenshotTaken) {
|
|
1260
1317
|
this.lastDetectedBox = bestBox;
|
|
1261
1318
|
this.takeScreenshot().catch(error => {
|
|
1262
|
-
this.
|
|
1319
|
+
this.logger.error('Error al tomar captura de pantalla:', error);
|
|
1263
1320
|
});
|
|
1264
1321
|
this.hasScreenshotTaken = true;
|
|
1265
1322
|
// Reset para permitir segunda captura
|
|
@@ -1277,6 +1334,7 @@ const JaakStamps = class {
|
|
|
1277
1334
|
if (boxes.length === 0) {
|
|
1278
1335
|
this.statusMessage = "Posicione la identificación dentro del marco";
|
|
1279
1336
|
this.statusColor = "#ff6b6b";
|
|
1337
|
+
this.logger.debug('Sin detección de documento en el frame');
|
|
1280
1338
|
}
|
|
1281
1339
|
else {
|
|
1282
1340
|
const bestBox = boxes.reduce((best, current) => current.score > best.score ? current : best);
|
|
@@ -1286,6 +1344,11 @@ const JaakStamps = class {
|
|
|
1286
1344
|
if (allSidesAligned) {
|
|
1287
1345
|
this.statusMessage = "Identificación perfectamente alineada. Mantenga inmóvil";
|
|
1288
1346
|
this.statusColor = "#00ff00";
|
|
1347
|
+
this.logger.state('DOCUMENTO_PERFECTAMENTE_ALINEADO', {
|
|
1348
|
+
score: bestBox.score,
|
|
1349
|
+
boxDimensions: { width: bestBox.w, height: bestBox.h },
|
|
1350
|
+
alignedSides: 4
|
|
1351
|
+
});
|
|
1289
1352
|
}
|
|
1290
1353
|
else if (alignedSides > 0) {
|
|
1291
1354
|
this.statusMessage = `Alinee los lados restantes (${alignedSides}/4 lados correctos)`;
|
|
@@ -1346,6 +1409,14 @@ const JaakStamps = class {
|
|
|
1346
1409
|
async takeScreenshot() {
|
|
1347
1410
|
if (!this.videoRef || !this.lastDetectedBox)
|
|
1348
1411
|
return;
|
|
1412
|
+
this.logger.state('INICIANDO_CAPTURA', {
|
|
1413
|
+
captureStep: this.captureStep,
|
|
1414
|
+
detectedBox: this.lastDetectedBox,
|
|
1415
|
+
videoResolution: {
|
|
1416
|
+
width: this.videoRef.videoWidth,
|
|
1417
|
+
height: this.videoRef.videoHeight
|
|
1418
|
+
}
|
|
1419
|
+
});
|
|
1349
1420
|
// Activar animación
|
|
1350
1421
|
this.triggerCaptureAnimation();
|
|
1351
1422
|
// OPTIMIZATION: Reuse capture canvas for full frame
|
|
@@ -1385,7 +1456,7 @@ const JaakStamps = class {
|
|
|
1385
1456
|
await this.loadMobileNetModel();
|
|
1386
1457
|
}
|
|
1387
1458
|
catch (error) {
|
|
1388
|
-
this.
|
|
1459
|
+
this.logger.warn('Fallo al cargar modelo de clasificación, continuando sin clasificación:', error);
|
|
1389
1460
|
}
|
|
1390
1461
|
}
|
|
1391
1462
|
// Classify the cropped document if model is available
|
|
@@ -1393,7 +1464,7 @@ const JaakStamps = class {
|
|
|
1393
1464
|
const classification = await this.classifyDocument(croppedCanvas);
|
|
1394
1465
|
if (classification && classification.class === 'passport') {
|
|
1395
1466
|
// If it's a passport, skip back capture since passports don't have a back side
|
|
1396
|
-
this.
|
|
1467
|
+
this.logger.state('PASAPORTE_DETECTADO_SALTANDO_REVERSO', { classification: classification?.class });
|
|
1397
1468
|
this.completeProcess(true);
|
|
1398
1469
|
return;
|
|
1399
1470
|
}
|
|
@@ -1414,14 +1485,23 @@ const JaakStamps = class {
|
|
|
1414
1485
|
this.isDetectionPaused = false;
|
|
1415
1486
|
}, 3000);
|
|
1416
1487
|
}, 800);
|
|
1417
|
-
this.
|
|
1488
|
+
this.logger.state('CAPTURA_FRENTE_COMPLETADA', {
|
|
1489
|
+
captureStep: this.captureStep,
|
|
1490
|
+
hasFullFrame: !!this.capturedFullFrame,
|
|
1491
|
+
hasCroppedId: !!this.capturedCroppedId
|
|
1492
|
+
});
|
|
1418
1493
|
}
|
|
1419
1494
|
else if (this.captureStep === 'back') {
|
|
1420
1495
|
// Captura de la trasera usando canvas reutilizado
|
|
1421
1496
|
this.capturedBackFullFrame = this.captureCanvas.toDataURL('image/png');
|
|
1422
1497
|
this.capturedBackCroppedId = croppedCanvas.toDataURL('image/png');
|
|
1423
1498
|
this.completeProcess(false);
|
|
1424
|
-
this.
|
|
1499
|
+
this.logger.state('CAPTURA_TRASERA_COMPLETADA', {
|
|
1500
|
+
captureStep: this.captureStep,
|
|
1501
|
+
hasBackFullFrame: !!this.capturedBackFullFrame,
|
|
1502
|
+
hasBackCroppedId: !!this.capturedBackCroppedId,
|
|
1503
|
+
processCompleted: true
|
|
1504
|
+
});
|
|
1425
1505
|
}
|
|
1426
1506
|
}
|
|
1427
1507
|
triggerCaptureAnimation() {
|
|
@@ -1445,7 +1525,7 @@ const JaakStamps = class {
|
|
|
1445
1525
|
const ctx = this.canvasRef.getContext("2d");
|
|
1446
1526
|
ctx.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
|
|
1447
1527
|
}
|
|
1448
|
-
this.
|
|
1528
|
+
this.logger.state('DETECTOR_DETENIDO', { timestamp: Date.now() });
|
|
1449
1529
|
}
|
|
1450
1530
|
resetDetection() {
|
|
1451
1531
|
this.bestScore = 0;
|
|
@@ -1484,6 +1564,13 @@ const JaakStamps = class {
|
|
|
1484
1564
|
"Proceso completado (solo frente capturado)" :
|
|
1485
1565
|
"Proceso de captura completado exitosamente";
|
|
1486
1566
|
this.statusColor = "#28a745";
|
|
1567
|
+
this.logger.state('PROCESO_COMPLETADO', {
|
|
1568
|
+
skippedBack,
|
|
1569
|
+
hasFrontImages: !!(this.capturedFullFrame && this.capturedCroppedId),
|
|
1570
|
+
hasBackImages: !!(this.capturedBackFullFrame && this.capturedBackCroppedId),
|
|
1571
|
+
totalImages: skippedBack ? 2 : 4,
|
|
1572
|
+
timestamp: new Date().toISOString()
|
|
1573
|
+
});
|
|
1487
1574
|
// Detener el detector
|
|
1488
1575
|
this.stopDetection();
|
|
1489
1576
|
// Emitir evento con las imágenes capturadas
|
|
@@ -1535,7 +1622,7 @@ const JaakStamps = class {
|
|
|
1535
1622
|
this.cleanup();
|
|
1536
1623
|
}
|
|
1537
1624
|
render() {
|
|
1538
|
-
return (h("div", { key: '
|
|
1625
|
+
return (h("div", { key: '87e2e2065012b5792b52b18349490492b5bdc80c', class: "detector-container" }, h("div", { key: '04b8bba38297d39c84ddc01f5a9bf72c65b9bef4', class: "video-container" }, h("video", { key: '905b99e1670fccb2ff5555818f91d0b0241fa29d', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: this.isVideoActive ? 'block' : 'none' } }), h("canvas", { key: '3f219b649b8d4f961b15256b8586451c2a737eb8', ref: el => this.canvasRef = el, class: this.shouldMirrorVideo ? 'mirror' : '' }), this.isMaskReady && (h("div", { key: 'f8d6742689d4446897ca48c2407cb3d3fab643e9', class: "overlay-mask" }, h("div", { key: '630a06c530f168cc0b71286adbf48fd922eb710d', class: "card-outline" }, h("div", { key: 'ce8c043ad41d5574cd0c4d737dec08b9f7fee927', class: "side side-top" }), h("div", { key: 'e90ead592f84e5df98143bc88714e70f32684204', class: "side side-right" }), h("div", { key: '31d6778c5036e42a3addb26c732149abc5a18ef7', class: "side side-bottom" }), h("div", { key: 'f85c31e77f024f9070c706b06b91d62a7fdbc357', class: "side side-left" }), h("div", { key: '27b362711bc53019483c0d36742d97e10ae9b9ce', class: "corner corner-tl" }), h("div", { key: '03b55893610684d690987c2eacf3c4e5d0c3bbe5', class: "corner corner-tr" }), h("div", { key: 'b6bf31327925c45a7fa8e1fd5ab2f25b824a03a2', class: "corner corner-bl" }), h("div", { key: '0737e0c82f8ad9703ce2546f3e594db6d50cafde', class: "corner corner-br" }), !this.showFlipAnimation && !this.showSuccessAnimation && (h("div", { key: '145f8383c496e151bd6ef4f5841292adeba083c4', class: "guide-text" }, this.statusMessage))), this.captureStep === 'back' && !this.showFlipAnimation && !this.showSuccessAnimation && (h("button", { key: 'fcdedebc31eddd21b978dd63e93c348d324b47da', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")), this.isVideoActive && (h("div", { key: 'dc9157bf7bed3b6439db742055201e2c4eddec84', class: "camera-controls" }, this.isMultipleCamerasAvailable && (h("button", { key: '6b052562ccb203dbf3cc8b627f31ed2435559f80', class: "flip-camera-button", onClick: () => this.flipCamera(), type: "button", title: "Cambiar c\u00E1mara" }, "Girar c\u00E1mara")), h("button", { key: 'f9fad1757d01f0cb45f65bb2088bd1f0bc0e4e8d', class: "camera-selector-button", onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara" }, "C\u00E1maras"), this.debug && (h("div", { key: '5362fb33508c7f903b09f65fdb449b608804260d', style: {
|
|
1539
1626
|
position: 'absolute',
|
|
1540
1627
|
top: '50px',
|
|
1541
1628
|
right: '0',
|
|
@@ -1545,10 +1632,10 @@ const JaakStamps = class {
|
|
|
1545
1632
|
fontSize: '10px',
|
|
1546
1633
|
borderRadius: '4px',
|
|
1547
1634
|
whiteSpace: 'nowrap'
|
|
1548
|
-
} }, "C\u00E1maras: ", this.availableCameras.length, h("br", { key: '
|
|
1635
|
+
} }, "C\u00E1maras: ", this.availableCameras.length, h("br", { key: '5ead451a54a59c885f62740d0a0ce43ba8b674e4' }), "M\u00FAltiples: ", this.isMultipleCamerasAvailable ? 'Sí' : 'No', h("br", { key: '9a92514d07576ed7052eaa3a418c00013ef7c479' }), "Selector: ", this.showCameraSelector ? 'Visible' : 'Oculto', h("br", { key: 'd06abebad3b2e3c19aa22e511e0c4cfd4425b8b2' }), "Video: ", this.isVideoActive ? 'Activo' : 'Inactivo')))), this.showCameraSelector && this.availableCameras.length > 0 && (h("div", { key: '93a09ce3bb108175b55944a71c21e86e58de55be', class: "camera-selector-dropdown" }, h("div", { key: '7ceb4c8826945ab2a9da106a88a44cbb5490e92a', class: "camera-selector-header" }, h("span", { key: 'fa98621700584d8021ff57eca6f804b6eb792c5b' }, "Seleccionar C\u00E1mara"), h("button", { key: 'ce6477a1494f58fb5974dd7c9e62bd7d041572c5', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'eff226b006c95fafce2566947155e13ee68f9a02', class: "camera-list" }, this.availableCameras.map((camera) => (h("button", { key: camera.deviceId, class: `camera-option ${this.selectedCameraId === camera.deviceId ? 'selected' : ''}`, onClick: () => {
|
|
1549
1636
|
this.switchCamera(camera.deviceId);
|
|
1550
1637
|
this.toggleCameraSelector();
|
|
1551
|
-
}, type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${this.availableCameras.indexOf(camera) + 1}`), this.selectedCameraId === camera.deviceId && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '
|
|
1638
|
+
}, type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${this.availableCameras.indexOf(camera) + 1}`), this.selectedCameraId === camera.deviceId && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '617d33caa5d3b3e6dca56d479b27c0ac7ed19c2c', class: "device-info" }, h("small", { key: 'fba56ac1238c33864f8dba1d8bd9a5661e11d770' }, "Dispositivo: ", this.deviceType)))))), this.isCapturing && (h("div", { key: 'b46982a0b949ee9d50d0a819c59b24dceec9d7b2', class: "capture-animation" })), this.showFlipAnimation && (h("div", { key: 'c82773fffca8ec53949197a105e1e11bf0f9b294', class: "flip-animation" }, h("div", { key: 'ad52c9ec91132bf5ed94e36f621489a66b0bf680', class: "id-card-icon" }), h("div", { key: '2be407ee84beddc5ce968a9a94d9014f416cde54', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), this.showSuccessAnimation && (h("div", { key: 'f20b6be925178a123de99e535e893b7c09391dee', class: "success-animation" }, h("div", { key: 'd3ae65d40943f73bc92e9529764ded454adc5dbf', class: "check-icon" }), h("div", { key: 'f2b03082a106c69f09d384ba3b1cb4a636d3a189', class: "success-text" }, "\u00A1Proceso completado!"))), this.isLoading && (h("div", { key: '65736e303d9eb1c3f6f2dccb5cc0d27c571ac9c8', class: "loading-overlay" }, h("div", { key: '5863d855d1caea9202a9f3d0a29919985ddbb926', class: "loading-spinner" }), h("div", { key: 'aa5a16c96ac6bfa43846ba06346fad6dce39dfbb', class: "loading-text" }, this.statusMessage))), this.debug && (h("div", { key: '308c664b07d2c2427c38f766fc9eb78d27843f67', class: "status-bar" }, h("div", { key: '3884b311710d7f373a508eb492771e503e68f648', class: "status-message", style: { 'color': this.statusColor } }, this.statusMessage))), h("div", { key: '3125cfecda03d3ab9e80e0d9d5674f1cc167e2f8', class: "watermark" }, h("img", { key: '5ef43a18aea74f570db0d61f4fd86c3becf1d23e', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
|
|
1552
1639
|
}
|
|
1553
1640
|
};
|
|
1554
1641
|
JaakStamps.style = myComponentCss;
|