@jaak.ai/stamps 2.0.0-dev.39 → 2.0.0-dev.41
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/README.md +4 -1
- package/dist/cjs/jaak-stamps-webcomponent.cjs.js +1 -1
- package/dist/cjs/jaak-stamps.cjs.entry.js +875 -13
- 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 +66 -0
- package/dist/collection/components/my-component/my-component.js +501 -10
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/CameraService.js +161 -0
- package/dist/collection/services/CameraService.js.map +1 -1
- package/dist/collection/services/DetectionService.js +164 -1
- package/dist/collection/services/DetectionService.js.map +1 -1
- package/dist/collection/services/ImageQualityService.js +329 -0
- package/dist/collection/services/ImageQualityService.js.map +1 -0
- package/dist/collection/services/ServiceContainer.js +6 -1
- package/dist/collection/services/ServiceContainer.js.map +1 -1
- package/dist/collection/services/interfaces/ICameraService.js.map +1 -1
- package/dist/collection/services/interfaces/IDetectionService.js.map +1 -1
- package/dist/collection/services/interfaces/IImageQualityService.js +2 -0
- package/dist/collection/services/interfaces/IImageQualityService.js.map +1 -0
- package/dist/components/jaak-stamps.js +892 -14
- 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 +875 -13
- 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-47f37982.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-47f37982.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +48 -0
- package/dist/types/components.d.ts +65 -0
- package/dist/types/services/CameraService.d.ts +5 -0
- package/dist/types/services/DetectionService.d.ts +22 -2
- package/dist/types/services/ImageQualityService.d.ts +31 -0
- package/dist/types/services/ServiceContainer.d.ts +7 -0
- package/dist/types/services/interfaces/ICameraService.d.ts +2 -0
- package/dist/types/services/interfaces/IDetectionService.d.ts +13 -0
- package/dist/types/services/interfaces/IImageQualityService.d.ts +58 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-043b1cfd.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-043b1cfd.entry.js.map +0 -1
|
@@ -8,6 +8,13 @@ export class JaakStamps {
|
|
|
8
8
|
cropMargin = 0;
|
|
9
9
|
useDocumentClassification = false;
|
|
10
10
|
preferredCamera = 'auto';
|
|
11
|
+
captureDelay = 1000;
|
|
12
|
+
enableQualityValidation = true;
|
|
13
|
+
qualityThreshold = 60;
|
|
14
|
+
minQualityScore = 45;
|
|
15
|
+
minFocusScore = 16;
|
|
16
|
+
minBlurScore = 22;
|
|
17
|
+
maxReflectionScore = 15;
|
|
11
18
|
captureCompleted;
|
|
12
19
|
isReady;
|
|
13
20
|
// State derived from services
|
|
@@ -19,12 +26,19 @@ export class JaakStamps {
|
|
|
19
26
|
shouldMirrorVideo = true;
|
|
20
27
|
showCameraSelector = false;
|
|
21
28
|
isSwitchingCamera = false;
|
|
29
|
+
hasDocumentDetected = false;
|
|
22
30
|
currentStatus = {
|
|
23
31
|
message: 'Inicializando componente...',
|
|
24
32
|
description: 'Configurando servicios y cargando recursos',
|
|
25
33
|
type: 'initializing',
|
|
26
34
|
isInitialized: false
|
|
27
35
|
};
|
|
36
|
+
qualityFeedback = {
|
|
37
|
+
message: 'Analizando calidad...',
|
|
38
|
+
score: 0,
|
|
39
|
+
hasIssues: false,
|
|
40
|
+
canCapture: false
|
|
41
|
+
};
|
|
28
42
|
performanceData = {
|
|
29
43
|
fps: 0,
|
|
30
44
|
inferenceTime: 0,
|
|
@@ -92,7 +106,14 @@ export class JaakStamps {
|
|
|
92
106
|
maskSize: this.maskSize,
|
|
93
107
|
cropMargin: this.cropMargin,
|
|
94
108
|
useDocumentClassification: this.useDocumentClassification,
|
|
95
|
-
preferredCamera: this.preferredCamera
|
|
109
|
+
preferredCamera: this.preferredCamera,
|
|
110
|
+
captureDelay: this.captureDelay,
|
|
111
|
+
enableQualityValidation: this.enableQualityValidation,
|
|
112
|
+
qualityThreshold: this.qualityThreshold,
|
|
113
|
+
minQualityScore: this.minQualityScore,
|
|
114
|
+
minFocusScore: this.minFocusScore,
|
|
115
|
+
minBlurScore: this.minBlurScore,
|
|
116
|
+
maxReflectionScore: this.maxReflectionScore
|
|
96
117
|
};
|
|
97
118
|
this.serviceContainer = new ServiceContainer(config);
|
|
98
119
|
this.logger = this.serviceContainer.getLogger();
|
|
@@ -119,7 +140,8 @@ export class JaakStamps {
|
|
|
119
140
|
maskSize: this.maskSize,
|
|
120
141
|
cropMargin: this.cropMargin,
|
|
121
142
|
useDocumentClassification: this.useDocumentClassification,
|
|
122
|
-
preferredCamera: this.preferredCamera
|
|
143
|
+
preferredCamera: this.preferredCamera,
|
|
144
|
+
captureDelay: this.captureDelay
|
|
123
145
|
});
|
|
124
146
|
this.validateProps();
|
|
125
147
|
if (this.debug) {
|
|
@@ -147,6 +169,30 @@ export class JaakStamps {
|
|
|
147
169
|
this.logger.warn(`Propiedad preferredCamera inválida. Valor: ${this.preferredCamera}, esperado: ${validOptions.join(', ')}. Usando valor por defecto: 'auto'`);
|
|
148
170
|
this.preferredCamera = 'auto';
|
|
149
171
|
}
|
|
172
|
+
if (this.captureDelay < 0 || this.captureDelay > 10000) {
|
|
173
|
+
this.logger.warn(`Propiedad captureDelay inválida. Valor: ${this.captureDelay}, esperado: 0-10000. Usando valor por defecto: 1000`);
|
|
174
|
+
this.captureDelay = 1000;
|
|
175
|
+
}
|
|
176
|
+
if (this.qualityThreshold < 0 || this.qualityThreshold > 100) {
|
|
177
|
+
this.logger.warn(`Propiedad qualityThreshold inválida. Valor: ${this.qualityThreshold}, esperado: 0-100. Usando valor por defecto: 60`);
|
|
178
|
+
this.qualityThreshold = 60;
|
|
179
|
+
}
|
|
180
|
+
if (this.minQualityScore < 0 || this.minQualityScore > 100) {
|
|
181
|
+
this.logger.warn(`Propiedad minQualityScore inválida. Valor: ${this.minQualityScore}, esperado: 0-100. Usando valor por defecto: 45`);
|
|
182
|
+
this.minQualityScore = 45;
|
|
183
|
+
}
|
|
184
|
+
if (this.minFocusScore < 0 || this.minFocusScore > 100) {
|
|
185
|
+
this.logger.warn(`Propiedad minFocusScore inválida. Valor: ${this.minFocusScore}, esperado: 0-100. Usando valor por defecto: 16`);
|
|
186
|
+
this.minFocusScore = 16;
|
|
187
|
+
}
|
|
188
|
+
if (this.minBlurScore < 0 || this.minBlurScore > 200) {
|
|
189
|
+
this.logger.warn(`Propiedad minBlurScore inválida. Valor: ${this.minBlurScore}, esperado: 0-200. Usando valor por defecto: 22`);
|
|
190
|
+
this.minBlurScore = 22;
|
|
191
|
+
}
|
|
192
|
+
if (this.maxReflectionScore < 0 || this.maxReflectionScore > 100) {
|
|
193
|
+
this.logger.warn(`Propiedad maxReflectionScore inválida. Valor: ${this.maxReflectionScore}, esperado: 0-100. Usando valor por defecto: 15`);
|
|
194
|
+
this.maxReflectionScore = 15;
|
|
195
|
+
}
|
|
150
196
|
}
|
|
151
197
|
async loadOnnxRuntime() {
|
|
152
198
|
if (!window.ort) {
|
|
@@ -371,6 +417,91 @@ export class JaakStamps {
|
|
|
371
417
|
availableCameras: this.cameraService.getAvailableCameras().length
|
|
372
418
|
};
|
|
373
419
|
}
|
|
420
|
+
async setCaptureDelay(delay) {
|
|
421
|
+
if (delay < 0 || delay > 10000) {
|
|
422
|
+
throw new Error('Capture delay must be between 0 and 10000 milliseconds');
|
|
423
|
+
}
|
|
424
|
+
this.captureDelay = delay;
|
|
425
|
+
this.serviceContainer.updateConfig({ captureDelay: delay });
|
|
426
|
+
return {
|
|
427
|
+
success: true,
|
|
428
|
+
captureDelay: this.captureDelay
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
async getCaptureDelay() {
|
|
432
|
+
return this.captureDelay;
|
|
433
|
+
}
|
|
434
|
+
async setTorchEnabled(enabled) {
|
|
435
|
+
const torchEnabled = await this.cameraService.setTorchEnabled(enabled, this.videoStream);
|
|
436
|
+
return {
|
|
437
|
+
success: torchEnabled,
|
|
438
|
+
enabled: torchEnabled ? enabled : false
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
async focusAtPoint(x, y) {
|
|
442
|
+
const focused = await this.cameraService.focusAtPoint(x, y, this.videoStream);
|
|
443
|
+
return {
|
|
444
|
+
success: focused,
|
|
445
|
+
coordinates: { x, y }
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
async getImageQuality() {
|
|
449
|
+
if (!this.videoRef || !this.detectionService.isModelLoaded()) {
|
|
450
|
+
return null;
|
|
451
|
+
}
|
|
452
|
+
try {
|
|
453
|
+
const qualityResult = this.detectionService.validateImageQuality(this.videoRef);
|
|
454
|
+
return {
|
|
455
|
+
qualityScore: qualityResult.qualityScore,
|
|
456
|
+
overallQuality: qualityResult.overallQuality,
|
|
457
|
+
issues: qualityResult.issues,
|
|
458
|
+
recommendations: qualityResult.recommendations,
|
|
459
|
+
canCapture: this.detectionService.isImageQualityAcceptable(qualityResult)
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
catch (error) {
|
|
463
|
+
this.logger.error('Error al analizar calidad de imagen:', error);
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
async setQualityThresholds(thresholds) {
|
|
468
|
+
// Validate thresholds
|
|
469
|
+
if (thresholds.minQualityScore !== undefined && (thresholds.minQualityScore < 0 || thresholds.minQualityScore > 100)) {
|
|
470
|
+
throw new Error('minQualityScore must be between 0 and 100');
|
|
471
|
+
}
|
|
472
|
+
if (thresholds.minFocusScore !== undefined && (thresholds.minFocusScore < 0 || thresholds.minFocusScore > 100)) {
|
|
473
|
+
throw new Error('minFocusScore must be between 0 and 100');
|
|
474
|
+
}
|
|
475
|
+
if (thresholds.minBlurScore !== undefined && (thresholds.minBlurScore < 0 || thresholds.minBlurScore > 200)) {
|
|
476
|
+
throw new Error('minBlurScore must be between 0 and 200');
|
|
477
|
+
}
|
|
478
|
+
if (thresholds.maxReflectionScore !== undefined && (thresholds.maxReflectionScore < 0 || thresholds.maxReflectionScore > 100)) {
|
|
479
|
+
throw new Error('maxReflectionScore must be between 0 and 100');
|
|
480
|
+
}
|
|
481
|
+
// Update component properties
|
|
482
|
+
if (thresholds.minQualityScore !== undefined)
|
|
483
|
+
this.minQualityScore = thresholds.minQualityScore;
|
|
484
|
+
if (thresholds.minFocusScore !== undefined)
|
|
485
|
+
this.minFocusScore = thresholds.minFocusScore;
|
|
486
|
+
if (thresholds.minBlurScore !== undefined)
|
|
487
|
+
this.minBlurScore = thresholds.minBlurScore;
|
|
488
|
+
if (thresholds.maxReflectionScore !== undefined)
|
|
489
|
+
this.maxReflectionScore = thresholds.maxReflectionScore;
|
|
490
|
+
// Update detection service
|
|
491
|
+
this.detectionService.updateQualityThresholds(thresholds);
|
|
492
|
+
return {
|
|
493
|
+
success: true,
|
|
494
|
+
thresholds: this.detectionService.getQualityThresholds()
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
async getQualityThresholds() {
|
|
498
|
+
return {
|
|
499
|
+
minQualityScore: this.minQualityScore,
|
|
500
|
+
minFocusScore: this.minFocusScore,
|
|
501
|
+
minBlurScore: this.minBlurScore,
|
|
502
|
+
maxReflectionScore: this.maxReflectionScore
|
|
503
|
+
};
|
|
504
|
+
}
|
|
374
505
|
// DETECTION METHODS
|
|
375
506
|
async startDetection() {
|
|
376
507
|
this.logger.state('INICIANDO_DETECCION');
|
|
@@ -472,7 +603,36 @@ export class JaakStamps {
|
|
|
472
603
|
// Measure preprocessing and inference time
|
|
473
604
|
const inferenceStartTime = performance.now();
|
|
474
605
|
const inputTensor = this.detectionService.preprocess(this.videoRef);
|
|
475
|
-
|
|
606
|
+
// Enhanced detection with quality validation if enabled
|
|
607
|
+
let detections;
|
|
608
|
+
let qualityResult = null;
|
|
609
|
+
let canCapture = true;
|
|
610
|
+
if (this.enableQualityValidation) {
|
|
611
|
+
// Use enhanced detection method with quality validation
|
|
612
|
+
const enhancedResult = await this.detectionService.runInferenceWithQuality(inputTensor, this.videoRef);
|
|
613
|
+
detections = enhancedResult.detections;
|
|
614
|
+
qualityResult = enhancedResult.qualityResult;
|
|
615
|
+
canCapture = enhancedResult.canCapture;
|
|
616
|
+
// Update quality feedback state
|
|
617
|
+
this.qualityFeedback = {
|
|
618
|
+
message: enhancedResult.feedback,
|
|
619
|
+
score: qualityResult.qualityScore,
|
|
620
|
+
hasIssues: qualityResult.issues.length > 0,
|
|
621
|
+
canCapture: canCapture
|
|
622
|
+
};
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
// Standard detection without quality validation
|
|
626
|
+
detections = await this.detectionService.runInference(inputTensor);
|
|
627
|
+
// Quick quality feedback for real-time display
|
|
628
|
+
const quickFeedback = this.detectionService.getQuickQualityFeedback(this.videoRef);
|
|
629
|
+
this.qualityFeedback = {
|
|
630
|
+
message: quickFeedback.feedback,
|
|
631
|
+
score: 0, // Not calculated in quick mode
|
|
632
|
+
hasIssues: quickFeedback.hasBlur || quickFeedback.hasReflections || !quickFeedback.isFocused,
|
|
633
|
+
canCapture: true // Allow capture without strict validation
|
|
634
|
+
};
|
|
635
|
+
}
|
|
476
636
|
const inferenceTime = performance.now() - inferenceStartTime;
|
|
477
637
|
// Record ONNX performance metrics
|
|
478
638
|
if (this.debug) {
|
|
@@ -488,6 +648,8 @@ export class JaakStamps {
|
|
|
488
648
|
}
|
|
489
649
|
});
|
|
490
650
|
}
|
|
651
|
+
// Update document detection state
|
|
652
|
+
this.hasDocumentDetected = detections.length > 0;
|
|
491
653
|
// Adaptive frame rate
|
|
492
654
|
if (detections.length === 0) {
|
|
493
655
|
this.consecutiveFailures++;
|
|
@@ -549,6 +711,7 @@ export class JaakStamps {
|
|
|
549
711
|
}
|
|
550
712
|
this.detectionBoxes = [];
|
|
551
713
|
this.alignmentStartTime = undefined;
|
|
714
|
+
this.hasDocumentDetected = false;
|
|
552
715
|
this.serviceContainer?.cleanup();
|
|
553
716
|
}
|
|
554
717
|
render() {
|
|
@@ -567,7 +730,7 @@ export class JaakStamps {
|
|
|
567
730
|
deviceType: 'desktop',
|
|
568
731
|
preferredFacing: null
|
|
569
732
|
};
|
|
570
|
-
return (h("div", { key: '
|
|
733
|
+
return (h("div", { key: 'd71fc140c7fc87160ceaf479f9b9beae7685e9bc', class: "detector-container" }, h("div", { key: 'd83347ab6ccacfe940fb66d17adc21cff126d875', class: "video-container" }, h("video", { key: 'fb69de65e8133c7936cfb03ec86acdf89d2a8112', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: 'c957341c1a750a1732afd6bb1045c1ba9bb2993d', 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: {
|
|
571
734
|
position: 'absolute',
|
|
572
735
|
left: `${box.x}px`,
|
|
573
736
|
top: `${box.y}px`,
|
|
@@ -576,7 +739,9 @@ export class JaakStamps {
|
|
|
576
739
|
border: '2px solid #32406C',
|
|
577
740
|
pointerEvents: 'none',
|
|
578
741
|
boxSizing: 'border-box'
|
|
579
|
-
} })))), this.isMaskReady && (h("div", { key: '
|
|
742
|
+
} })))), this.isMaskReady && (h("div", { key: 'cf81504f7f129a2bb2789dd7addfe8d365fd7973', class: "overlay-mask" }, h("div", { key: 'b0f8ab1e02d1731295b95cbca4b44be430c6104d', class: "card-outline" }, h("div", { key: 'fadb33b8dc3c2cbfbb78aa0ff4d273b2b26a3565', class: "side side-top" }), h("div", { key: '3f3ca187195c78f2c3daffa481cc275f970c68a5', class: "side side-right" }), h("div", { key: '1e6bac145a85bbee2dab24da81b8064bc4ac282b', class: "side side-bottom" }), h("div", { key: '9bef1cd7afcef6cb1975a1103ec57d33d89f7640', class: "side side-left" }), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '9198d8b8fb1f4a17ec615943a09844f47a639048', class: "guide-text" }, this.enableQualityValidation && this.hasDocumentDetected && this.qualityFeedback.message ?
|
|
743
|
+
this.qualityFeedback.message :
|
|
744
|
+
'Alinee su identificación con el marco')), this.enableQualityValidation && this.hasDocumentDetected && captureState.isVideoActive && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '04afa661c1d988d9bedb48c78672de233dd49f9b', class: `quality-indicator ${this.qualityFeedback.hasIssues ? 'warning' : 'good'}` }, h("div", { key: 'bc789e19894de1d3dfd4a232e05e612d804e0e6c', class: "quality-score" }, this.qualityFeedback.score > 0 ? `${this.qualityFeedback.score}%` : ''), h("div", { key: '0750f5e5dfdb7a7c054d01965146d34a5bb4485a', class: `quality-status ${this.qualityFeedback.canCapture ? 'ready' : 'not-ready'}` }, this.qualityFeedback.canCapture ? '✓' : '!')))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("button", { key: 'cbe391726b5d62acbb466c36b135e0556fc488f7', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, "Saltar reverso")), captureState.isVideoActive && (h("div", { key: '929f8fe054b30e3c30bf066319e957a633fa587c', class: "camera-controls" }, h("button", { key: 'b4f68dd3a6865cba49c3f5d38c43874b7b9b364d', 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: 'c9315ff70704fdc265af07bf765b6247814563e6', class: "camera-selector-dropdown" }, h("div", { key: 'f4950e7e3c3e279c48310a4049550f3143fb4d3f', class: "camera-selector-header" }, h("span", { key: '4cfacf909549b0e18bd8ac6e54e127ce09b75335' }, "Seleccionar C\u00E1mara"), h("button", { key: '13d7679c5235f41f0dbc38b9f397483cf4ec9ffd', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: '6c97cb8ba9486c33a633901d9dd49765f87d92ed', 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: '35796316fc950b8491f6167303b549b098abbf58', class: "device-info" }, h("small", { key: '83c59a8cb0c0b67a37163fe75c1f1f383fcb00f4' }, "Dispositivo: ", cameraInfo.deviceType)))))), captureState.isCapturing && (h("div", { key: 'be5b316abb21c06cf5bb69ed090d43d45537a9e6', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '43e64fcc325c7c96871a99838c5fa094c6774af2', class: "flip-animation" }, h("div", { key: '39223d9b593716e76912ade58b556c7212a7e05f', class: "id-card-icon" }), h("div", { key: '79463b43724c3c56c45bd5b41337117d7d415618', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '7be8ca4d0bd59b1e4127254ff68e41321aa387cc', class: "success-animation" }, h("div", { key: '03a3e625f622c546a3016f85e029f9ea165f65c3', class: "check-icon" }), h("div", { key: '9c63faad517dad4b2ede8ec5a0998ad0b5c807d5', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: '94aa38c67fdaf328e74a2c1ec476987bf8e483d5', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: '52a460f2fe11505158331cc06d7121db80bdfed9', class: "status-spinner" })), h("div", { key: '1eabfed00df31ff30fdf818f3d33cd837a7f31a5', class: "status-content" }, h("div", { key: '4bdbadf18fc48f2fad5dafd9ddf4a78f0a81dbf5', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '14c41346fc9fc306315cdda1c54ec1e828c38f62', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '21fb0ca08547143648097f2aa4f3eb3ade73bce1', class: "performance-monitor" }, h("div", { key: '88c990f42b5c87c9bc971acd228fc84bacec861b', class: "performance-expanded" }, h("div", { key: '351215f4b8ab202b42a4c9b0bfa8665485469f64', class: "metrics-row" }, h("div", { key: '28a2c5386ba99850f7dc41add6fb4ef073a6b8cb', class: "metric-compact" }, h("span", { key: '7a2ab758f9baf1264cd4ad70ff30f42a35c41065', class: "metric-label" }, "FPS"), h("span", { key: '1c4370d016f2bdcf61275b4869bddbd8109a7b2a', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: 'e79c27b4cbad3e70f2df917a5147dd125d51304d', class: "metric-compact" }, h("span", { key: 'aee4c178ae751cfe94735ef9fcb78f273f9cb885', class: "metric-label" }, "MEM"), h("span", { key: '823e98dec413968ee5080b29839729e6ac9f91d2', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'e29037f684c82579a711aff022060c97ab9d93cf', class: "metrics-row" }, h("div", { key: '2917f3c4b026e3106fad741944e582aff36e10e0', class: "metric-compact" }, h("span", { key: 'e8783e8e2b18b29b37342eea376a75f257a46850', class: "metric-label" }, "INF"), h("span", { key: '30cdc1db3189135bc772aab5c31e081294ebd431', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: 'c481ec26394e35efe38047e5fa1b835e520f49b8', class: "metric-compact" }, h("span", { key: 'c806cae91f3fcad896bd6053b6a0391ab518ab6f', class: "metric-label" }, "FRAME"), h("span", { key: 'af9996e2093c918ea903d036e637905baeef1aa2', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '48422447a6d00f78a9f861bfc50de4ef5a628a57', class: "metrics-row" }, h("div", { key: 'c88a03fbff56f68796df33187256fd5a5a68f763', class: "metric-compact" }, h("span", { key: '5e366c35865f8bf45aecac126ce98e0e17be0825', class: "metric-label" }, "DET"), h("span", { key: '123570ac9ae59cf5ef1b992ea6c4563b753990c3', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: 'dea3a496f84e80f9d6f27173c8fa2e4149bf8e0b', class: "metric-compact" }, h("span", { key: 'fe47d6c16ca84fff8824bef92d8ce9efe50dfa38', class: "metric-label" }, "RATE"), h("span", { key: '873846eb42c1ed97f4e9493871e51741766c852f', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: 'b485b1d8fafee0314ffbf1c7934ffc9a3d4c6902', class: "watermark" }, h("img", { key: 'f5fae340c3e96ecafe26aa819dbc2411038aa953', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
|
|
580
745
|
}
|
|
581
746
|
// Utility methods
|
|
582
747
|
updateDetectionBoxes(boxes) {
|
|
@@ -648,15 +813,38 @@ export class JaakStamps {
|
|
|
648
813
|
if (allSidesAligned && bestBox) {
|
|
649
814
|
cardOutline?.classList.add('perfect-match');
|
|
650
815
|
corners?.forEach(corner => corner.classList.add('perfect-match'));
|
|
651
|
-
|
|
816
|
+
// Check quality validation before allowing capture
|
|
817
|
+
const qualityCheckPassed = !this.enableQualityValidation || this.qualityFeedback.canCapture;
|
|
818
|
+
// Debug logging
|
|
819
|
+
this.logger.state('CAPTURE_EVALUATION', {
|
|
820
|
+
allSidesAligned: true,
|
|
821
|
+
hasScreenshotTaken: this.hasScreenshotTaken,
|
|
822
|
+
qualityCheckPassed,
|
|
823
|
+
enableQualityValidation: this.enableQualityValidation,
|
|
824
|
+
qualityFeedback: this.qualityFeedback,
|
|
825
|
+
captureDelay: this.captureDelay,
|
|
826
|
+
alignmentStartTime: this.alignmentStartTime
|
|
827
|
+
});
|
|
828
|
+
if (!this.hasScreenshotTaken && qualityCheckPassed) {
|
|
652
829
|
const currentTime = Date.now();
|
|
653
830
|
// Initialize alignment start time if not set
|
|
654
831
|
if (!this.alignmentStartTime) {
|
|
655
832
|
this.alignmentStartTime = currentTime;
|
|
833
|
+
this.logger.state('ALIGNMENT_TIMER_STARTED', { startTime: currentTime });
|
|
656
834
|
}
|
|
657
|
-
// Check if document has been aligned for
|
|
835
|
+
// Check if document has been aligned for the configured delay
|
|
658
836
|
const alignmentDuration = currentTime - this.alignmentStartTime;
|
|
659
|
-
|
|
837
|
+
this.logger.state('ALIGNMENT_DURATION_CHECK', {
|
|
838
|
+
alignmentDuration,
|
|
839
|
+
captureDelay: this.captureDelay,
|
|
840
|
+
readyToCapture: alignmentDuration >= this.captureDelay
|
|
841
|
+
});
|
|
842
|
+
if (alignmentDuration >= this.captureDelay) {
|
|
843
|
+
this.logger.state('TRIGGERING_CAPTURE', {
|
|
844
|
+
alignmentDuration,
|
|
845
|
+
captureDelay: this.captureDelay,
|
|
846
|
+
qualityScore: this.qualityFeedback.score
|
|
847
|
+
});
|
|
660
848
|
this.lastDetectedBox = bestBox;
|
|
661
849
|
this.takeScreenshot().catch(error => {
|
|
662
850
|
this.logger.error('Error al tomar captura de pantalla:', error);
|
|
@@ -668,6 +856,17 @@ export class JaakStamps {
|
|
|
668
856
|
}, 2000);
|
|
669
857
|
}
|
|
670
858
|
}
|
|
859
|
+
else if (!qualityCheckPassed) {
|
|
860
|
+
// Reset alignment timer if quality check fails
|
|
861
|
+
this.logger.state('QUALITY_CHECK_FAILED', {
|
|
862
|
+
enableQualityValidation: this.enableQualityValidation,
|
|
863
|
+
canCapture: this.qualityFeedback.canCapture,
|
|
864
|
+
qualityScore: this.qualityFeedback.score,
|
|
865
|
+
hasIssues: this.qualityFeedback.hasIssues
|
|
866
|
+
});
|
|
867
|
+
this.alignmentStartTime = undefined;
|
|
868
|
+
cardOutline?.classList.add('quality-warning');
|
|
869
|
+
}
|
|
671
870
|
}
|
|
672
871
|
else {
|
|
673
872
|
cardOutline?.classList.remove('perfect-match');
|
|
@@ -843,7 +1042,12 @@ export class JaakStamps {
|
|
|
843
1042
|
}
|
|
844
1043
|
}
|
|
845
1044
|
resetDetection() {
|
|
1045
|
+
const currentCaptureState = this.stateManager.getCaptureState();
|
|
1046
|
+
const wasVideoActive = currentCaptureState.isVideoActive;
|
|
846
1047
|
this.stateManager.reset();
|
|
1048
|
+
if (wasVideoActive) {
|
|
1049
|
+
this.stateManager.updateCaptureState({ isVideoActive: true });
|
|
1050
|
+
}
|
|
847
1051
|
this.hasScreenshotTaken = false;
|
|
848
1052
|
this.startTime = Date.now();
|
|
849
1053
|
this.frameSkipCounter = 0;
|
|
@@ -851,12 +1055,12 @@ export class JaakStamps {
|
|
|
851
1055
|
this.lastInferenceTime = 0;
|
|
852
1056
|
this.detectionBoxes = [];
|
|
853
1057
|
this.alignmentStartTime = undefined;
|
|
1058
|
+
this.hasDocumentDetected = false;
|
|
854
1059
|
if (this.alignmentTimer) {
|
|
855
1060
|
clearTimeout(this.alignmentTimer);
|
|
856
1061
|
this.alignmentTimer = undefined;
|
|
857
1062
|
}
|
|
858
|
-
|
|
859
|
-
if (captureState.isVideoActive && this.detectionService.isModelLoaded()) {
|
|
1063
|
+
if (wasVideoActive && this.detectionService.isModelLoaded()) {
|
|
860
1064
|
this.updateStatus('Captura reiniciada', 'Buscando documento en el marco de captura', 'active');
|
|
861
1065
|
this.detectFrame();
|
|
862
1066
|
}
|
|
@@ -870,6 +1074,7 @@ export class JaakStamps {
|
|
|
870
1074
|
this.videoStream = undefined;
|
|
871
1075
|
this.stateManager.updateCaptureState({ isVideoActive: false, isLoading: false });
|
|
872
1076
|
}
|
|
1077
|
+
this.isMaskReady = false;
|
|
873
1078
|
this.updateStatus('Sesión finalizada', '', 'ready');
|
|
874
1079
|
this.detectionBoxes = [];
|
|
875
1080
|
this.cleanup();
|
|
@@ -1058,6 +1263,146 @@ export class JaakStamps {
|
|
|
1058
1263
|
"setter": false,
|
|
1059
1264
|
"reflect": false,
|
|
1060
1265
|
"defaultValue": "'auto'"
|
|
1266
|
+
},
|
|
1267
|
+
"captureDelay": {
|
|
1268
|
+
"type": "number",
|
|
1269
|
+
"attribute": "capture-delay",
|
|
1270
|
+
"mutable": false,
|
|
1271
|
+
"complexType": {
|
|
1272
|
+
"original": "number",
|
|
1273
|
+
"resolved": "number",
|
|
1274
|
+
"references": {}
|
|
1275
|
+
},
|
|
1276
|
+
"required": false,
|
|
1277
|
+
"optional": false,
|
|
1278
|
+
"docs": {
|
|
1279
|
+
"tags": [],
|
|
1280
|
+
"text": ""
|
|
1281
|
+
},
|
|
1282
|
+
"getter": false,
|
|
1283
|
+
"setter": false,
|
|
1284
|
+
"reflect": false,
|
|
1285
|
+
"defaultValue": "1000"
|
|
1286
|
+
},
|
|
1287
|
+
"enableQualityValidation": {
|
|
1288
|
+
"type": "boolean",
|
|
1289
|
+
"attribute": "enable-quality-validation",
|
|
1290
|
+
"mutable": false,
|
|
1291
|
+
"complexType": {
|
|
1292
|
+
"original": "boolean",
|
|
1293
|
+
"resolved": "boolean",
|
|
1294
|
+
"references": {}
|
|
1295
|
+
},
|
|
1296
|
+
"required": false,
|
|
1297
|
+
"optional": false,
|
|
1298
|
+
"docs": {
|
|
1299
|
+
"tags": [],
|
|
1300
|
+
"text": ""
|
|
1301
|
+
},
|
|
1302
|
+
"getter": false,
|
|
1303
|
+
"setter": false,
|
|
1304
|
+
"reflect": false,
|
|
1305
|
+
"defaultValue": "true"
|
|
1306
|
+
},
|
|
1307
|
+
"qualityThreshold": {
|
|
1308
|
+
"type": "number",
|
|
1309
|
+
"attribute": "quality-threshold",
|
|
1310
|
+
"mutable": false,
|
|
1311
|
+
"complexType": {
|
|
1312
|
+
"original": "number",
|
|
1313
|
+
"resolved": "number",
|
|
1314
|
+
"references": {}
|
|
1315
|
+
},
|
|
1316
|
+
"required": false,
|
|
1317
|
+
"optional": false,
|
|
1318
|
+
"docs": {
|
|
1319
|
+
"tags": [],
|
|
1320
|
+
"text": ""
|
|
1321
|
+
},
|
|
1322
|
+
"getter": false,
|
|
1323
|
+
"setter": false,
|
|
1324
|
+
"reflect": false,
|
|
1325
|
+
"defaultValue": "60"
|
|
1326
|
+
},
|
|
1327
|
+
"minQualityScore": {
|
|
1328
|
+
"type": "number",
|
|
1329
|
+
"attribute": "min-quality-score",
|
|
1330
|
+
"mutable": false,
|
|
1331
|
+
"complexType": {
|
|
1332
|
+
"original": "number",
|
|
1333
|
+
"resolved": "number",
|
|
1334
|
+
"references": {}
|
|
1335
|
+
},
|
|
1336
|
+
"required": false,
|
|
1337
|
+
"optional": false,
|
|
1338
|
+
"docs": {
|
|
1339
|
+
"tags": [],
|
|
1340
|
+
"text": ""
|
|
1341
|
+
},
|
|
1342
|
+
"getter": false,
|
|
1343
|
+
"setter": false,
|
|
1344
|
+
"reflect": false,
|
|
1345
|
+
"defaultValue": "45"
|
|
1346
|
+
},
|
|
1347
|
+
"minFocusScore": {
|
|
1348
|
+
"type": "number",
|
|
1349
|
+
"attribute": "min-focus-score",
|
|
1350
|
+
"mutable": false,
|
|
1351
|
+
"complexType": {
|
|
1352
|
+
"original": "number",
|
|
1353
|
+
"resolved": "number",
|
|
1354
|
+
"references": {}
|
|
1355
|
+
},
|
|
1356
|
+
"required": false,
|
|
1357
|
+
"optional": false,
|
|
1358
|
+
"docs": {
|
|
1359
|
+
"tags": [],
|
|
1360
|
+
"text": ""
|
|
1361
|
+
},
|
|
1362
|
+
"getter": false,
|
|
1363
|
+
"setter": false,
|
|
1364
|
+
"reflect": false,
|
|
1365
|
+
"defaultValue": "16"
|
|
1366
|
+
},
|
|
1367
|
+
"minBlurScore": {
|
|
1368
|
+
"type": "number",
|
|
1369
|
+
"attribute": "min-blur-score",
|
|
1370
|
+
"mutable": false,
|
|
1371
|
+
"complexType": {
|
|
1372
|
+
"original": "number",
|
|
1373
|
+
"resolved": "number",
|
|
1374
|
+
"references": {}
|
|
1375
|
+
},
|
|
1376
|
+
"required": false,
|
|
1377
|
+
"optional": false,
|
|
1378
|
+
"docs": {
|
|
1379
|
+
"tags": [],
|
|
1380
|
+
"text": ""
|
|
1381
|
+
},
|
|
1382
|
+
"getter": false,
|
|
1383
|
+
"setter": false,
|
|
1384
|
+
"reflect": false,
|
|
1385
|
+
"defaultValue": "22"
|
|
1386
|
+
},
|
|
1387
|
+
"maxReflectionScore": {
|
|
1388
|
+
"type": "number",
|
|
1389
|
+
"attribute": "max-reflection-score",
|
|
1390
|
+
"mutable": false,
|
|
1391
|
+
"complexType": {
|
|
1392
|
+
"original": "number",
|
|
1393
|
+
"resolved": "number",
|
|
1394
|
+
"references": {}
|
|
1395
|
+
},
|
|
1396
|
+
"required": false,
|
|
1397
|
+
"optional": false,
|
|
1398
|
+
"docs": {
|
|
1399
|
+
"tags": [],
|
|
1400
|
+
"text": ""
|
|
1401
|
+
},
|
|
1402
|
+
"getter": false,
|
|
1403
|
+
"setter": false,
|
|
1404
|
+
"reflect": false,
|
|
1405
|
+
"defaultValue": "15"
|
|
1061
1406
|
}
|
|
1062
1407
|
};
|
|
1063
1408
|
}
|
|
@@ -1069,7 +1414,9 @@ export class JaakStamps {
|
|
|
1069
1414
|
"shouldMirrorVideo": {},
|
|
1070
1415
|
"showCameraSelector": {},
|
|
1071
1416
|
"isSwitchingCamera": {},
|
|
1417
|
+
"hasDocumentDetected": {},
|
|
1072
1418
|
"currentStatus": {},
|
|
1419
|
+
"qualityFeedback": {},
|
|
1073
1420
|
"performanceData": {}
|
|
1074
1421
|
};
|
|
1075
1422
|
}
|
|
@@ -1281,6 +1628,150 @@ export class JaakStamps {
|
|
|
1281
1628
|
"text": "",
|
|
1282
1629
|
"tags": []
|
|
1283
1630
|
}
|
|
1631
|
+
},
|
|
1632
|
+
"setCaptureDelay": {
|
|
1633
|
+
"complexType": {
|
|
1634
|
+
"signature": "(delay: number) => Promise<{ success: boolean; captureDelay: number; }>",
|
|
1635
|
+
"parameters": [{
|
|
1636
|
+
"name": "delay",
|
|
1637
|
+
"type": "number",
|
|
1638
|
+
"docs": ""
|
|
1639
|
+
}],
|
|
1640
|
+
"references": {
|
|
1641
|
+
"Promise": {
|
|
1642
|
+
"location": "global",
|
|
1643
|
+
"id": "global::Promise"
|
|
1644
|
+
}
|
|
1645
|
+
},
|
|
1646
|
+
"return": "Promise<{ success: boolean; captureDelay: number; }>"
|
|
1647
|
+
},
|
|
1648
|
+
"docs": {
|
|
1649
|
+
"text": "",
|
|
1650
|
+
"tags": []
|
|
1651
|
+
}
|
|
1652
|
+
},
|
|
1653
|
+
"getCaptureDelay": {
|
|
1654
|
+
"complexType": {
|
|
1655
|
+
"signature": "() => Promise<number>",
|
|
1656
|
+
"parameters": [],
|
|
1657
|
+
"references": {
|
|
1658
|
+
"Promise": {
|
|
1659
|
+
"location": "global",
|
|
1660
|
+
"id": "global::Promise"
|
|
1661
|
+
}
|
|
1662
|
+
},
|
|
1663
|
+
"return": "Promise<number>"
|
|
1664
|
+
},
|
|
1665
|
+
"docs": {
|
|
1666
|
+
"text": "",
|
|
1667
|
+
"tags": []
|
|
1668
|
+
}
|
|
1669
|
+
},
|
|
1670
|
+
"setTorchEnabled": {
|
|
1671
|
+
"complexType": {
|
|
1672
|
+
"signature": "(enabled: boolean) => Promise<{ success: boolean; enabled: boolean; }>",
|
|
1673
|
+
"parameters": [{
|
|
1674
|
+
"name": "enabled",
|
|
1675
|
+
"type": "boolean",
|
|
1676
|
+
"docs": ""
|
|
1677
|
+
}],
|
|
1678
|
+
"references": {
|
|
1679
|
+
"Promise": {
|
|
1680
|
+
"location": "global",
|
|
1681
|
+
"id": "global::Promise"
|
|
1682
|
+
}
|
|
1683
|
+
},
|
|
1684
|
+
"return": "Promise<{ success: boolean; enabled: boolean; }>"
|
|
1685
|
+
},
|
|
1686
|
+
"docs": {
|
|
1687
|
+
"text": "",
|
|
1688
|
+
"tags": []
|
|
1689
|
+
}
|
|
1690
|
+
},
|
|
1691
|
+
"focusAtPoint": {
|
|
1692
|
+
"complexType": {
|
|
1693
|
+
"signature": "(x: number, y: number) => Promise<{ success: boolean; coordinates: { x: number; y: number; }; }>",
|
|
1694
|
+
"parameters": [{
|
|
1695
|
+
"name": "x",
|
|
1696
|
+
"type": "number",
|
|
1697
|
+
"docs": ""
|
|
1698
|
+
}, {
|
|
1699
|
+
"name": "y",
|
|
1700
|
+
"type": "number",
|
|
1701
|
+
"docs": ""
|
|
1702
|
+
}],
|
|
1703
|
+
"references": {
|
|
1704
|
+
"Promise": {
|
|
1705
|
+
"location": "global",
|
|
1706
|
+
"id": "global::Promise"
|
|
1707
|
+
}
|
|
1708
|
+
},
|
|
1709
|
+
"return": "Promise<{ success: boolean; coordinates: { x: number; y: number; }; }>"
|
|
1710
|
+
},
|
|
1711
|
+
"docs": {
|
|
1712
|
+
"text": "",
|
|
1713
|
+
"tags": []
|
|
1714
|
+
}
|
|
1715
|
+
},
|
|
1716
|
+
"getImageQuality": {
|
|
1717
|
+
"complexType": {
|
|
1718
|
+
"signature": "() => Promise<{ qualityScore: any; overallQuality: any; issues: any; recommendations: any; canCapture: boolean; }>",
|
|
1719
|
+
"parameters": [],
|
|
1720
|
+
"references": {
|
|
1721
|
+
"Promise": {
|
|
1722
|
+
"location": "global",
|
|
1723
|
+
"id": "global::Promise"
|
|
1724
|
+
}
|
|
1725
|
+
},
|
|
1726
|
+
"return": "Promise<{ qualityScore: any; overallQuality: any; issues: any; recommendations: any; canCapture: boolean; }>"
|
|
1727
|
+
},
|
|
1728
|
+
"docs": {
|
|
1729
|
+
"text": "",
|
|
1730
|
+
"tags": []
|
|
1731
|
+
}
|
|
1732
|
+
},
|
|
1733
|
+
"setQualityThresholds": {
|
|
1734
|
+
"complexType": {
|
|
1735
|
+
"signature": "(thresholds: QualityThresholds) => Promise<{ success: boolean; thresholds: QualityThresholds; }>",
|
|
1736
|
+
"parameters": [{
|
|
1737
|
+
"name": "thresholds",
|
|
1738
|
+
"type": "QualityThresholds",
|
|
1739
|
+
"docs": ""
|
|
1740
|
+
}],
|
|
1741
|
+
"references": {
|
|
1742
|
+
"Promise": {
|
|
1743
|
+
"location": "global",
|
|
1744
|
+
"id": "global::Promise"
|
|
1745
|
+
},
|
|
1746
|
+
"QualityThresholds": {
|
|
1747
|
+
"location": "import",
|
|
1748
|
+
"path": "../../services/interfaces/IDetectionService",
|
|
1749
|
+
"id": "src/services/interfaces/IDetectionService.ts::QualityThresholds"
|
|
1750
|
+
}
|
|
1751
|
+
},
|
|
1752
|
+
"return": "Promise<{ success: boolean; thresholds: QualityThresholds; }>"
|
|
1753
|
+
},
|
|
1754
|
+
"docs": {
|
|
1755
|
+
"text": "",
|
|
1756
|
+
"tags": []
|
|
1757
|
+
}
|
|
1758
|
+
},
|
|
1759
|
+
"getQualityThresholds": {
|
|
1760
|
+
"complexType": {
|
|
1761
|
+
"signature": "() => Promise<{ minQualityScore: number; minFocusScore: number; minBlurScore: number; maxReflectionScore: number; }>",
|
|
1762
|
+
"parameters": [],
|
|
1763
|
+
"references": {
|
|
1764
|
+
"Promise": {
|
|
1765
|
+
"location": "global",
|
|
1766
|
+
"id": "global::Promise"
|
|
1767
|
+
}
|
|
1768
|
+
},
|
|
1769
|
+
"return": "Promise<{ minQualityScore: number; minFocusScore: number; minBlurScore: number; maxReflectionScore: number; }>"
|
|
1770
|
+
},
|
|
1771
|
+
"docs": {
|
|
1772
|
+
"text": "",
|
|
1773
|
+
"tags": []
|
|
1774
|
+
}
|
|
1284
1775
|
}
|
|
1285
1776
|
};
|
|
1286
1777
|
}
|