@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
|
@@ -68,34 +68,65 @@ export class JaakStamps {
|
|
|
68
68
|
CONFIDENCE_THRESHOLD = 0.6;
|
|
69
69
|
// ISO/IEC 7810 ID-1 standard dimensions (85.60mm x 53.98mm)
|
|
70
70
|
ID1_ASPECT_RATIO = 85.60 / 53.98; // 1.5863320574...
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
logger = {
|
|
72
|
+
info: (...args) => {
|
|
73
|
+
if (this.debug) {
|
|
74
|
+
console.log(`[JAAK-STAMPS] [INFO] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
warn: (...args) => {
|
|
78
|
+
if (this.debug) {
|
|
79
|
+
console.warn(`[JAAK-STAMPS] [WARN] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
error: (...args) => {
|
|
83
|
+
if (this.debug) {
|
|
84
|
+
console.error(`[JAAK-STAMPS] [ERROR] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
debug: (...args) => {
|
|
88
|
+
if (this.debug) {
|
|
89
|
+
console.debug(`[JAAK-STAMPS] [DEBUG] [${new Date().toLocaleTimeString()}]`, ...args);
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
state: (state, data) => {
|
|
93
|
+
if (this.debug) {
|
|
94
|
+
console.log(`[JAAK-STAMPS] [STATE] [${new Date().toLocaleTimeString()}] ${state}`, data || '');
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
performance: (operation, duration) => {
|
|
98
|
+
if (this.debug) {
|
|
99
|
+
console.log(`[JAAK-STAMPS] [PERF] [${new Date().toLocaleTimeString()}] ${operation}: ${duration}ms`);
|
|
100
|
+
}
|
|
74
101
|
}
|
|
75
|
-
}
|
|
102
|
+
};
|
|
76
103
|
validateMaskSize() {
|
|
77
104
|
if (this.maskSize < 50 || this.maskSize > 100) {
|
|
78
|
-
|
|
105
|
+
this.logger.warn(`Propiedad maskSize inválida. Valor: ${this.maskSize}, esperado: 50-100. Usando valor por defecto: 90`);
|
|
79
106
|
this.maskSize = 90;
|
|
80
107
|
}
|
|
81
108
|
}
|
|
82
109
|
validateCropMargin() {
|
|
83
110
|
if (this.cropMargin < 0 || this.cropMargin > 100) {
|
|
84
|
-
|
|
111
|
+
this.logger.warn(`Propiedad cropMargin inválida. Valor: ${this.cropMargin}, esperado: 0-100. Usando valor por defecto: 0`);
|
|
85
112
|
this.cropMargin = 0;
|
|
86
113
|
}
|
|
87
114
|
}
|
|
88
115
|
validatePreferredCamera() {
|
|
89
116
|
const validOptions = ['auto', 'front', 'back'];
|
|
90
117
|
if (!validOptions.includes(this.preferredCamera)) {
|
|
91
|
-
|
|
118
|
+
this.logger.warn(`Propiedad preferredCamera inválida. Valor: ${this.preferredCamera}, esperado: ${validOptions.join(', ')}. Usando valor por defecto: 'auto'`);
|
|
92
119
|
this.preferredCamera = 'auto';
|
|
93
120
|
}
|
|
94
121
|
}
|
|
95
122
|
emitReadyEvent() {
|
|
96
123
|
const isDocumentReady = !!window.ort && this.isModelPreloaded;
|
|
97
124
|
this.isReady.emit(isDocumentReady);
|
|
98
|
-
this.
|
|
125
|
+
this.logger.state('COMPONENTE_LISTO', {
|
|
126
|
+
ortLibraryLoaded: !!window.ort,
|
|
127
|
+
modelPreloaded: this.isModelPreloaded,
|
|
128
|
+
isReady: isDocumentReady
|
|
129
|
+
});
|
|
99
130
|
}
|
|
100
131
|
isRearCamera(stream) {
|
|
101
132
|
const videoTrack = stream.getVideoTracks()[0];
|
|
@@ -118,7 +149,11 @@ export class JaakStamps {
|
|
|
118
149
|
else {
|
|
119
150
|
this.deviceType = 'desktop';
|
|
120
151
|
}
|
|
121
|
-
this.
|
|
152
|
+
this.logger.state('DISPOSITIVO_DETECTADO', {
|
|
153
|
+
deviceType: this.deviceType,
|
|
154
|
+
userAgent: navigator.userAgent,
|
|
155
|
+
screenDimensions: { width: window.innerWidth, height: window.innerHeight }
|
|
156
|
+
});
|
|
122
157
|
// Enumerate available cameras
|
|
123
158
|
await this.enumerateAndDetectCameras();
|
|
124
159
|
// Load user preference
|
|
@@ -129,7 +164,7 @@ export class JaakStamps {
|
|
|
129
164
|
// First, check if we have permission to enumerate devices
|
|
130
165
|
const permissionStatus = await this.checkCameraPermission();
|
|
131
166
|
if (permissionStatus === 'denied') {
|
|
132
|
-
this.
|
|
167
|
+
this.logger.error('Permiso de cámara denegado por el usuario');
|
|
133
168
|
this.statusMessage = "Permiso de cámara denegado";
|
|
134
169
|
this.statusColor = "#ff6b6b";
|
|
135
170
|
return;
|
|
@@ -143,7 +178,7 @@ export class JaakStamps {
|
|
|
143
178
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
144
179
|
this.availableCameras = devices.filter(device => device.kind === 'videoinput');
|
|
145
180
|
this.isMultipleCamerasAvailable = this.availableCameras.length > 1;
|
|
146
|
-
this.
|
|
181
|
+
this.logger.state('CAMARAS_DETECTADAS', {
|
|
147
182
|
count: this.availableCameras.length,
|
|
148
183
|
isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
|
|
149
184
|
cameras: this.availableCameras.map(cam => ({
|
|
@@ -155,7 +190,7 @@ export class JaakStamps {
|
|
|
155
190
|
this.setInitialCameraPreference();
|
|
156
191
|
}
|
|
157
192
|
catch (error) {
|
|
158
|
-
this.
|
|
193
|
+
this.logger.error('Error al enumerar cámaras disponibles:', error);
|
|
159
194
|
this.handleCameraPermissionError(error);
|
|
160
195
|
}
|
|
161
196
|
}
|
|
@@ -168,7 +203,7 @@ export class JaakStamps {
|
|
|
168
203
|
return permission.state;
|
|
169
204
|
}
|
|
170
205
|
catch (error) {
|
|
171
|
-
this.
|
|
206
|
+
this.logger.warn('No se pudo verificar permisos de cámara:', error);
|
|
172
207
|
return 'prompt';
|
|
173
208
|
}
|
|
174
209
|
}
|
|
@@ -211,11 +246,11 @@ export class JaakStamps {
|
|
|
211
246
|
!camera.label.toLowerCase().includes('back') && !camera.label.toLowerCase().includes('rear'));
|
|
212
247
|
if (frontCamera) {
|
|
213
248
|
this.selectedCameraId = frontCamera.deviceId;
|
|
214
|
-
this.
|
|
249
|
+
this.logger.state('CAMARA_FRONTAL_SELECCIONADA', { label: frontCamera.label, deviceId: frontCamera.deviceId });
|
|
215
250
|
}
|
|
216
251
|
else {
|
|
217
252
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
218
|
-
this.
|
|
253
|
+
this.logger.warn('Cámara frontal no encontrada, usando primera disponible:', this.availableCameras[0].label);
|
|
219
254
|
}
|
|
220
255
|
}
|
|
221
256
|
else if (this.preferredCamera === 'back') {
|
|
@@ -226,11 +261,11 @@ export class JaakStamps {
|
|
|
226
261
|
camera.label.toLowerCase().includes('environment'));
|
|
227
262
|
if (backCamera) {
|
|
228
263
|
this.selectedCameraId = backCamera.deviceId;
|
|
229
|
-
this.
|
|
264
|
+
this.logger.state('CAMARA_TRASERA_SELECCIONADA', { label: backCamera.label, deviceId: backCamera.deviceId });
|
|
230
265
|
}
|
|
231
266
|
else {
|
|
232
267
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
233
|
-
this.
|
|
268
|
+
this.logger.warn('Cámara trasera no encontrada, usando primera disponible:', this.availableCameras[0].label);
|
|
234
269
|
}
|
|
235
270
|
}
|
|
236
271
|
else {
|
|
@@ -243,17 +278,17 @@ export class JaakStamps {
|
|
|
243
278
|
camera.label.toLowerCase().includes('environment'));
|
|
244
279
|
if (rearCamera) {
|
|
245
280
|
this.selectedCameraId = rearCamera.deviceId;
|
|
246
|
-
this.
|
|
281
|
+
this.logger.state('CAMARA_AUTO_SELECCIONADA_MOBILE', { type: 'rear', label: rearCamera.label, deviceId: rearCamera.deviceId });
|
|
247
282
|
}
|
|
248
283
|
else {
|
|
249
284
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
250
|
-
this.
|
|
285
|
+
this.logger.warn('Cámara trasera no encontrada en mobile, usando primera disponible:', this.availableCameras[0].label);
|
|
251
286
|
}
|
|
252
287
|
}
|
|
253
288
|
else {
|
|
254
289
|
// For desktop, use first available camera (usually the only one)
|
|
255
290
|
this.selectedCameraId = this.availableCameras[0].deviceId;
|
|
256
|
-
this.
|
|
291
|
+
this.logger.state('CAMARA_AUTO_SELECCIONADA_DESKTOP', { label: this.availableCameras[0].label, deviceId: this.availableCameras[0].deviceId });
|
|
257
292
|
}
|
|
258
293
|
}
|
|
259
294
|
}
|
|
@@ -267,12 +302,12 @@ export class JaakStamps {
|
|
|
267
302
|
if (isStillAvailable) {
|
|
268
303
|
this.selectedCameraId = preference.cameraId;
|
|
269
304
|
this.preferredCameraFacing = preference.facing;
|
|
270
|
-
this.
|
|
305
|
+
this.logger.state('PREFERENCIA_CAMARA_CARGADA', preference);
|
|
271
306
|
}
|
|
272
307
|
}
|
|
273
308
|
}
|
|
274
309
|
catch (error) {
|
|
275
|
-
this.
|
|
310
|
+
this.logger.warn('Error al cargar preferencia de cámara:', error);
|
|
276
311
|
}
|
|
277
312
|
}
|
|
278
313
|
saveCameraPreference() {
|
|
@@ -283,10 +318,10 @@ export class JaakStamps {
|
|
|
283
318
|
timestamp: Date.now()
|
|
284
319
|
};
|
|
285
320
|
localStorage.setItem('jaak-stamps-camera-preference', JSON.stringify(preference));
|
|
286
|
-
this.
|
|
321
|
+
this.logger.state('PREFERENCIA_CAMARA_GUARDADA', preference);
|
|
287
322
|
}
|
|
288
323
|
catch (error) {
|
|
289
|
-
this.
|
|
324
|
+
this.logger.warn('Error al guardar preferencia de cámara:', error);
|
|
290
325
|
}
|
|
291
326
|
}
|
|
292
327
|
async switchCamera(cameraId) {
|
|
@@ -296,7 +331,7 @@ export class JaakStamps {
|
|
|
296
331
|
// Check if the selected camera is still available
|
|
297
332
|
const selectedCamera = this.availableCameras.find(cam => cam.deviceId === cameraId);
|
|
298
333
|
if (!selectedCamera) {
|
|
299
|
-
this.
|
|
334
|
+
this.logger.warn('Cámara seleccionada no encontrada, re-enumerando dispositivos...');
|
|
300
335
|
await this.enumerateAndDetectCameras();
|
|
301
336
|
return;
|
|
302
337
|
}
|
|
@@ -320,10 +355,10 @@ export class JaakStamps {
|
|
|
320
355
|
this.saveCameraPreference();
|
|
321
356
|
// Setup new camera with error handling
|
|
322
357
|
await this.setupCameraWithRetry();
|
|
323
|
-
this.
|
|
358
|
+
this.logger.state('CAMARA_CAMBIADA', { label: selectedCamera.label, deviceId: selectedCamera.deviceId });
|
|
324
359
|
}
|
|
325
360
|
catch (error) {
|
|
326
|
-
this.
|
|
361
|
+
this.logger.error('Error al cambiar de cámara:', error);
|
|
327
362
|
this.handleCameraPermissionError(error);
|
|
328
363
|
}
|
|
329
364
|
}
|
|
@@ -338,7 +373,7 @@ export class JaakStamps {
|
|
|
338
373
|
return; // Success
|
|
339
374
|
}
|
|
340
375
|
catch (error) {
|
|
341
|
-
this.
|
|
376
|
+
this.logger.error(`Intento ${attempt} de configuración de cámara fallido:`, error);
|
|
342
377
|
if (attempt === maxRetries) {
|
|
343
378
|
// Last attempt failed, handle the error
|
|
344
379
|
this.statusMessage = "Error al configurar la cámara";
|
|
@@ -358,7 +393,7 @@ export class JaakStamps {
|
|
|
358
393
|
}
|
|
359
394
|
toggleCameraSelector() {
|
|
360
395
|
this.showCameraSelector = !this.showCameraSelector;
|
|
361
|
-
this.
|
|
396
|
+
this.logger.state('SELECTOR_CAMARA_TOGGLE', {
|
|
362
397
|
showCameraSelector: this.showCameraSelector,
|
|
363
398
|
isMultipleCamerasAvailable: this.isMultipleCamerasAvailable,
|
|
364
399
|
availableCameras: this.availableCameras.length,
|
|
@@ -374,6 +409,13 @@ export class JaakStamps {
|
|
|
374
409
|
await this.switchCamera(nextCamera.deviceId);
|
|
375
410
|
}
|
|
376
411
|
async componentDidLoad() {
|
|
412
|
+
this.logger.state('COMPONENTE_INICIALIZANDO', {
|
|
413
|
+
debug: this.debug,
|
|
414
|
+
maskSize: this.maskSize,
|
|
415
|
+
cropMargin: this.cropMargin,
|
|
416
|
+
useDocumentClassification: this.useDocumentClassification,
|
|
417
|
+
preferredCamera: this.preferredCamera
|
|
418
|
+
});
|
|
377
419
|
if (this.debug) {
|
|
378
420
|
// Show detailed initialization loading state only in debug mode
|
|
379
421
|
this.isLoading = true;
|
|
@@ -438,7 +480,7 @@ export class JaakStamps {
|
|
|
438
480
|
this.canvasRef.height = rect.height;
|
|
439
481
|
// Update mask positioning based on container and video dimensions
|
|
440
482
|
this.updateMaskDimensions(rect);
|
|
441
|
-
this.
|
|
483
|
+
this.logger.debug('Canvas redimensionado:', { width: rect.width, height: rect.height });
|
|
442
484
|
}
|
|
443
485
|
}
|
|
444
486
|
updateMaskDimensions(containerRect) {
|
|
@@ -498,7 +540,7 @@ export class JaakStamps {
|
|
|
498
540
|
this.el.style.setProperty('--mask-center-y', `${videoCenterYPercent}%`);
|
|
499
541
|
// Mark mask as ready now that dimensions are calculated
|
|
500
542
|
this.isMaskReady = true;
|
|
501
|
-
this.
|
|
543
|
+
this.logger.state('DIMENSIONES_MASCARA_ACTUALIZADAS', {
|
|
502
544
|
video: { width: videoWidth, height: videoHeight },
|
|
503
545
|
displayed: { width: displayedVideoWidth, height: displayedVideoHeight },
|
|
504
546
|
mask: { widthPercent: maskWidthPercent, heightPercent: maskHeightPercent },
|
|
@@ -520,7 +562,7 @@ export class JaakStamps {
|
|
|
520
562
|
this.captureCtx = this.captureCanvas.getContext('2d', {
|
|
521
563
|
alpha: false
|
|
522
564
|
});
|
|
523
|
-
this.
|
|
565
|
+
this.logger.state('CANVAS_POOL_INICIALIZADO', { preprocessCanvasSize: this.INPUT_SIZE });
|
|
524
566
|
}
|
|
525
567
|
disconnectedCallback() {
|
|
526
568
|
this.cleanup();
|
|
@@ -568,7 +610,7 @@ export class JaakStamps {
|
|
|
568
610
|
}
|
|
569
611
|
async preloadModel() {
|
|
570
612
|
if (this.isModelPreloaded || this.session) {
|
|
571
|
-
this.
|
|
613
|
+
this.logger.state('MODELO_YA_PRECARGADO', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
|
|
572
614
|
return { success: true, message: 'Model already loaded' };
|
|
573
615
|
}
|
|
574
616
|
try {
|
|
@@ -576,7 +618,7 @@ export class JaakStamps {
|
|
|
576
618
|
this.statusMessage = "Precargando modelos...";
|
|
577
619
|
this.statusColor = "#007bff";
|
|
578
620
|
const modelPath = this.MODEL_PATH;
|
|
579
|
-
this.
|
|
621
|
+
this.logger.state('PRECARGANDO_MODELO_DETECCION', { modelPath });
|
|
580
622
|
// Configure ONNX Runtime with device-specific optimizations
|
|
581
623
|
const sessionOptions = this.getSessionOptions();
|
|
582
624
|
const deviceInfo = this.getDeviceMemoryInfo();
|
|
@@ -585,7 +627,7 @@ export class JaakStamps {
|
|
|
585
627
|
}
|
|
586
628
|
catch (error) {
|
|
587
629
|
if (error.message.includes('failed to allocate a buffer')) {
|
|
588
|
-
this.
|
|
630
|
+
this.logger.warn('Fallo en asignación de buffer durante precarga, intentando con configuración mínima');
|
|
589
631
|
const fallbackOptions = {
|
|
590
632
|
executionProviders: ['wasm'],
|
|
591
633
|
graphOptimizationLevel: 'disabled',
|
|
@@ -606,7 +648,7 @@ export class JaakStamps {
|
|
|
606
648
|
// For low memory devices, load sequentially to avoid memory pressure
|
|
607
649
|
if (this.useDocumentClassification) {
|
|
608
650
|
if (deviceInfo.isLowMemory) {
|
|
609
|
-
this.
|
|
651
|
+
this.logger.state('CARGA_SECUENCIAL_MODELOS', { reason: 'low memory device' });
|
|
610
652
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
611
653
|
}
|
|
612
654
|
await this.loadMobileNetModel();
|
|
@@ -616,11 +658,15 @@ export class JaakStamps {
|
|
|
616
658
|
this.statusMessage = "Modelos precargados. Listo para comenzar detección";
|
|
617
659
|
this.statusColor = "#28a745";
|
|
618
660
|
this.emitReadyEvent();
|
|
619
|
-
this.
|
|
661
|
+
this.logger.state('MODELOS_PRECARGADOS_EXITOSAMENTE', {
|
|
662
|
+
detectionModel: !!this.session,
|
|
663
|
+
classificationModel: !!this.mobileNetSession,
|
|
664
|
+
useClassification: this.useDocumentClassification
|
|
665
|
+
});
|
|
620
666
|
return { success: true, message: 'Models preloaded successfully' };
|
|
621
667
|
}
|
|
622
668
|
catch (error) {
|
|
623
|
-
this.
|
|
669
|
+
this.logger.error('Error al precargar modelos:', error);
|
|
624
670
|
this.isLoading = false;
|
|
625
671
|
this.statusMessage = "Error al precargar los modelos";
|
|
626
672
|
this.statusColor = "#ff6b6b";
|
|
@@ -648,7 +694,7 @@ export class JaakStamps {
|
|
|
648
694
|
}
|
|
649
695
|
async setPreferredCamera(camera) {
|
|
650
696
|
this.preferredCamera = camera;
|
|
651
|
-
this.
|
|
697
|
+
this.logger.state('PREFERENCIA_CAMARA_CAMBIADA', { newPreference: camera });
|
|
652
698
|
// Re-detect and apply new camera preference
|
|
653
699
|
await this.enumerateAndDetectCameras();
|
|
654
700
|
// If video is active, switch to the new preferred camera
|
|
@@ -663,14 +709,14 @@ export class JaakStamps {
|
|
|
663
709
|
}
|
|
664
710
|
async loadMobileNetModel() {
|
|
665
711
|
try {
|
|
666
|
-
this.
|
|
712
|
+
this.logger.state('CARGANDO_MODELO_MOBILENET', { path: this.MOBILENET_MODEL_PATH });
|
|
667
713
|
// Load class map
|
|
668
714
|
const classResponse = await fetch(this.MOBILENET_CLASSES_PATH);
|
|
669
715
|
if (!classResponse.ok) {
|
|
670
716
|
throw new Error(`Failed to load class map: ${this.MOBILENET_CLASSES_PATH}`);
|
|
671
717
|
}
|
|
672
718
|
this.mobileNetClassMap = await classResponse.json();
|
|
673
|
-
this.
|
|
719
|
+
this.logger.state('CLASES_MOBILENET_CARGADAS', { classCount: Object.keys(this.mobileNetClassMap).length });
|
|
674
720
|
// Load model
|
|
675
721
|
const sessionOptions = this.getSessionOptions();
|
|
676
722
|
try {
|
|
@@ -678,7 +724,7 @@ export class JaakStamps {
|
|
|
678
724
|
}
|
|
679
725
|
catch (error) {
|
|
680
726
|
if (error.message.includes('failed to allocate a buffer')) {
|
|
681
|
-
this.
|
|
727
|
+
this.logger.warn('Fallo en asignación de buffer de MobileNet, intentando con configuración mínima');
|
|
682
728
|
const fallbackOptions = {
|
|
683
729
|
executionProviders: ['wasm'],
|
|
684
730
|
graphOptimizationLevel: 'disabled',
|
|
@@ -695,10 +741,10 @@ export class JaakStamps {
|
|
|
695
741
|
throw error;
|
|
696
742
|
}
|
|
697
743
|
}
|
|
698
|
-
this.
|
|
744
|
+
this.logger.state('MODELO_MOBILENET_CARGADO_EXITOSAMENTE', { sessionCreated: !!this.mobileNetSession });
|
|
699
745
|
}
|
|
700
746
|
catch (error) {
|
|
701
|
-
this.
|
|
747
|
+
this.logger.error('Error al cargar modelo MobileNet:', error);
|
|
702
748
|
throw error;
|
|
703
749
|
}
|
|
704
750
|
}
|
|
@@ -725,11 +771,11 @@ export class JaakStamps {
|
|
|
725
771
|
}
|
|
726
772
|
async classifyDocument(canvas) {
|
|
727
773
|
if (!this.mobileNetSession || !this.mobileNetClassMap) {
|
|
728
|
-
this.
|
|
774
|
+
this.logger.warn('Modelo MobileNet no está cargado, saltando clasificación');
|
|
729
775
|
return null;
|
|
730
776
|
}
|
|
731
777
|
try {
|
|
732
|
-
this.
|
|
778
|
+
this.logger.state('CLASIFICANDO_DOCUMENTO', { timestamp: Date.now() });
|
|
733
779
|
// Preprocess image for MobileNet
|
|
734
780
|
const inputTensor = this.preprocessMobileNet(canvas);
|
|
735
781
|
// Run inference
|
|
@@ -740,10 +786,11 @@ export class JaakStamps {
|
|
|
740
786
|
const maxIdx = output.reduce((bestIdx, val, idx, arr) => val > arr[bestIdx] ? idx : bestIdx, 0);
|
|
741
787
|
const confidence = output[maxIdx];
|
|
742
788
|
const className = this.mobileNetClassMap[maxIdx.toString()] || "unknown";
|
|
743
|
-
this.
|
|
789
|
+
this.logger.state('DOCUMENTO_CLASIFICADO', {
|
|
744
790
|
class: className,
|
|
745
791
|
confidence: confidence.toFixed(3),
|
|
746
|
-
classIndex: maxIdx
|
|
792
|
+
classIndex: maxIdx,
|
|
793
|
+
timestamp: Date.now()
|
|
747
794
|
});
|
|
748
795
|
return {
|
|
749
796
|
class: className,
|
|
@@ -752,7 +799,7 @@ export class JaakStamps {
|
|
|
752
799
|
};
|
|
753
800
|
}
|
|
754
801
|
catch (error) {
|
|
755
|
-
this.
|
|
802
|
+
this.logger.error('Error al clasificar documento:', error);
|
|
756
803
|
return null;
|
|
757
804
|
}
|
|
758
805
|
}
|
|
@@ -794,7 +841,7 @@ export class JaakStamps {
|
|
|
794
841
|
}
|
|
795
842
|
this.mobileNetClassMap = undefined;
|
|
796
843
|
this.isModelPreloaded = false;
|
|
797
|
-
this.
|
|
844
|
+
this.logger.state('CANVAS_POOL_LIMPIADO', { timestamp: Date.now() });
|
|
798
845
|
}
|
|
799
846
|
async getMaxResolution() {
|
|
800
847
|
try {
|
|
@@ -844,18 +891,19 @@ export class JaakStamps {
|
|
|
844
891
|
constraints.width = { ideal: maxWidth };
|
|
845
892
|
constraints.height = { ideal: maxHeight };
|
|
846
893
|
}
|
|
847
|
-
this.
|
|
894
|
+
this.logger.state('CAPACIDADES_RESOLUCION_DETECTADAS', {
|
|
848
895
|
maxWidth: capabilities.width.max,
|
|
849
896
|
maxHeight: capabilities.height.max,
|
|
850
897
|
selectedWidth: constraints.width.ideal,
|
|
851
898
|
selectedHeight: constraints.height.ideal,
|
|
852
|
-
isTablet
|
|
899
|
+
isTablet,
|
|
900
|
+
deviceType: this.deviceType
|
|
853
901
|
});
|
|
854
902
|
}
|
|
855
903
|
return constraints;
|
|
856
904
|
}
|
|
857
905
|
catch (err) {
|
|
858
|
-
this.
|
|
906
|
+
this.logger.warn('No se pudieron obtener capacidades de cámara, usando configuración de respaldo');
|
|
859
907
|
// Optimized fallback for tablets
|
|
860
908
|
const isTablet = /iPad|Android/i.test(navigator.userAgent) && window.innerWidth >= 768;
|
|
861
909
|
const fallbackConstraints = {
|
|
@@ -888,8 +936,11 @@ export class JaakStamps {
|
|
|
888
936
|
// Determine if video should be mirrored
|
|
889
937
|
const isRear = this.isRearCamera(stream);
|
|
890
938
|
this.shouldMirrorVideo = !isRear;
|
|
891
|
-
this.
|
|
892
|
-
|
|
939
|
+
this.logger.state('CAMARA_CONFIGURADA', {
|
|
940
|
+
isRearCamera: isRear,
|
|
941
|
+
shouldMirrorVideo: this.shouldMirrorVideo,
|
|
942
|
+
videoActive: this.isVideoActive
|
|
943
|
+
});
|
|
893
944
|
return new Promise((resolve) => {
|
|
894
945
|
this.videoRef.onloadedmetadata = async () => {
|
|
895
946
|
await this.videoRef.play();
|
|
@@ -906,7 +957,7 @@ export class JaakStamps {
|
|
|
906
957
|
}
|
|
907
958
|
}
|
|
908
959
|
catch (err) {
|
|
909
|
-
this.
|
|
960
|
+
this.logger.error('No se pudo acceder a la cámara:', err);
|
|
910
961
|
this.handleCameraPermissionError(err);
|
|
911
962
|
}
|
|
912
963
|
}
|
|
@@ -972,6 +1023,12 @@ export class JaakStamps {
|
|
|
972
1023
|
};
|
|
973
1024
|
}
|
|
974
1025
|
async startDetection() {
|
|
1026
|
+
this.logger.state('INICIANDO_DETECCION', {
|
|
1027
|
+
sessionExists: !!this.session,
|
|
1028
|
+
modelPreloaded: this.isModelPreloaded,
|
|
1029
|
+
videoActive: this.isVideoActive,
|
|
1030
|
+
captureStep: this.captureStep
|
|
1031
|
+
});
|
|
975
1032
|
try {
|
|
976
1033
|
// Check if model is already preloaded
|
|
977
1034
|
if (!this.session) {
|
|
@@ -985,14 +1042,14 @@ export class JaakStamps {
|
|
|
985
1042
|
this.statusColor = "#007bff";
|
|
986
1043
|
}
|
|
987
1044
|
const modelPath = this.MODEL_PATH;
|
|
988
|
-
this.
|
|
1045
|
+
this.logger.state('CARGANDO_MODELO_DETECCION', { modelPath });
|
|
989
1046
|
const sessionOptions = this.getSessionOptions();
|
|
990
1047
|
try {
|
|
991
1048
|
this.session = await window.ort.InferenceSession.create(modelPath, sessionOptions);
|
|
992
1049
|
}
|
|
993
1050
|
catch (error) {
|
|
994
1051
|
if (error.message.includes('failed to allocate a buffer')) {
|
|
995
|
-
this.
|
|
1052
|
+
this.logger.warn('Fallo en asignación de buffer, intentando con configuración mínima');
|
|
996
1053
|
const fallbackOptions = {
|
|
997
1054
|
executionProviders: ['wasm'],
|
|
998
1055
|
graphOptimizationLevel: 'disabled',
|
|
@@ -1023,7 +1080,7 @@ export class JaakStamps {
|
|
|
1023
1080
|
this.emitReadyEvent();
|
|
1024
1081
|
}
|
|
1025
1082
|
else {
|
|
1026
|
-
this.
|
|
1083
|
+
this.logger.state('USANDO_MODELOS_PRECARGADOS', { sessionExists: !!this.session, modelPreloaded: this.isModelPreloaded });
|
|
1027
1084
|
if (this.debug) {
|
|
1028
1085
|
this.statusMessage = "Usando modelos precargados...";
|
|
1029
1086
|
this.statusColor = "#007bff";
|
|
@@ -1042,7 +1099,7 @@ export class JaakStamps {
|
|
|
1042
1099
|
this.detectFrame();
|
|
1043
1100
|
}
|
|
1044
1101
|
catch (err) {
|
|
1045
|
-
this.
|
|
1102
|
+
this.logger.error('Error al inicializar detección:', err);
|
|
1046
1103
|
this.statusMessage = "Error al inicializar el detector";
|
|
1047
1104
|
this.statusColor = "#ff6b6b";
|
|
1048
1105
|
this.isLoading = false;
|
|
@@ -1124,7 +1181,7 @@ export class JaakStamps {
|
|
|
1124
1181
|
}
|
|
1125
1182
|
}
|
|
1126
1183
|
catch (e) {
|
|
1127
|
-
this.
|
|
1184
|
+
this.logger.error('Error en inferencia de modelo:', e);
|
|
1128
1185
|
// Solo continuar si no hemos completado el proceso
|
|
1129
1186
|
if (this.captureStep !== 'completed') {
|
|
1130
1187
|
// On error, wait longer before retrying
|
|
@@ -1252,7 +1309,7 @@ export class JaakStamps {
|
|
|
1252
1309
|
if (!this.hasScreenshotTaken) {
|
|
1253
1310
|
this.lastDetectedBox = bestBox;
|
|
1254
1311
|
this.takeScreenshot().catch(error => {
|
|
1255
|
-
this.
|
|
1312
|
+
this.logger.error('Error al tomar captura de pantalla:', error);
|
|
1256
1313
|
});
|
|
1257
1314
|
this.hasScreenshotTaken = true;
|
|
1258
1315
|
// Reset para permitir segunda captura
|
|
@@ -1270,6 +1327,7 @@ export class JaakStamps {
|
|
|
1270
1327
|
if (boxes.length === 0) {
|
|
1271
1328
|
this.statusMessage = "Posicione la identificación dentro del marco";
|
|
1272
1329
|
this.statusColor = "#ff6b6b";
|
|
1330
|
+
this.logger.debug('Sin detección de documento en el frame');
|
|
1273
1331
|
}
|
|
1274
1332
|
else {
|
|
1275
1333
|
const bestBox = boxes.reduce((best, current) => current.score > best.score ? current : best);
|
|
@@ -1279,6 +1337,11 @@ export class JaakStamps {
|
|
|
1279
1337
|
if (allSidesAligned) {
|
|
1280
1338
|
this.statusMessage = "Identificación perfectamente alineada. Mantenga inmóvil";
|
|
1281
1339
|
this.statusColor = "#00ff00";
|
|
1340
|
+
this.logger.state('DOCUMENTO_PERFECTAMENTE_ALINEADO', {
|
|
1341
|
+
score: bestBox.score,
|
|
1342
|
+
boxDimensions: { width: bestBox.w, height: bestBox.h },
|
|
1343
|
+
alignedSides: 4
|
|
1344
|
+
});
|
|
1282
1345
|
}
|
|
1283
1346
|
else if (alignedSides > 0) {
|
|
1284
1347
|
this.statusMessage = `Alinee los lados restantes (${alignedSides}/4 lados correctos)`;
|
|
@@ -1339,6 +1402,14 @@ export class JaakStamps {
|
|
|
1339
1402
|
async takeScreenshot() {
|
|
1340
1403
|
if (!this.videoRef || !this.lastDetectedBox)
|
|
1341
1404
|
return;
|
|
1405
|
+
this.logger.state('INICIANDO_CAPTURA', {
|
|
1406
|
+
captureStep: this.captureStep,
|
|
1407
|
+
detectedBox: this.lastDetectedBox,
|
|
1408
|
+
videoResolution: {
|
|
1409
|
+
width: this.videoRef.videoWidth,
|
|
1410
|
+
height: this.videoRef.videoHeight
|
|
1411
|
+
}
|
|
1412
|
+
});
|
|
1342
1413
|
// Activar animación
|
|
1343
1414
|
this.triggerCaptureAnimation();
|
|
1344
1415
|
// OPTIMIZATION: Reuse capture canvas for full frame
|
|
@@ -1378,7 +1449,7 @@ export class JaakStamps {
|
|
|
1378
1449
|
await this.loadMobileNetModel();
|
|
1379
1450
|
}
|
|
1380
1451
|
catch (error) {
|
|
1381
|
-
this.
|
|
1452
|
+
this.logger.warn('Fallo al cargar modelo de clasificación, continuando sin clasificación:', error);
|
|
1382
1453
|
}
|
|
1383
1454
|
}
|
|
1384
1455
|
// Classify the cropped document if model is available
|
|
@@ -1386,7 +1457,7 @@ export class JaakStamps {
|
|
|
1386
1457
|
const classification = await this.classifyDocument(croppedCanvas);
|
|
1387
1458
|
if (classification && classification.class === 'passport') {
|
|
1388
1459
|
// If it's a passport, skip back capture since passports don't have a back side
|
|
1389
|
-
this.
|
|
1460
|
+
this.logger.state('PASAPORTE_DETECTADO_SALTANDO_REVERSO', { classification: classification?.class });
|
|
1390
1461
|
this.completeProcess(true);
|
|
1391
1462
|
return;
|
|
1392
1463
|
}
|
|
@@ -1407,14 +1478,23 @@ export class JaakStamps {
|
|
|
1407
1478
|
this.isDetectionPaused = false;
|
|
1408
1479
|
}, 3000);
|
|
1409
1480
|
}, 800);
|
|
1410
|
-
this.
|
|
1481
|
+
this.logger.state('CAPTURA_FRENTE_COMPLETADA', {
|
|
1482
|
+
captureStep: this.captureStep,
|
|
1483
|
+
hasFullFrame: !!this.capturedFullFrame,
|
|
1484
|
+
hasCroppedId: !!this.capturedCroppedId
|
|
1485
|
+
});
|
|
1411
1486
|
}
|
|
1412
1487
|
else if (this.captureStep === 'back') {
|
|
1413
1488
|
// Captura de la trasera usando canvas reutilizado
|
|
1414
1489
|
this.capturedBackFullFrame = this.captureCanvas.toDataURL('image/png');
|
|
1415
1490
|
this.capturedBackCroppedId = croppedCanvas.toDataURL('image/png');
|
|
1416
1491
|
this.completeProcess(false);
|
|
1417
|
-
this.
|
|
1492
|
+
this.logger.state('CAPTURA_TRASERA_COMPLETADA', {
|
|
1493
|
+
captureStep: this.captureStep,
|
|
1494
|
+
hasBackFullFrame: !!this.capturedBackFullFrame,
|
|
1495
|
+
hasBackCroppedId: !!this.capturedBackCroppedId,
|
|
1496
|
+
processCompleted: true
|
|
1497
|
+
});
|
|
1418
1498
|
}
|
|
1419
1499
|
}
|
|
1420
1500
|
triggerCaptureAnimation() {
|
|
@@ -1438,7 +1518,7 @@ export class JaakStamps {
|
|
|
1438
1518
|
const ctx = this.canvasRef.getContext("2d");
|
|
1439
1519
|
ctx.clearRect(0, 0, this.canvasRef.width, this.canvasRef.height);
|
|
1440
1520
|
}
|
|
1441
|
-
this.
|
|
1521
|
+
this.logger.state('DETECTOR_DETENIDO', { timestamp: Date.now() });
|
|
1442
1522
|
}
|
|
1443
1523
|
resetDetection() {
|
|
1444
1524
|
this.bestScore = 0;
|
|
@@ -1477,6 +1557,13 @@ export class JaakStamps {
|
|
|
1477
1557
|
"Proceso completado (solo frente capturado)" :
|
|
1478
1558
|
"Proceso de captura completado exitosamente";
|
|
1479
1559
|
this.statusColor = "#28a745";
|
|
1560
|
+
this.logger.state('PROCESO_COMPLETADO', {
|
|
1561
|
+
skippedBack,
|
|
1562
|
+
hasFrontImages: !!(this.capturedFullFrame && this.capturedCroppedId),
|
|
1563
|
+
hasBackImages: !!(this.capturedBackFullFrame && this.capturedBackCroppedId),
|
|
1564
|
+
totalImages: skippedBack ? 2 : 4,
|
|
1565
|
+
timestamp: new Date().toISOString()
|
|
1566
|
+
});
|
|
1480
1567
|
// Detener el detector
|
|
1481
1568
|
this.stopDetection();
|
|
1482
1569
|
// Emitir evento con las imágenes capturadas
|
|
@@ -1528,7 +1615,7 @@ export class JaakStamps {
|
|
|
1528
1615
|
this.cleanup();
|
|
1529
1616
|
}
|
|
1530
1617
|
render() {
|
|
1531
|
-
return (h("div", { key: '
|
|
1618
|
+
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: {
|
|
1532
1619
|
position: 'absolute',
|
|
1533
1620
|
top: '50px',
|
|
1534
1621
|
right: '0',
|
|
@@ -1538,10 +1625,10 @@ export class JaakStamps {
|
|
|
1538
1625
|
fontSize: '10px',
|
|
1539
1626
|
borderRadius: '4px',
|
|
1540
1627
|
whiteSpace: 'nowrap'
|
|
1541
|
-
} }, "C\u00E1maras: ", this.availableCameras.length, h("br", { key: '
|
|
1628
|
+
} }, "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: () => {
|
|
1542
1629
|
this.switchCamera(camera.deviceId);
|
|
1543
1630
|
this.toggleCameraSelector();
|
|
1544
|
-
}, 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: '
|
|
1631
|
+
}, 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" })))));
|
|
1545
1632
|
}
|
|
1546
1633
|
static get is() { return "jaak-stamps"; }
|
|
1547
1634
|
static get encapsulation() { return "shadow"; }
|