@jaak.ai/stamps 2.0.0-dev.58 → 2.0.1
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-webcomponent.cjs.js +1 -1
- package/dist/cjs/jaak-stamps.cjs.entry.js +611 -546
- package/dist/cjs/jaak-stamps.cjs.entry.js.map +1 -1
- package/dist/cjs/jaak-stamps.entry.cjs.js.map +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/my-component/my-component.css +2 -14
- package/dist/collection/components/my-component/my-component.js +237 -346
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/CameraService.js +344 -156
- package/dist/collection/services/CameraService.js.map +1 -1
- package/dist/collection/services/DetectionService.js +38 -53
- package/dist/collection/services/DetectionService.js.map +1 -1
- package/dist/collection/services/EventBusService.js +1 -1
- package/dist/collection/services/EventBusService.js.map +1 -1
- package/dist/collection/services/LoggerService.js +40 -0
- package/dist/collection/services/LoggerService.js.map +1 -0
- package/dist/collection/services/ServiceContainer.js +12 -2
- package/dist/collection/services/ServiceContainer.js.map +1 -1
- package/dist/collection/services/interfaces/ICameraService.js.map +1 -1
- package/dist/collection/services/interfaces/ILogger.js +2 -0
- package/dist/collection/services/interfaces/ILogger.js.map +1 -0
- package/dist/collection/types/component-types.js.map +1 -1
- package/dist/components/jaak-stamps.js +614 -548
- package/dist/components/jaak-stamps.js.map +1 -1
- package/dist/esm/jaak-stamps-webcomponent.js +1 -1
- package/dist/esm/jaak-stamps.entry.js +611 -546
- package/dist/esm/jaak-stamps.entry.js.map +1 -1
- package/dist/esm/loader.js +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-2264b5b4.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-2264b5b4.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +17 -62
- package/dist/types/components.d.ts +8 -6
- package/dist/types/services/CameraService.d.ts +14 -12
- package/dist/types/services/DetectionService.d.ts +3 -9
- package/dist/types/services/LoggerService.d.ts +12 -0
- package/dist/types/services/ServiceContainer.d.ts +2 -0
- package/dist/types/services/interfaces/ICameraService.d.ts +12 -3
- package/dist/types/services/interfaces/ILogger.d.ts +8 -0
- package/dist/types/types/component-types.d.ts +0 -3
- package/package.json +4 -4
- package/dist/jaak-stamps-webcomponent/p-39560f23.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-39560f23.entry.js.map +0 -1
|
@@ -23,16 +23,9 @@ export class JaakStamps {
|
|
|
23
23
|
showCameraSelector = false;
|
|
24
24
|
isSwitchingCamera = false;
|
|
25
25
|
hasDocumentDetected = false;
|
|
26
|
-
cameraInfoWithAutofocus = {
|
|
27
|
-
availableCameras: [],
|
|
28
|
-
selectedCameraId: null,
|
|
29
|
-
deviceType: 'desktop',
|
|
30
|
-
isMultipleCamerasAvailable: false,
|
|
31
|
-
preferredFacing: null
|
|
32
|
-
};
|
|
33
26
|
currentStatus = {
|
|
34
|
-
message: '
|
|
35
|
-
description: 'Configurando
|
|
27
|
+
message: 'Inicializando componente...',
|
|
28
|
+
description: 'Configurando servicios y cargando recursos',
|
|
36
29
|
type: 'initializing',
|
|
37
30
|
isInitialized: false
|
|
38
31
|
};
|
|
@@ -49,6 +42,7 @@ export class JaakStamps {
|
|
|
49
42
|
backDocumentTimerRemaining = 0;
|
|
50
43
|
// Services
|
|
51
44
|
serviceContainer;
|
|
45
|
+
logger;
|
|
52
46
|
eventBus;
|
|
53
47
|
stateManager;
|
|
54
48
|
cameraService;
|
|
@@ -79,25 +73,19 @@ export class JaakStamps {
|
|
|
79
73
|
lastUpdateTime: 0
|
|
80
74
|
};
|
|
81
75
|
performanceUpdateInterval;
|
|
82
|
-
// Performance optimization
|
|
76
|
+
// Performance optimization
|
|
83
77
|
frameSkipCounter = 0;
|
|
84
|
-
|
|
85
|
-
MAX_FRAME_SKIP = 8;
|
|
78
|
+
FRAME_SKIP = 2;
|
|
86
79
|
consecutiveFailures = 0;
|
|
87
80
|
MAX_FAILURES = 30;
|
|
88
81
|
lastInferenceTime = 0;
|
|
89
82
|
MIN_INFERENCE_INTERVAL = 50;
|
|
90
|
-
performanceHistory = [];
|
|
91
|
-
PERFORMANCE_HISTORY_SIZE = 10;
|
|
92
|
-
// Canvas pool for optimized screenshot capture
|
|
93
|
-
canvasPool = [];
|
|
94
|
-
MAX_CANVAS_POOL_SIZE = 3;
|
|
95
83
|
async componentDidLoad() {
|
|
96
|
-
this.updateStatus('
|
|
84
|
+
this.updateStatus('Iniciando servicios...', 'Configurando módulos internos', 'initializing');
|
|
97
85
|
await this.initializeServices();
|
|
98
|
-
this.updateStatus('
|
|
86
|
+
this.updateStatus('Configurando eventos...', 'Preparando comunicación entre servicios', 'initializing');
|
|
99
87
|
await this.setupEventListeners();
|
|
100
|
-
this.updateStatus('
|
|
88
|
+
this.updateStatus('Inicializando cámara...', 'Detectando dispositivos disponibles', 'initializing');
|
|
101
89
|
await this.initializeComponent();
|
|
102
90
|
if (this.debug) {
|
|
103
91
|
this.initializePerformanceMonitor();
|
|
@@ -114,23 +102,33 @@ export class JaakStamps {
|
|
|
114
102
|
captureDelay: this.captureDelay
|
|
115
103
|
};
|
|
116
104
|
this.serviceContainer = new ServiceContainer(config);
|
|
105
|
+
this.logger = this.serviceContainer.getLogger();
|
|
117
106
|
this.eventBus = this.serviceContainer.getEventBus();
|
|
118
107
|
this.stateManager = this.serviceContainer.getStateManager();
|
|
119
108
|
this.cameraService = this.serviceContainer.getCameraService();
|
|
120
109
|
this.detectionService = this.serviceContainer.getDetectionService();
|
|
110
|
+
this.logger.state('SERVICIOS_INICIALIZADOS', { timestamp: Date.now() });
|
|
121
111
|
}
|
|
122
112
|
async setupEventListeners() {
|
|
123
113
|
this.eventBus.on('state-changed', (data) => {
|
|
124
114
|
this.handleStateChange(data);
|
|
125
115
|
});
|
|
126
|
-
this.eventBus.on('camera-changed', () => {
|
|
127
|
-
|
|
116
|
+
this.eventBus.on('camera-changed', (cameraId) => {
|
|
117
|
+
this.logger.state('CAMARA_CAMBIADA_EVENT', { cameraId });
|
|
128
118
|
});
|
|
129
|
-
this.eventBus.on('error', () => {
|
|
130
|
-
|
|
119
|
+
this.eventBus.on('error', (error) => {
|
|
120
|
+
this.logger.error('Error en servicio:', error);
|
|
131
121
|
});
|
|
132
122
|
}
|
|
133
123
|
async initializeComponent() {
|
|
124
|
+
this.logger.state('COMPONENTE_INICIALIZANDO', {
|
|
125
|
+
debug: this.debug,
|
|
126
|
+
maskSize: this.maskSize,
|
|
127
|
+
cropMargin: this.cropMargin,
|
|
128
|
+
useDocumentClassification: this.useDocumentClassification,
|
|
129
|
+
preferredCamera: this.preferredCamera,
|
|
130
|
+
captureDelay: this.captureDelay
|
|
131
|
+
});
|
|
134
132
|
this.validateProps();
|
|
135
133
|
if (this.debug) {
|
|
136
134
|
this.stateManager.updateCaptureState({ isLoading: true });
|
|
@@ -139,29 +137,32 @@ export class JaakStamps {
|
|
|
139
137
|
this.updateStatus('Detectando cámaras...', 'Buscando dispositivos de captura', 'initializing');
|
|
140
138
|
await this.cameraService.detectDeviceType();
|
|
141
139
|
await this.cameraService.enumerateDevices();
|
|
142
|
-
|
|
143
|
-
this.updateStatus('Preparando reconocimiento...', 'Configurando detección de documentos', 'initializing');
|
|
140
|
+
this.updateStatus('Cargando modelo IA...', 'Preparando reconocimiento de documentos', 'initializing');
|
|
144
141
|
await this.loadOnnxRuntime();
|
|
145
142
|
this.initializeResizeObserver();
|
|
146
143
|
}
|
|
147
144
|
validateProps() {
|
|
148
145
|
if (this.maskSize < 50 || this.maskSize > 100) {
|
|
146
|
+
this.logger.warn(`Propiedad maskSize inválida. Valor: ${this.maskSize}, esperado: 50-100. Usando valor por defecto: 90`);
|
|
149
147
|
this.maskSize = 90;
|
|
150
148
|
}
|
|
151
149
|
if (this.cropMargin < 0 || this.cropMargin > 100) {
|
|
150
|
+
this.logger.warn(`Propiedad cropMargin inválida. Valor: ${this.cropMargin}, esperado: 0-100. Usando valor por defecto: 0`);
|
|
152
151
|
this.cropMargin = 0;
|
|
153
152
|
}
|
|
154
153
|
const validOptions = ['auto', 'front', 'back'];
|
|
155
154
|
if (!validOptions.includes(this.preferredCamera)) {
|
|
155
|
+
this.logger.warn(`Propiedad preferredCamera inválida. Valor: ${this.preferredCamera}, esperado: ${validOptions.join(', ')}. Usando valor por defecto: 'auto'`);
|
|
156
156
|
this.preferredCamera = 'auto';
|
|
157
157
|
}
|
|
158
158
|
if (this.captureDelay < 0 || this.captureDelay > 10000) {
|
|
159
|
+
this.logger.warn(`Propiedad captureDelay inválida. Valor: ${this.captureDelay}, esperado: 0-10000. Usando valor por defecto: 1500`);
|
|
159
160
|
this.captureDelay = 1500;
|
|
160
161
|
}
|
|
161
162
|
}
|
|
162
163
|
async loadOnnxRuntime() {
|
|
163
164
|
if (!window.ort) {
|
|
164
|
-
this.updateStatus('
|
|
165
|
+
this.updateStatus('Descargando librerías...', 'Obteniendo recursos de reconocimiento', 'initializing');
|
|
165
166
|
const script = document.createElement('script');
|
|
166
167
|
script.src = 'https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.min.js';
|
|
167
168
|
document.head.appendChild(script);
|
|
@@ -201,6 +202,11 @@ export class JaakStamps {
|
|
|
201
202
|
emitReadyEvent() {
|
|
202
203
|
const isDocumentReady = !!window.ort && this.detectionService.isModelLoaded();
|
|
203
204
|
this.isReady.emit(isDocumentReady);
|
|
205
|
+
this.logger.state('COMPONENTE_LISTO', {
|
|
206
|
+
ortLibraryLoaded: !!window.ort,
|
|
207
|
+
modelPreloaded: this.detectionService.isModelLoaded(),
|
|
208
|
+
isReady: isDocumentReady
|
|
209
|
+
});
|
|
204
210
|
}
|
|
205
211
|
handleStateChange(data) {
|
|
206
212
|
// React to state changes from StateManager
|
|
@@ -223,6 +229,7 @@ export class JaakStamps {
|
|
|
223
229
|
const container = this.detectionContainer.parentElement;
|
|
224
230
|
const rect = container.getBoundingClientRect();
|
|
225
231
|
this.updateMaskDimensions(rect);
|
|
232
|
+
this.logger.debug('Container redimensionado:', { width: rect.width, height: rect.height });
|
|
226
233
|
}
|
|
227
234
|
}
|
|
228
235
|
updateMaskDimensions(containerRect) {
|
|
@@ -276,38 +283,16 @@ export class JaakStamps {
|
|
|
276
283
|
this.el.style.setProperty('--mask-center-x', `${videoCenterXPercent}%`);
|
|
277
284
|
this.el.style.setProperty('--mask-center-y', `${videoCenterYPercent}%`);
|
|
278
285
|
this.isMaskReady = true;
|
|
286
|
+
this.logger.state('DIMENSIONES_MASCARA_ACTUALIZADAS', {
|
|
287
|
+
video: { width: videoWidth, height: videoHeight },
|
|
288
|
+
displayed: { width: displayedVideoWidth, height: displayedVideoHeight },
|
|
289
|
+
mask: { widthPercent: maskWidthPercent, heightPercent: maskHeightPercent },
|
|
290
|
+
center: { x: videoCenterXPercent, y: videoCenterYPercent },
|
|
291
|
+
offset: { x: videoOffsetX, y: videoOffsetY }
|
|
292
|
+
});
|
|
279
293
|
}
|
|
280
294
|
// PUBLIC METHODS
|
|
281
|
-
// Helper method to check if component is ready for operations
|
|
282
|
-
isComponentReady() {
|
|
283
|
-
if (!this.currentStatus.isInitialized) {
|
|
284
|
-
return {
|
|
285
|
-
ready: false,
|
|
286
|
-
message: 'El componente aún se está inicializando',
|
|
287
|
-
status: 'initializing'
|
|
288
|
-
};
|
|
289
|
-
}
|
|
290
|
-
if (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') {
|
|
291
|
-
return {
|
|
292
|
-
ready: false,
|
|
293
|
-
message: 'El componente está cargando recursos',
|
|
294
|
-
status: 'loading'
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
if (!this.serviceContainer || !this.stateManager || !this.cameraService || !this.detectionService) {
|
|
298
|
-
return {
|
|
299
|
-
ready: false,
|
|
300
|
-
message: 'Los servicios del componente no están disponibles',
|
|
301
|
-
status: 'error'
|
|
302
|
-
};
|
|
303
|
-
}
|
|
304
|
-
return { ready: true };
|
|
305
|
-
}
|
|
306
295
|
async getCapturedImages() {
|
|
307
|
-
const readyCheck = this.isComponentReady();
|
|
308
|
-
if (!readyCheck.ready) {
|
|
309
|
-
throw new Error(readyCheck.message);
|
|
310
|
-
}
|
|
311
296
|
const state = this.stateManager.getCaptureState();
|
|
312
297
|
if (state.step !== 'completed') {
|
|
313
298
|
throw new Error('El proceso de captura no ha sido completado');
|
|
@@ -315,128 +300,47 @@ export class JaakStamps {
|
|
|
315
300
|
return this.stateManager.getCapturedImages();
|
|
316
301
|
}
|
|
317
302
|
async isProcessCompleted() {
|
|
318
|
-
const readyCheck = this.isComponentReady();
|
|
319
|
-
if (!readyCheck.ready) {
|
|
320
|
-
return false; // Return false instead of error for this method
|
|
321
|
-
}
|
|
322
303
|
return this.stateManager.isProcessCompleted();
|
|
323
304
|
}
|
|
324
305
|
async startCapture() {
|
|
325
|
-
|
|
326
|
-
if (!readyCheck.ready) {
|
|
327
|
-
this.updateStatus(readyCheck.message, 'Espere a que termine la inicialización', readyCheck.status);
|
|
328
|
-
return { success: false, error: readyCheck.message };
|
|
329
|
-
}
|
|
330
|
-
try {
|
|
331
|
-
await this.startDetection();
|
|
332
|
-
return { success: true };
|
|
333
|
-
}
|
|
334
|
-
catch (error) {
|
|
335
|
-
this.updateStatus('Error al iniciar captura', error.message, 'error');
|
|
336
|
-
return { success: false, error: error.message };
|
|
337
|
-
}
|
|
306
|
+
await this.startDetection();
|
|
338
307
|
}
|
|
339
308
|
async stopCapture() {
|
|
340
|
-
|
|
341
|
-
if (!readyCheck.ready) {
|
|
342
|
-
return { success: false, error: readyCheck.message };
|
|
343
|
-
}
|
|
344
|
-
try {
|
|
345
|
-
this.exitSession();
|
|
346
|
-
return { success: true };
|
|
347
|
-
}
|
|
348
|
-
catch (error) {
|
|
349
|
-
return { success: false, error: error.message };
|
|
350
|
-
}
|
|
309
|
+
this.exitSession();
|
|
351
310
|
}
|
|
352
311
|
async resetCapture() {
|
|
353
|
-
|
|
354
|
-
if (!readyCheck.ready) {
|
|
355
|
-
return { success: false, error: readyCheck.message };
|
|
356
|
-
}
|
|
357
|
-
try {
|
|
358
|
-
this.resetDetection();
|
|
359
|
-
return { success: true };
|
|
360
|
-
}
|
|
361
|
-
catch (error) {
|
|
362
|
-
return { success: false, error: error.message };
|
|
363
|
-
}
|
|
312
|
+
this.resetDetection();
|
|
364
313
|
}
|
|
365
314
|
async skipBackCapture() {
|
|
366
|
-
const
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
try {
|
|
371
|
-
const captureState = this.stateManager.getCaptureState();
|
|
372
|
-
const capturedImages = this.stateManager.getCapturedImages();
|
|
373
|
-
if (captureState.step === 'back' && capturedImages.front.fullFrame) {
|
|
374
|
-
this.completeProcess(true);
|
|
375
|
-
return { success: true };
|
|
376
|
-
}
|
|
377
|
-
else {
|
|
378
|
-
return { success: false, error: 'No se puede saltar el reverso en el estado actual' };
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
catch (error) {
|
|
382
|
-
return { success: false, error: error.message };
|
|
315
|
+
const captureState = this.stateManager.getCaptureState();
|
|
316
|
+
const capturedImages = this.stateManager.getCapturedImages();
|
|
317
|
+
if (captureState.step === 'back' && capturedImages.front.fullFrame) {
|
|
318
|
+
this.completeProcess(true);
|
|
383
319
|
}
|
|
384
320
|
}
|
|
385
321
|
async getStatus() {
|
|
386
|
-
const
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
componentMessage: readyCheck.message
|
|
396
|
-
};
|
|
397
|
-
}
|
|
398
|
-
try {
|
|
399
|
-
const captureState = this.stateManager.getCaptureState();
|
|
400
|
-
const capturedImages = this.stateManager.getCapturedImages();
|
|
401
|
-
return {
|
|
402
|
-
isVideoActive: captureState.isVideoActive,
|
|
403
|
-
captureStep: captureState.step,
|
|
404
|
-
hasImages: !!(capturedImages.front.fullFrame || capturedImages.back.fullFrame),
|
|
405
|
-
isProcessCompleted: this.stateManager.isProcessCompleted(),
|
|
406
|
-
isModelPreloaded: this.detectionService.isModelLoaded(),
|
|
407
|
-
componentStatus: 'ready'
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
catch (error) {
|
|
411
|
-
return {
|
|
412
|
-
isVideoActive: false,
|
|
413
|
-
captureStep: 'front',
|
|
414
|
-
hasImages: false,
|
|
415
|
-
isProcessCompleted: false,
|
|
416
|
-
isModelPreloaded: false,
|
|
417
|
-
componentStatus: 'error',
|
|
418
|
-
componentMessage: error.message
|
|
419
|
-
};
|
|
420
|
-
}
|
|
322
|
+
const captureState = this.stateManager.getCaptureState();
|
|
323
|
+
const capturedImages = this.stateManager.getCapturedImages();
|
|
324
|
+
return {
|
|
325
|
+
isVideoActive: captureState.isVideoActive,
|
|
326
|
+
captureStep: captureState.step,
|
|
327
|
+
hasImages: !!(capturedImages.front.fullFrame || capturedImages.back.fullFrame),
|
|
328
|
+
isProcessCompleted: this.stateManager.isProcessCompleted(),
|
|
329
|
+
isModelPreloaded: this.detectionService.isModelLoaded()
|
|
330
|
+
};
|
|
421
331
|
}
|
|
422
332
|
async preloadModel() {
|
|
423
|
-
const readyCheck = this.isComponentReady();
|
|
424
|
-
if (!readyCheck.ready) {
|
|
425
|
-
this.updateStatus(readyCheck.message, 'Espere a que termine la inicialización', readyCheck.status);
|
|
426
|
-
return { success: false, error: readyCheck.message };
|
|
427
|
-
}
|
|
428
333
|
if (this.detectionService.isModelLoaded()) {
|
|
429
|
-
this.
|
|
334
|
+
this.logger.state('MODELO_YA_PRECARGADO');
|
|
335
|
+
this.updateStatus('Modelos ya cargados', '', 'ready');
|
|
430
336
|
return { success: true, message: 'Model already loaded' };
|
|
431
337
|
}
|
|
432
338
|
try {
|
|
433
339
|
const loadStartTime = performance.now();
|
|
434
|
-
this.updateStatus('
|
|
435
|
-
|
|
436
|
-
this.stateManager.updateCaptureState({ isLoading: true });
|
|
437
|
-
}
|
|
340
|
+
this.updateStatus('Descargando modelo de detección...', 'Obteniendo red neuronal para reconocimiento de documentos', 'loading');
|
|
341
|
+
this.stateManager.updateCaptureState({ isLoading: true });
|
|
438
342
|
await this.detectionService.loadModel();
|
|
439
|
-
this.updateStatus('
|
|
343
|
+
this.updateStatus('Cargando clasificador...', 'Preparando modelo de clasificación de tipos de documento', 'loading');
|
|
440
344
|
await this.detectionService.loadClassificationModel();
|
|
441
345
|
const loadEndTime = performance.now();
|
|
442
346
|
const loadTime = loadEndTime - loadStartTime;
|
|
@@ -444,118 +348,80 @@ export class JaakStamps {
|
|
|
444
348
|
if (this.debug) {
|
|
445
349
|
this.recordOnnxPerformance(loadTime, 0);
|
|
446
350
|
}
|
|
447
|
-
this.updateStatus('
|
|
351
|
+
this.updateStatus('Optimizando modelos...', 'Configurando parámetros de rendimiento', 'loading');
|
|
448
352
|
await new Promise(resolve => setTimeout(resolve, 300));
|
|
449
|
-
this.updateStatus('
|
|
450
|
-
|
|
451
|
-
this.stateManager.updateCaptureState({ isLoading: false });
|
|
452
|
-
}
|
|
353
|
+
this.updateStatus('Modelos precargados', '', 'ready');
|
|
354
|
+
this.stateManager.updateCaptureState({ isLoading: false });
|
|
453
355
|
this.emitReadyEvent();
|
|
356
|
+
this.logger.state('MODELOS_PRECARGADOS_EXITOSAMENTE', { loadTime: Math.round(loadTime) });
|
|
454
357
|
return { success: true, message: 'Models preloaded successfully' };
|
|
455
358
|
}
|
|
456
359
|
catch (error) {
|
|
457
|
-
this.
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
360
|
+
this.logger.error('Error al precargar modelos:', error);
|
|
361
|
+
this.updateStatus('Error al cargar modelos', 'No se pudieron descargar los recursos necesarios', 'error');
|
|
362
|
+
this.stateManager.updateCaptureState({ isLoading: false });
|
|
461
363
|
return { success: false, error: error.message };
|
|
462
364
|
}
|
|
463
365
|
}
|
|
464
366
|
async getCameraInfo() {
|
|
465
|
-
|
|
466
|
-
if (!readyCheck.ready) {
|
|
467
|
-
return {
|
|
468
|
-
availableCameras: [],
|
|
469
|
-
selectedCameraId: null,
|
|
470
|
-
deviceType: 'desktop',
|
|
471
|
-
isMultipleCamerasAvailable: false,
|
|
472
|
-
preferredFacing: null,
|
|
473
|
-
error: readyCheck.message
|
|
474
|
-
};
|
|
475
|
-
}
|
|
476
|
-
try {
|
|
477
|
-
return await this.cameraService.getCameraInfo();
|
|
478
|
-
}
|
|
479
|
-
catch (error) {
|
|
480
|
-
return {
|
|
481
|
-
availableCameras: [],
|
|
482
|
-
selectedCameraId: null,
|
|
483
|
-
deviceType: 'desktop',
|
|
484
|
-
isMultipleCamerasAvailable: false,
|
|
485
|
-
preferredFacing: null,
|
|
486
|
-
error: error.message
|
|
487
|
-
};
|
|
488
|
-
}
|
|
367
|
+
return this.cameraService.getCameraInfo();
|
|
489
368
|
}
|
|
490
369
|
async setPreferredCamera(camera) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
}
|
|
500
|
-
try {
|
|
501
|
-
this.preferredCamera = camera;
|
|
502
|
-
this.serviceContainer.updateConfig({ preferredCamera: camera });
|
|
503
|
-
await this.cameraService.enumerateDevices();
|
|
504
|
-
await this.updateCameraInfoWithAutofocus();
|
|
505
|
-
const captureState = this.stateManager.getCaptureState();
|
|
506
|
-
if (captureState.isVideoActive) {
|
|
507
|
-
const selectedCameraId = this.cameraService.getSelectedCameraId();
|
|
508
|
-
if (selectedCameraId) {
|
|
509
|
-
await this.cameraService.switchCamera(selectedCameraId);
|
|
510
|
-
}
|
|
370
|
+
this.preferredCamera = camera;
|
|
371
|
+
this.serviceContainer.updateConfig({ preferredCamera: camera });
|
|
372
|
+
await this.cameraService.enumerateDevices();
|
|
373
|
+
const captureState = this.stateManager.getCaptureState();
|
|
374
|
+
if (captureState.isVideoActive) {
|
|
375
|
+
const selectedCameraId = this.cameraService.getSelectedCameraId();
|
|
376
|
+
if (selectedCameraId) {
|
|
377
|
+
await this.cameraService.switchCamera(selectedCameraId);
|
|
511
378
|
}
|
|
512
|
-
return {
|
|
513
|
-
success: true,
|
|
514
|
-
selectedCamera: this.cameraService.getSelectedCameraId(),
|
|
515
|
-
availableCameras: this.cameraService.getAvailableCameras().length
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
catch (error) {
|
|
519
|
-
return {
|
|
520
|
-
success: false,
|
|
521
|
-
error: error.message,
|
|
522
|
-
selectedCamera: null,
|
|
523
|
-
availableCameras: 0
|
|
524
|
-
};
|
|
525
379
|
}
|
|
380
|
+
return {
|
|
381
|
+
success: true,
|
|
382
|
+
selectedCamera: this.cameraService.getSelectedCameraId(),
|
|
383
|
+
availableCameras: this.cameraService.getAvailableCameras().length
|
|
384
|
+
};
|
|
526
385
|
}
|
|
527
386
|
async setCaptureDelay(delay) {
|
|
528
387
|
if (delay < 0 || delay > 10000) {
|
|
529
|
-
|
|
530
|
-
success: false,
|
|
531
|
-
error: 'Capture delay must be between 0 and 10000 milliseconds',
|
|
532
|
-
captureDelay: this.captureDelay
|
|
533
|
-
};
|
|
388
|
+
throw new Error('Capture delay must be between 0 and 10000 milliseconds');
|
|
534
389
|
}
|
|
535
|
-
// Allow setting capture delay even during initialization
|
|
536
390
|
this.captureDelay = delay;
|
|
537
|
-
|
|
538
|
-
this.serviceContainer.updateConfig({ captureDelay: delay });
|
|
539
|
-
}
|
|
391
|
+
this.serviceContainer.updateConfig({ captureDelay: delay });
|
|
540
392
|
return {
|
|
541
393
|
success: true,
|
|
542
394
|
captureDelay: this.captureDelay
|
|
543
395
|
};
|
|
544
396
|
}
|
|
545
397
|
async getCaptureDelay() {
|
|
546
|
-
// Always allow getting capture delay, even during initialization
|
|
547
398
|
return this.captureDelay;
|
|
548
399
|
}
|
|
400
|
+
async setTorchEnabled(enabled) {
|
|
401
|
+
const torchEnabled = await this.cameraService.setTorchEnabled(enabled, this.videoStream);
|
|
402
|
+
return {
|
|
403
|
+
success: torchEnabled,
|
|
404
|
+
enabled: torchEnabled ? enabled : false
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
async focusAtPoint(x, y) {
|
|
408
|
+
const focused = await this.cameraService.focusAtPoint(x, y, this.videoStream);
|
|
409
|
+
return {
|
|
410
|
+
success: focused,
|
|
411
|
+
coordinates: { x, y }
|
|
412
|
+
};
|
|
413
|
+
}
|
|
549
414
|
// DETECTION METHODS
|
|
550
415
|
async startDetection() {
|
|
416
|
+
this.logger.state('INICIANDO_DETECCION');
|
|
551
417
|
try {
|
|
552
418
|
// Paso 1: Verificar y cargar modelos si es necesario
|
|
553
419
|
if (!this.detectionService.isModelLoaded()) {
|
|
554
420
|
const loadStartTime = performance.now();
|
|
555
|
-
this.updateStatus('
|
|
421
|
+
this.updateStatus('Cargando modelo de detección...', 'Descargando red neuronal para reconocimiento', 'loading');
|
|
556
422
|
this.stateManager.updateCaptureState({ isLoading: true });
|
|
557
423
|
await this.detectionService.loadModel();
|
|
558
|
-
this.updateStatus('
|
|
424
|
+
this.updateStatus('Cargando clasificador...', 'Preparando modelo de clasificación de documentos', 'loading');
|
|
559
425
|
await this.detectionService.loadClassificationModel();
|
|
560
426
|
const loadEndTime = performance.now();
|
|
561
427
|
const loadTime = loadEndTime - loadStartTime;
|
|
@@ -563,13 +429,13 @@ export class JaakStamps {
|
|
|
563
429
|
if (this.debug) {
|
|
564
430
|
this.recordOnnxPerformance(loadTime, 0);
|
|
565
431
|
}
|
|
432
|
+
this.logger.state('MODELOS_CARGADOS_EN_DETECCION', { loadTime: Math.round(loadTime) });
|
|
566
433
|
}
|
|
567
434
|
// Paso 2: Detectar y configurar dispositivos
|
|
568
|
-
this.updateStatus('
|
|
435
|
+
this.updateStatus('Detectando cámaras...', 'Buscando dispositivos de captura disponibles', 'loading');
|
|
569
436
|
await this.cameraService.enumerateDevices();
|
|
570
|
-
await this.updateCameraInfoWithAutofocus();
|
|
571
437
|
// Paso 3: Configurar cámara seleccionada
|
|
572
|
-
this.updateStatus('
|
|
438
|
+
this.updateStatus('Configurando cámara...', 'Estableciendo resolución y parámetros óptimos', 'loading');
|
|
573
439
|
const stream = await this.cameraService.setupCamera();
|
|
574
440
|
// Paso 4: Inicializar video y ocultar estado inmediatamente
|
|
575
441
|
this.updateStatus('Captura activa', 'Buscando documento en el marco de captura', 'active');
|
|
@@ -586,7 +452,8 @@ export class JaakStamps {
|
|
|
586
452
|
this.detectFrame();
|
|
587
453
|
}
|
|
588
454
|
catch (err) {
|
|
589
|
-
this.
|
|
455
|
+
this.logger.error('Error al inicializar detección:', err);
|
|
456
|
+
this.updateStatus('Error al iniciar captura', 'No se pudo completar la inicialización', 'error');
|
|
590
457
|
this.stateManager.updateCaptureState({ isLoading: false });
|
|
591
458
|
}
|
|
592
459
|
}
|
|
@@ -596,6 +463,10 @@ export class JaakStamps {
|
|
|
596
463
|
this.videoStream = stream;
|
|
597
464
|
const isRear = this.cameraService.isRearCamera(stream);
|
|
598
465
|
this.shouldMirrorVideo = !isRear;
|
|
466
|
+
this.logger.state('CAMARA_CONFIGURADA', {
|
|
467
|
+
isRearCamera: isRear,
|
|
468
|
+
shouldMirrorVideo: this.shouldMirrorVideo
|
|
469
|
+
});
|
|
599
470
|
return new Promise((resolve) => {
|
|
600
471
|
this.videoRef.onloadedmetadata = async () => {
|
|
601
472
|
await this.videoRef.play();
|
|
@@ -620,10 +491,9 @@ export class JaakStamps {
|
|
|
620
491
|
}
|
|
621
492
|
return;
|
|
622
493
|
}
|
|
623
|
-
//
|
|
494
|
+
// Frame skipping for performance
|
|
624
495
|
this.frameSkipCounter++;
|
|
625
|
-
|
|
626
|
-
if (this.frameSkipCounter <= currentFrameSkip) {
|
|
496
|
+
if (this.frameSkipCounter <= this.FRAME_SKIP) {
|
|
627
497
|
if (captureState.step !== 'completed') {
|
|
628
498
|
this.animationId = requestAnimationFrame(() => this.detectFrame());
|
|
629
499
|
}
|
|
@@ -699,6 +569,7 @@ export class JaakStamps {
|
|
|
699
569
|
}
|
|
700
570
|
}
|
|
701
571
|
catch (e) {
|
|
572
|
+
this.logger.error('Error en inferencia de modelo:', e);
|
|
702
573
|
const captureState = this.stateManager.getCaptureState();
|
|
703
574
|
if (captureState.step !== 'completed') {
|
|
704
575
|
setTimeout(() => this.detectFrame(), 100);
|
|
@@ -725,8 +596,6 @@ export class JaakStamps {
|
|
|
725
596
|
clearInterval(this.performanceUpdateInterval);
|
|
726
597
|
this.performanceUpdateInterval = undefined;
|
|
727
598
|
}
|
|
728
|
-
// Clear canvas pool
|
|
729
|
-
this.canvasPool = [];
|
|
730
599
|
this.detectionBoxes = [];
|
|
731
600
|
this.alignmentStartTime = undefined;
|
|
732
601
|
this.hasDocumentDetected = false;
|
|
@@ -741,8 +610,14 @@ export class JaakStamps {
|
|
|
741
610
|
step: 'front',
|
|
742
611
|
isCapturing: false
|
|
743
612
|
};
|
|
744
|
-
const cameraInfo = this.
|
|
745
|
-
|
|
613
|
+
const cameraInfo = this.cameraService?.getCameraInfo() || {
|
|
614
|
+
availableCameras: [],
|
|
615
|
+
isMultipleCamerasAvailable: false,
|
|
616
|
+
selectedCameraId: null,
|
|
617
|
+
deviceType: 'desktop',
|
|
618
|
+
preferredFacing: null
|
|
619
|
+
};
|
|
620
|
+
return (h("div", { key: '9d4d77042218ab3d0bc4fb1ce879db09dc3e78b4', class: "detector-container" }, h("div", { key: '51ac8ccb1275637282b038ad8364d19f14ef61b1', class: "video-container" }, h("video", { key: 'a34f0481da20ec5b7b62b21aa275ec5f6dfec5d1', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '43b71dfe3eaf20ffa66a4139e24b1af6a2074631', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index) => (h("div", { key: index, class: "detection-box", style: {
|
|
746
621
|
position: 'absolute',
|
|
747
622
|
left: `${box.x}px`,
|
|
748
623
|
top: `${box.y}px`,
|
|
@@ -751,9 +626,9 @@ export class JaakStamps {
|
|
|
751
626
|
border: '2px solid #32406C',
|
|
752
627
|
pointerEvents: 'none',
|
|
753
628
|
boxSizing: 'border-box'
|
|
754
|
-
} })))), this.isMaskReady && (h("div", { key: '
|
|
629
|
+
} })))), this.isMaskReady && (h("div", { key: 'c2596f8cabb227e3ea3b082495f52b141cb1690f', class: "overlay-mask" }, h("div", { key: 'ba1ea39b5df1cd312a9bd9410b7225a29cfb8a29', class: "card-outline" }, h("div", { key: '6ce4d4d969d5f3fbcf75a4eb285f61d434c5633b', class: "side side-top" }), h("div", { key: '36653ecc4fcda25dfc84bc4d1f4c4c5dfb71ced7', class: "side side-right" }), h("div", { key: '8b108fa8fb370b229a0d1a77cb1ff044319a8f75', class: "side side-bottom" }), h("div", { key: 'a7aa3b45c065a50445aafd5c3ccefb57b0c9c769', class: "side side-left" }), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'b94b92273e12a019238e11ae57f21e140f13c3f1', class: "guide-text" }, "Alinee su identificaci\u00F3n con el marco"))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '144c3741003ec0cc148bb6ce92012d7b3cd110c8', class: "skip-section" }, h("div", { key: 'f0a984a6b75afa374c5d47da9d53e39f98071da0', class: "skip-explanation" }, "Si tu documento no tiene lado trasero, da clic en el bot\u00F3n para continuar con el proceso"), h("button", { key: '57ac30d776e30709aab6e0a621cef889da3cc677', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
|
|
755
630
|
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
756
|
-
: 'Saltar reverso'))), captureState.isVideoActive && (h("div", { key: '
|
|
631
|
+
: 'Saltar reverso'))), captureState.isVideoActive && (h("div", { key: 'bd45628707e0169317ed3dd4247e1056d7046104', class: "camera-controls" }, h("button", { key: 'e750fbf4d5d76d9e9596823bb2b86801ef19e485', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (h("div", { key: '40ada780a8ea13aeeaee9cb39bc6496f69f2679d', class: "camera-selector-dropdown" }, h("div", { key: '3a920bb02ba024f0359513f10544bf0528ecee6d', class: "camera-selector-header" }, h("span", { key: 'e5efd478a602b13821ba53cb9a7a59d1b4a71178' }, "Seleccionar C\u00E1mara"), h("button", { key: '2df6cc11e162be74862029e33815927e3fa8f2f8', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: '06934642dff134c9e1a6872f935a5892a9c7b835', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '8d5ede287c2efb0ebe418bee8dc7fb310443c991', class: "device-info" }, h("small", { key: 'b7dd10565113694b09f01ab28ffa29262ae1d2bc' }, "Dispositivo: ", cameraInfo.deviceType)))))), captureState.isCapturing && (h("div", { key: '2f9e549e6c0c56d4db5835e58361fb17bba6cf90', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: 'a6ef0ed127f23e9d764896ed743ca8d8454851a6', class: "flip-animation" }, h("div", { key: '0b04411f88a634bb3243b00ca2d5a45fd6962dea', class: "id-card-icon" }), h("div", { key: '9327be58879b407cea87f455989406e58302e9d1', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: 'bd268578b5003e99256e3340b4a9a6fb7656be64', class: "success-animation" }, h("div", { key: '064e0a5b9851de14bc6829f028e7ea7161fd1633', class: "check-icon" }), h("div", { key: 'bdcd94a8806399e396e218a359c10b11d05f38d6', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '3d9af617376c16e44e065873919c3d90ff46110a', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'be7b56decfd6f12dcca46b2a9456480e3d5ac00e', class: "status-spinner" })), h("div", { key: '5fe9850883cb749cebaa18c3e9c13ca21325e373', class: "status-content" }, h("div", { key: '43fdb50691e4b98e56126af1a129f625061128bf', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: 'b76cbfa4a0349421fcd535d3fd8bf40c89ca3aef', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: 'eddefb464af0487ab9ab2a0f76dccbb6a2092e51', class: "performance-monitor" }, h("div", { key: '7b7d93b56cb4cd4fbb1bdde89c6150b282fa805e', class: "performance-expanded" }, h("div", { key: 'f302e8b9d985fb8cad53c4c4e0d37a3bf5a63261', class: "metrics-row" }, h("div", { key: 'e8d8f2420ee8643a7f454d38065c75b5be598f77', class: "metric-compact" }, h("span", { key: '6e52eb5bb06e0df57e61774de38c31349f45e22b', class: "metric-label" }, "FPS"), h("span", { key: '6636f9cea20c49b49c17db86188e2f6b214c45c3', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: 'afa1d9dec05b14256a1b1fcec8638b8c21a56e37', class: "metric-compact" }, h("span", { key: '9c55e30f5d01582648bacc1fb38ca1990485a591', class: "metric-label" }, "MEM"), h("span", { key: 'ca263601e8715027f95ffb2d5413a643dc570cf2', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: '03caf19961fd01b7781484d49d8121b1e78c161f', class: "metrics-row" }, h("div", { key: 'bffb08f01f703411f7c8605e4f8d95b1c37b5c0f', class: "metric-compact" }, h("span", { key: '9b92279b3253cc669412733facb3751f4344d69f', class: "metric-label" }, "INF"), h("span", { key: '3234d4150e2e1479e3b552767af8123e69911d6c', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: '77082d2669db53f19fb50b3bbfa1ebefb0b86ff4', class: "metric-compact" }, h("span", { key: 'cc6ef96c72c800ba36dab2a388f1de863b2dacd5', class: "metric-label" }, "FRAME"), h("span", { key: 'e2bb4b7351869a76e810f8bbf20d805154495e35', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '5700d7ef839fa77686299d79445203090dc8079f', class: "metrics-row" }, h("div", { key: 'a2999a035fccb7f250c01b084075490678513c87', class: "metric-compact" }, h("span", { key: '3677d58665996fa5969507dbaff9e956b2ea54ee', class: "metric-label" }, "DET"), h("span", { key: 'c584312438b339c82a3bdc33f00fb985ff2a6f55', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '58866219f213bf8607083f30be2d5ca5d0515cea', class: "metric-compact" }, h("span", { key: 'd90b450051331347f219b6c0f197536d0dcee9b7', class: "metric-label" }, "RATE"), h("span", { key: 'f6e6cd7948e06014e5a0416e4e81394fa36ec61d', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: 'c1d0194f181a0082cc1aa5452de382908da61b65', class: "watermark" }, h("img", { key: 'e04d35f3c79a2b4a3922ab5b0f102220171fa7c0', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
|
|
757
632
|
}
|
|
758
633
|
// Utility methods
|
|
759
634
|
updateDetectionBoxes(boxes) {
|
|
@@ -834,18 +709,35 @@ export class JaakStamps {
|
|
|
834
709
|
if (allSidesAligned && bestBox) {
|
|
835
710
|
cardOutline?.classList.add('perfect-match');
|
|
836
711
|
corners?.forEach(corner => corner.classList.add('perfect-match'));
|
|
712
|
+
// Debug logging
|
|
713
|
+
this.logger.state('CAPTURE_EVALUATION', {
|
|
714
|
+
allSidesAligned: true,
|
|
715
|
+
hasScreenshotTaken: this.hasScreenshotTaken,
|
|
716
|
+
captureDelay: this.captureDelay,
|
|
717
|
+
alignmentStartTime: this.alignmentStartTime
|
|
718
|
+
});
|
|
837
719
|
if (!this.hasScreenshotTaken) {
|
|
838
720
|
const currentTime = Date.now();
|
|
839
721
|
// Initialize alignment start time if not set
|
|
840
722
|
if (!this.alignmentStartTime) {
|
|
841
723
|
this.alignmentStartTime = currentTime;
|
|
724
|
+
this.logger.state('ALIGNMENT_TIMER_STARTED', { startTime: currentTime });
|
|
842
725
|
}
|
|
843
726
|
// Check if document has been aligned for the configured delay
|
|
844
727
|
const alignmentDuration = currentTime - this.alignmentStartTime;
|
|
728
|
+
this.logger.state('ALIGNMENT_DURATION_CHECK', {
|
|
729
|
+
alignmentDuration,
|
|
730
|
+
captureDelay: this.captureDelay,
|
|
731
|
+
readyToCapture: alignmentDuration >= this.captureDelay
|
|
732
|
+
});
|
|
845
733
|
if (alignmentDuration >= this.captureDelay) {
|
|
734
|
+
this.logger.state('TRIGGERING_CAPTURE', {
|
|
735
|
+
alignmentDuration,
|
|
736
|
+
captureDelay: this.captureDelay
|
|
737
|
+
});
|
|
846
738
|
this.lastDetectedBox = bestBox;
|
|
847
|
-
this.takeScreenshot().catch(
|
|
848
|
-
|
|
739
|
+
this.takeScreenshot().catch(error => {
|
|
740
|
+
this.logger.error('Error al tomar captura de pantalla:', error);
|
|
849
741
|
});
|
|
850
742
|
this.hasScreenshotTaken = true;
|
|
851
743
|
this.alignmentStartTime = undefined;
|
|
@@ -871,12 +763,21 @@ export class JaakStamps {
|
|
|
871
763
|
async takeScreenshot() {
|
|
872
764
|
if (!this.videoRef || !this.lastDetectedBox)
|
|
873
765
|
return;
|
|
766
|
+
this.logger.state('INICIANDO_CAPTURA', {
|
|
767
|
+
captureStep: this.stateManager.getCaptureState().step,
|
|
768
|
+
detectedBox: this.lastDetectedBox,
|
|
769
|
+
videoResolution: {
|
|
770
|
+
width: this.videoRef.videoWidth,
|
|
771
|
+
height: this.videoRef.videoHeight
|
|
772
|
+
}
|
|
773
|
+
});
|
|
874
774
|
this.stateManager.updateCaptureState({ isCapturing: true });
|
|
875
775
|
this.triggerCaptureAnimation();
|
|
876
|
-
//
|
|
877
|
-
const captureCanvas =
|
|
776
|
+
// Create capture canvas
|
|
777
|
+
const captureCanvas = document.createElement('canvas');
|
|
778
|
+
captureCanvas.width = this.videoRef.videoWidth;
|
|
779
|
+
captureCanvas.height = this.videoRef.videoHeight;
|
|
878
780
|
const captureCtx = captureCanvas.getContext('2d', { alpha: false });
|
|
879
|
-
captureCtx.clearRect(0, 0, captureCanvas.width, captureCanvas.height);
|
|
880
781
|
captureCtx.drawImage(this.videoRef, 0, 0, captureCanvas.width, captureCanvas.height);
|
|
881
782
|
// Calculate crop coordinates
|
|
882
783
|
const INPUT_SIZE = 320;
|
|
@@ -886,10 +787,11 @@ export class JaakStamps {
|
|
|
886
787
|
const cropY = Math.max(0, (this.lastDetectedBox.y * scaleY) - this.cropMargin);
|
|
887
788
|
const cropWidth = Math.min((this.lastDetectedBox.w * scaleX) + (2 * this.cropMargin), this.videoRef.videoWidth - cropX);
|
|
888
789
|
const cropHeight = Math.min((this.lastDetectedBox.h * scaleY) + (2 * this.cropMargin), this.videoRef.videoHeight - cropY);
|
|
889
|
-
//
|
|
890
|
-
const croppedCanvas =
|
|
790
|
+
// Create cropped version
|
|
791
|
+
const croppedCanvas = document.createElement('canvas');
|
|
792
|
+
croppedCanvas.width = cropWidth;
|
|
793
|
+
croppedCanvas.height = cropHeight;
|
|
891
794
|
const croppedCtx = croppedCanvas.getContext('2d', { alpha: false });
|
|
892
|
-
croppedCtx.clearRect(0, 0, croppedCanvas.width, croppedCanvas.height);
|
|
893
795
|
croppedCtx.drawImage(this.videoRef, cropX, cropY, cropWidth, cropHeight, 0, 0, cropWidth, cropHeight);
|
|
894
796
|
const captureState = this.stateManager.getCaptureState();
|
|
895
797
|
if (captureState.step === 'front') {
|
|
@@ -903,6 +805,7 @@ export class JaakStamps {
|
|
|
903
805
|
if (this.useDocumentClassification) {
|
|
904
806
|
const classification = await this.detectionService.classifyDocument(croppedCanvas);
|
|
905
807
|
if (classification && classification.class === 'passport') {
|
|
808
|
+
this.logger.state('PASAPORTE_DETECTADO_SALTANDO_REVERSO', { classification: classification?.class });
|
|
906
809
|
this.completeProcess(true);
|
|
907
810
|
return;
|
|
908
811
|
}
|
|
@@ -929,9 +832,6 @@ export class JaakStamps {
|
|
|
929
832
|
});
|
|
930
833
|
this.completeProcess(false);
|
|
931
834
|
}
|
|
932
|
-
// Return canvases to pool after use
|
|
933
|
-
this.returnCanvasToPool(captureCanvas);
|
|
934
|
-
this.returnCanvasToPool(croppedCanvas);
|
|
935
835
|
}
|
|
936
836
|
triggerCaptureAnimation() {
|
|
937
837
|
const cardOutline = this.el.shadowRoot?.querySelector('.card-outline');
|
|
@@ -960,6 +860,11 @@ export class JaakStamps {
|
|
|
960
860
|
setTimeout(() => {
|
|
961
861
|
this.stateManager.updateCaptureState({ showSuccessAnimation: false });
|
|
962
862
|
}, 3000);
|
|
863
|
+
this.logger.state('PROCESO_COMPLETADO', {
|
|
864
|
+
skippedBack,
|
|
865
|
+
totalImages: capturedImages.metadata.totalImages,
|
|
866
|
+
timestamp: new Date().toISOString()
|
|
867
|
+
});
|
|
963
868
|
}
|
|
964
869
|
stopDetection() {
|
|
965
870
|
if (this.animationId) {
|
|
@@ -968,6 +873,7 @@ export class JaakStamps {
|
|
|
968
873
|
}
|
|
969
874
|
this.clearBackDocumentTimer();
|
|
970
875
|
this.detectionBoxes = [];
|
|
876
|
+
this.logger.state('DETECTOR_DETENIDO', { timestamp: Date.now() });
|
|
971
877
|
}
|
|
972
878
|
startBackDocumentTimer() {
|
|
973
879
|
if (!this.enableBackDocumentTimer)
|
|
@@ -996,15 +902,6 @@ export class JaakStamps {
|
|
|
996
902
|
return; // Don't toggle if switching camera
|
|
997
903
|
this.showCameraSelector = !this.showCameraSelector;
|
|
998
904
|
}
|
|
999
|
-
async updateCameraInfoWithAutofocus() {
|
|
1000
|
-
try {
|
|
1001
|
-
const cameraInfo = await this.cameraService.getCameraInfo();
|
|
1002
|
-
this.cameraInfoWithAutofocus = cameraInfo;
|
|
1003
|
-
}
|
|
1004
|
-
catch (error) {
|
|
1005
|
-
// Keep existing state if update fails
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
905
|
async handleCameraSwitch(cameraId) {
|
|
1009
906
|
if (this.isSwitchingCamera)
|
|
1010
907
|
return; // Prevent multiple simultaneous switches
|
|
@@ -1012,6 +909,10 @@ export class JaakStamps {
|
|
|
1012
909
|
// Close the selector immediately when user selects a camera
|
|
1013
910
|
this.showCameraSelector = false;
|
|
1014
911
|
this.isSwitchingCamera = true;
|
|
912
|
+
this.logger.state('INICIANDO_CAMBIO_CAMARA', {
|
|
913
|
+
from: this.cameraService.getSelectedCameraId(),
|
|
914
|
+
to: cameraId
|
|
915
|
+
});
|
|
1015
916
|
// Stop current video stream
|
|
1016
917
|
if (this.videoStream) {
|
|
1017
918
|
this.videoStream.getTracks().forEach(track => track.stop());
|
|
@@ -1022,17 +923,21 @@ export class JaakStamps {
|
|
|
1022
923
|
const newStream = await this.cameraService.setupCamera();
|
|
1023
924
|
// Update video element
|
|
1024
925
|
await this.initializeVideoStream(newStream);
|
|
1025
|
-
|
|
1026
|
-
|
|
926
|
+
this.logger.state('CAMBIO_CAMARA_EXITOSO', {
|
|
927
|
+
newCameraId: cameraId,
|
|
928
|
+
isRearCamera: this.cameraService.isRearCamera(newStream)
|
|
929
|
+
});
|
|
1027
930
|
}
|
|
1028
931
|
catch (error) {
|
|
932
|
+
this.logger.error('Error al cambiar cámara:', error);
|
|
1029
933
|
// Try to restore previous camera if switch failed
|
|
1030
934
|
try {
|
|
1031
935
|
const fallbackStream = await this.cameraService.setupCamera();
|
|
1032
936
|
await this.initializeVideoStream(fallbackStream);
|
|
1033
937
|
}
|
|
1034
938
|
catch (fallbackError) {
|
|
1035
|
-
this.
|
|
939
|
+
this.logger.error('Error al restaurar cámara anterior:', fallbackError);
|
|
940
|
+
this.updateStatus('Error al cambiar cámara', 'No se pudo completar el cambio de dispositivo', 'error');
|
|
1036
941
|
}
|
|
1037
942
|
}
|
|
1038
943
|
finally {
|
|
@@ -1073,7 +978,7 @@ export class JaakStamps {
|
|
|
1073
978
|
this.stateManager.updateCaptureState({ isVideoActive: false, isLoading: false });
|
|
1074
979
|
}
|
|
1075
980
|
this.isMaskReady = false;
|
|
1076
|
-
this.updateStatus('
|
|
981
|
+
this.updateStatus('Sesión finalizada', '', 'ready');
|
|
1077
982
|
this.detectionBoxes = [];
|
|
1078
983
|
this.cleanup();
|
|
1079
984
|
}
|
|
@@ -1084,6 +989,7 @@ export class JaakStamps {
|
|
|
1084
989
|
this.performanceUpdateInterval = window.setInterval(() => {
|
|
1085
990
|
this.updatePerformanceMetrics();
|
|
1086
991
|
}, 500);
|
|
992
|
+
this.logger.debug('Monitor de performance inicializado');
|
|
1087
993
|
}
|
|
1088
994
|
updatePerformanceMetrics() {
|
|
1089
995
|
const currentTime = performance.now();
|
|
@@ -1126,66 +1032,6 @@ export class JaakStamps {
|
|
|
1126
1032
|
if (detectionsFound > 0) {
|
|
1127
1033
|
this.performanceMetrics.successfulDetections++;
|
|
1128
1034
|
}
|
|
1129
|
-
// Update performance history for adaptive frame skipping
|
|
1130
|
-
this.performanceHistory.push(processingTime);
|
|
1131
|
-
if (this.performanceHistory.length > this.PERFORMANCE_HISTORY_SIZE) {
|
|
1132
|
-
this.performanceHistory.shift();
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
// Adaptive frame skipping based on performance
|
|
1136
|
-
getAdaptiveFrameSkip() {
|
|
1137
|
-
// Base conditions for high frame skip
|
|
1138
|
-
if (this.consecutiveFailures > 20)
|
|
1139
|
-
return this.MAX_FRAME_SKIP;
|
|
1140
|
-
if (this.performanceMetrics.inferenceTime > 200)
|
|
1141
|
-
return 6;
|
|
1142
|
-
if (this.performanceMetrics.memoryUsage > 200)
|
|
1143
|
-
return 5;
|
|
1144
|
-
// Calculate average processing time
|
|
1145
|
-
if (this.performanceHistory.length > 0) {
|
|
1146
|
-
const avgProcessingTime = this.performanceHistory.reduce((a, b) => a + b, 0) / this.performanceHistory.length;
|
|
1147
|
-
if (avgProcessingTime > 100)
|
|
1148
|
-
return 4;
|
|
1149
|
-
if (avgProcessingTime > 80)
|
|
1150
|
-
return 3;
|
|
1151
|
-
if (avgProcessingTime > 60)
|
|
1152
|
-
return this.BASE_FRAME_SKIP + 1;
|
|
1153
|
-
}
|
|
1154
|
-
// Low memory devices get higher frame skip
|
|
1155
|
-
if (this.performanceMetrics.memoryUsage > 150)
|
|
1156
|
-
return 4;
|
|
1157
|
-
// Performance is good, use base frame skip
|
|
1158
|
-
return this.BASE_FRAME_SKIP;
|
|
1159
|
-
}
|
|
1160
|
-
// Canvas pool management for screenshots
|
|
1161
|
-
getPooledCanvas(width, height) {
|
|
1162
|
-
// Try to find a canvas with matching dimensions
|
|
1163
|
-
const matchingIndex = this.canvasPool.findIndex(canvas => canvas.width === width && canvas.height === height);
|
|
1164
|
-
if (matchingIndex !== -1) {
|
|
1165
|
-
return this.canvasPool.splice(matchingIndex, 1)[0];
|
|
1166
|
-
}
|
|
1167
|
-
// If no matching canvas, try to reuse any canvas and resize
|
|
1168
|
-
if (this.canvasPool.length > 0) {
|
|
1169
|
-
const canvas = this.canvasPool.pop();
|
|
1170
|
-
canvas.width = width;
|
|
1171
|
-
canvas.height = height;
|
|
1172
|
-
return canvas;
|
|
1173
|
-
}
|
|
1174
|
-
// Create new canvas if pool is empty
|
|
1175
|
-
const canvas = document.createElement('canvas');
|
|
1176
|
-
canvas.width = width;
|
|
1177
|
-
canvas.height = height;
|
|
1178
|
-
return canvas;
|
|
1179
|
-
}
|
|
1180
|
-
returnCanvasToPool(canvas) {
|
|
1181
|
-
// Only return to pool if not at max capacity
|
|
1182
|
-
if (this.canvasPool.length < this.MAX_CANVAS_POOL_SIZE) {
|
|
1183
|
-
// Clear the canvas before returning to pool
|
|
1184
|
-
const ctx = canvas.getContext('2d');
|
|
1185
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1186
|
-
this.canvasPool.push(canvas);
|
|
1187
|
-
}
|
|
1188
|
-
// If pool is full, let the canvas be garbage collected
|
|
1189
1035
|
}
|
|
1190
1036
|
static get is() { return "jaak-stamps"; }
|
|
1191
1037
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1392,7 +1238,6 @@ export class JaakStamps {
|
|
|
1392
1238
|
"showCameraSelector": {},
|
|
1393
1239
|
"isSwitchingCamera": {},
|
|
1394
1240
|
"hasDocumentDetected": {},
|
|
1395
|
-
"cameraInfoWithAutofocus": {},
|
|
1396
1241
|
"currentStatus": {},
|
|
1397
1242
|
"performanceData": {},
|
|
1398
1243
|
"backDocumentTimerRemaining": {}
|
|
@@ -1474,7 +1319,7 @@ export class JaakStamps {
|
|
|
1474
1319
|
},
|
|
1475
1320
|
"startCapture": {
|
|
1476
1321
|
"complexType": {
|
|
1477
|
-
"signature": "() => Promise<
|
|
1322
|
+
"signature": "() => Promise<void>",
|
|
1478
1323
|
"parameters": [],
|
|
1479
1324
|
"references": {
|
|
1480
1325
|
"Promise": {
|
|
@@ -1482,7 +1327,7 @@ export class JaakStamps {
|
|
|
1482
1327
|
"id": "global::Promise"
|
|
1483
1328
|
}
|
|
1484
1329
|
},
|
|
1485
|
-
"return": "Promise<
|
|
1330
|
+
"return": "Promise<void>"
|
|
1486
1331
|
},
|
|
1487
1332
|
"docs": {
|
|
1488
1333
|
"text": "",
|
|
@@ -1491,7 +1336,7 @@ export class JaakStamps {
|
|
|
1491
1336
|
},
|
|
1492
1337
|
"stopCapture": {
|
|
1493
1338
|
"complexType": {
|
|
1494
|
-
"signature": "() => Promise<
|
|
1339
|
+
"signature": "() => Promise<void>",
|
|
1495
1340
|
"parameters": [],
|
|
1496
1341
|
"references": {
|
|
1497
1342
|
"Promise": {
|
|
@@ -1499,7 +1344,7 @@ export class JaakStamps {
|
|
|
1499
1344
|
"id": "global::Promise"
|
|
1500
1345
|
}
|
|
1501
1346
|
},
|
|
1502
|
-
"return": "Promise<
|
|
1347
|
+
"return": "Promise<void>"
|
|
1503
1348
|
},
|
|
1504
1349
|
"docs": {
|
|
1505
1350
|
"text": "",
|
|
@@ -1508,7 +1353,7 @@ export class JaakStamps {
|
|
|
1508
1353
|
},
|
|
1509
1354
|
"resetCapture": {
|
|
1510
1355
|
"complexType": {
|
|
1511
|
-
"signature": "() => Promise<
|
|
1356
|
+
"signature": "() => Promise<void>",
|
|
1512
1357
|
"parameters": [],
|
|
1513
1358
|
"references": {
|
|
1514
1359
|
"Promise": {
|
|
@@ -1516,7 +1361,7 @@ export class JaakStamps {
|
|
|
1516
1361
|
"id": "global::Promise"
|
|
1517
1362
|
}
|
|
1518
1363
|
},
|
|
1519
|
-
"return": "Promise<
|
|
1364
|
+
"return": "Promise<void>"
|
|
1520
1365
|
},
|
|
1521
1366
|
"docs": {
|
|
1522
1367
|
"text": "",
|
|
@@ -1525,7 +1370,7 @@ export class JaakStamps {
|
|
|
1525
1370
|
},
|
|
1526
1371
|
"skipBackCapture": {
|
|
1527
1372
|
"complexType": {
|
|
1528
|
-
"signature": "() => Promise<
|
|
1373
|
+
"signature": "() => Promise<void>",
|
|
1529
1374
|
"parameters": [],
|
|
1530
1375
|
"references": {
|
|
1531
1376
|
"Promise": {
|
|
@@ -1533,7 +1378,7 @@ export class JaakStamps {
|
|
|
1533
1378
|
"id": "global::Promise"
|
|
1534
1379
|
}
|
|
1535
1380
|
},
|
|
1536
|
-
"return": "Promise<
|
|
1381
|
+
"return": "Promise<void>"
|
|
1537
1382
|
},
|
|
1538
1383
|
"docs": {
|
|
1539
1384
|
"text": "",
|
|
@@ -1603,7 +1448,7 @@ export class JaakStamps {
|
|
|
1603
1448
|
},
|
|
1604
1449
|
"setPreferredCamera": {
|
|
1605
1450
|
"complexType": {
|
|
1606
|
-
"signature": "(camera: \"auto\" | \"front\" | \"back\") => Promise<{ success: boolean; selectedCamera: string; availableCameras: number;
|
|
1451
|
+
"signature": "(camera: \"auto\" | \"front\" | \"back\") => Promise<{ success: boolean; selectedCamera: string; availableCameras: number; }>",
|
|
1607
1452
|
"parameters": [{
|
|
1608
1453
|
"name": "camera",
|
|
1609
1454
|
"type": "\"auto\" | \"front\" | \"back\"",
|
|
@@ -1615,7 +1460,7 @@ export class JaakStamps {
|
|
|
1615
1460
|
"id": "global::Promise"
|
|
1616
1461
|
}
|
|
1617
1462
|
},
|
|
1618
|
-
"return": "Promise<{ success: boolean; selectedCamera: string; availableCameras: number;
|
|
1463
|
+
"return": "Promise<{ success: boolean; selectedCamera: string; availableCameras: number; }>"
|
|
1619
1464
|
},
|
|
1620
1465
|
"docs": {
|
|
1621
1466
|
"text": "",
|
|
@@ -1624,7 +1469,7 @@ export class JaakStamps {
|
|
|
1624
1469
|
},
|
|
1625
1470
|
"setCaptureDelay": {
|
|
1626
1471
|
"complexType": {
|
|
1627
|
-
"signature": "(delay: number) => Promise<{ success: boolean;
|
|
1472
|
+
"signature": "(delay: number) => Promise<{ success: boolean; captureDelay: number; }>",
|
|
1628
1473
|
"parameters": [{
|
|
1629
1474
|
"name": "delay",
|
|
1630
1475
|
"type": "number",
|
|
@@ -1636,7 +1481,7 @@ export class JaakStamps {
|
|
|
1636
1481
|
"id": "global::Promise"
|
|
1637
1482
|
}
|
|
1638
1483
|
},
|
|
1639
|
-
"return": "Promise<{ success: boolean;
|
|
1484
|
+
"return": "Promise<{ success: boolean; captureDelay: number; }>"
|
|
1640
1485
|
},
|
|
1641
1486
|
"docs": {
|
|
1642
1487
|
"text": "",
|
|
@@ -1659,6 +1504,52 @@ export class JaakStamps {
|
|
|
1659
1504
|
"text": "",
|
|
1660
1505
|
"tags": []
|
|
1661
1506
|
}
|
|
1507
|
+
},
|
|
1508
|
+
"setTorchEnabled": {
|
|
1509
|
+
"complexType": {
|
|
1510
|
+
"signature": "(enabled: boolean) => Promise<{ success: boolean; enabled: boolean; }>",
|
|
1511
|
+
"parameters": [{
|
|
1512
|
+
"name": "enabled",
|
|
1513
|
+
"type": "boolean",
|
|
1514
|
+
"docs": ""
|
|
1515
|
+
}],
|
|
1516
|
+
"references": {
|
|
1517
|
+
"Promise": {
|
|
1518
|
+
"location": "global",
|
|
1519
|
+
"id": "global::Promise"
|
|
1520
|
+
}
|
|
1521
|
+
},
|
|
1522
|
+
"return": "Promise<{ success: boolean; enabled: boolean; }>"
|
|
1523
|
+
},
|
|
1524
|
+
"docs": {
|
|
1525
|
+
"text": "",
|
|
1526
|
+
"tags": []
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
"focusAtPoint": {
|
|
1530
|
+
"complexType": {
|
|
1531
|
+
"signature": "(x: number, y: number) => Promise<{ success: boolean; coordinates: { x: number; y: number; }; }>",
|
|
1532
|
+
"parameters": [{
|
|
1533
|
+
"name": "x",
|
|
1534
|
+
"type": "number",
|
|
1535
|
+
"docs": ""
|
|
1536
|
+
}, {
|
|
1537
|
+
"name": "y",
|
|
1538
|
+
"type": "number",
|
|
1539
|
+
"docs": ""
|
|
1540
|
+
}],
|
|
1541
|
+
"references": {
|
|
1542
|
+
"Promise": {
|
|
1543
|
+
"location": "global",
|
|
1544
|
+
"id": "global::Promise"
|
|
1545
|
+
}
|
|
1546
|
+
},
|
|
1547
|
+
"return": "Promise<{ success: boolean; coordinates: { x: number; y: number; }; }>"
|
|
1548
|
+
},
|
|
1549
|
+
"docs": {
|
|
1550
|
+
"text": "",
|
|
1551
|
+
"tags": []
|
|
1552
|
+
}
|
|
1662
1553
|
}
|
|
1663
1554
|
};
|
|
1664
1555
|
}
|