@jaak.ai/stamps 2.1.0-dev.5 → 2.1.0-dev.7
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 +270 -25
- 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 +36 -11
- package/dist/collection/components/my-component/my-component.js +240 -21
- package/dist/collection/components/my-component/my-component.js.map +1 -1
- package/dist/collection/services/DetectionService.js +32 -4
- package/dist/collection/services/DetectionService.js.map +1 -1
- package/dist/components/jaak-stamps.js +272 -25
- 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 +270 -25
- 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-be6b6ca3.entry.js +2 -0
- package/dist/jaak-stamps-webcomponent/p-be6b6ca3.entry.js.map +1 -0
- package/dist/types/components/my-component/my-component.d.ts +7 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-c08802a9.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-c08802a9.entry.js.map +0 -1
|
@@ -16,7 +16,7 @@ var patchBrowser = () => {
|
|
|
16
16
|
|
|
17
17
|
patchBrowser().then(async (options) => {
|
|
18
18
|
await globalScripts();
|
|
19
|
-
return bootstrapLazy([["jaak-stamps",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"maskSize":[2,"mask-size"],"cropMargin":[2,"crop-margin"],"useDocumentClassification":[4,"use-document-classification"],"useDocumentDetector":[4,"use-document-detector"],"preferredCamera":[1,"preferred-camera"],"captureDelay":[2,"capture-delay"],"enableBackDocumentTimer":[4,"enable-back-document-timer"],"backDocumentTimerDuration":[2,"back-document-timer-duration"],"detectionBoxes":[32],"sideAlignment":[32],"isMaskReady":[32],"shouldMirrorVideo":[32],"showCameraSelector":[32],"isSwitchingCamera":[32],"hasDocumentDetected":[32],"cameraInfoWithAutofocus":[32],"currentStatus":[32],"performanceData":[32],"backDocumentTimerRemaining":[32],"showManualCaptureButton":[32],"performanceDegradedMode":[32],"showPerformanceMessage":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"skipBackCapture":[64],"getStatus":[64],"preloadModel":[64],"getCameraInfo":[64],"setPreferredCamera":[64],"setCaptureDelay":[64],"getCaptureDelay":[64]}]]]], options);
|
|
19
|
+
return bootstrapLazy([["jaak-stamps",[[1,"jaak-stamps",{"debug":[4],"alignmentTolerance":[2,"alignment-tolerance"],"maskSize":[2,"mask-size"],"cropMargin":[2,"crop-margin"],"useDocumentClassification":[4,"use-document-classification"],"useDocumentDetector":[4,"use-document-detector"],"preferredCamera":[1,"preferred-camera"],"captureDelay":[2,"capture-delay"],"enableBackDocumentTimer":[4,"enable-back-document-timer"],"backDocumentTimerDuration":[2,"back-document-timer-duration"],"detectionBoxes":[32],"sideAlignment":[32],"isMaskReady":[32],"shouldMirrorVideo":[32],"showCameraSelector":[32],"isSwitchingCamera":[32],"hasDocumentDetected":[32],"cameraInfoWithAutofocus":[32],"currentStatus":[32],"performanceData":[32],"backDocumentTimerRemaining":[32],"showManualCaptureButton":[32],"performanceDegradedMode":[32],"showPerformanceMessage":[32],"captureStateVersion":[32],"processingButton":[32],"getCapturedImages":[64],"isProcessCompleted":[64],"startCapture":[64],"stopCapture":[64],"resetCapture":[64],"skipBackCapture":[64],"getStatus":[64],"preloadModel":[64],"getCameraInfo":[64],"setPreferredCamera":[64],"setCaptureDelay":[64],"getCaptureDelay":[64]}]]]], options);
|
|
20
20
|
});
|
|
21
21
|
//# sourceMappingURL=jaak-stamps-webcomponent.js.map
|
|
22
22
|
|
|
@@ -670,7 +670,12 @@ class DetectionService {
|
|
|
670
670
|
this.session = await window.ort.InferenceSession.create(this.MODEL_PATH, sessionOptions);
|
|
671
671
|
}
|
|
672
672
|
catch (error) {
|
|
673
|
-
|
|
673
|
+
// Múltiples tipos de errores de memoria que pueden ocurrir
|
|
674
|
+
const isMemoryError = error.message.includes('failed to allocate a buffer') ||
|
|
675
|
+
error.message.includes('Out of memory') ||
|
|
676
|
+
error.message.includes('RangeError: Out of memory') ||
|
|
677
|
+
error.message.includes('no available backend found');
|
|
678
|
+
if (isMemoryError) {
|
|
674
679
|
const fallbackOptions = {
|
|
675
680
|
executionProviders: ['wasm'],
|
|
676
681
|
graphOptimizationLevel: 'disabled',
|
|
@@ -680,8 +685,17 @@ class DetectionService {
|
|
|
680
685
|
executionMode: 'sequential',
|
|
681
686
|
interOpNumThreads: 1,
|
|
682
687
|
intraOpNumThreads: 1,
|
|
688
|
+
// Configuraciones adicionales para dispositivos con poca memoria
|
|
689
|
+
enableProfiling: false,
|
|
690
|
+
sessionLogSeverityLevel: 4,
|
|
691
|
+
sessionLogVerbosityLevel: 0,
|
|
683
692
|
};
|
|
684
|
-
|
|
693
|
+
try {
|
|
694
|
+
this.session = await window.ort.InferenceSession.create(this.MODEL_PATH, fallbackOptions);
|
|
695
|
+
}
|
|
696
|
+
catch (fallbackError) {
|
|
697
|
+
throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);
|
|
698
|
+
}
|
|
685
699
|
}
|
|
686
700
|
else {
|
|
687
701
|
throw error;
|
|
@@ -721,7 +735,12 @@ class DetectionService {
|
|
|
721
735
|
this.mobileNetSession = await window.ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, sessionOptions);
|
|
722
736
|
}
|
|
723
737
|
catch (error) {
|
|
724
|
-
|
|
738
|
+
// Múltiples tipos de errores de memoria que pueden ocurrir
|
|
739
|
+
const isMemoryError = error.message.includes('failed to allocate a buffer') ||
|
|
740
|
+
error.message.includes('Out of memory') ||
|
|
741
|
+
error.message.includes('RangeError: Out of memory') ||
|
|
742
|
+
error.message.includes('no available backend found');
|
|
743
|
+
if (isMemoryError) {
|
|
725
744
|
const fallbackOptions = {
|
|
726
745
|
executionProviders: ['wasm'],
|
|
727
746
|
graphOptimizationLevel: 'disabled',
|
|
@@ -731,8 +750,17 @@ class DetectionService {
|
|
|
731
750
|
executionMode: 'sequential',
|
|
732
751
|
interOpNumThreads: 1,
|
|
733
752
|
intraOpNumThreads: 1,
|
|
753
|
+
// Configuraciones adicionales para dispositivos con poca memoria
|
|
754
|
+
enableProfiling: false,
|
|
755
|
+
sessionLogSeverityLevel: 4,
|
|
756
|
+
sessionLogVerbosityLevel: 0,
|
|
734
757
|
};
|
|
735
|
-
|
|
758
|
+
try {
|
|
759
|
+
this.mobileNetSession = await window.ort.InferenceSession.create(this.MOBILENET_MODEL_PATH, fallbackOptions);
|
|
760
|
+
}
|
|
761
|
+
catch (fallbackError) {
|
|
762
|
+
throw new Error(`no available backend found. ERR: [wasm] RangeError: Out of memory`);
|
|
763
|
+
}
|
|
736
764
|
}
|
|
737
765
|
else {
|
|
738
766
|
throw error;
|
|
@@ -1089,7 +1117,7 @@ class ServiceContainer {
|
|
|
1089
1117
|
}
|
|
1090
1118
|
}
|
|
1091
1119
|
|
|
1092
|
-
const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background:#333;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);animation:drawCheck 0.4s ease-out 0.2s both}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled{background:#e9ecef;color:#6c757d;cursor:not-allowed;transform:none}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(255, 255, 255, 0.3);border-top:2px solid #ffffff;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{background:#e9ecef;color:#6c757d;cursor:not-allowed;transform:none}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}}";
|
|
1120
|
+
const myComponentCss = ":host{display:block;width:100%;height:100%;font-family:system-ui, -apple-system, sans-serif;color:#1a1a1a}.detector-container{display:flex;flex-direction:column;align-items:center;width:100%;height:100%}h1{font-size:24px;font-weight:500;color:#333;margin:0 0 24px 0}.video-container{position:relative;width:100%;height:100%;background:#333;border:1px solid #e0e0e0;border-radius:8px;overflow:hidden}video,.detection-overlay{position:absolute;width:100%;height:100%;border-radius:8px}video.mirror,.detection-overlay.mirror{transform:rotateY(180deg)}.detection-overlay{z-index:1;pointer-events:none}video{z-index:0}.detection-box{transition:opacity 0.2s ease}.status{margin-top:16px;font-size:12px;color:#666}.overlay-mask{position:absolute;top:0;left:0;width:100%;height:100%;z-index:10;display:block;pointer-events:none}.card-outline{position:absolute;top:var(--mask-center-y, 50%);left:var(--mask-center-x, 50%);transform:translate(-50%, -50%);width:var(--mask-width, 88%);height:var(--mask-height, 55%);border:none;border-radius:4px;background:transparent;opacity:0.8}.side{position:absolute;background:#999;transition:background-color 0.3s ease;border-radius:1px}.side-top.aligned{border-left-color:#28a745;border-top-color:#28a745}.side-right.aligned{border-right-color:#28a745;border-top-color:#28a745}.side-bottom.aligned{border-left-color:#28a745;border-bottom-color:#28a745}.side-left.aligned{border-right-color:#28a745;border-bottom-color:#28a745}.side-top{top:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-right{top:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-top:6px solid #ffffff;background:transparent}.side-bottom{bottom:-3px;left:-3px;width:30px;height:30px;border-left:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.side-left{bottom:-3px;right:-3px;width:30px;height:30px;border-right:6px solid #ffffff;border-bottom:6px solid #ffffff;background:transparent}.guide-text{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);color:#ffffff;font-size:12px;font-weight:500;text-align:center;white-space:normal;padding:13px;max-width:300px;z-index:20;height:fit-content;width:fit-content;animation:slideInFromTopCentered 0.3s ease-out}.quality-indicator{position:absolute;top:20px;right:20px;display:flex;align-items:center;gap:8px;background:rgba(0, 0, 0, 0.8);padding:8px 12px;border-radius:20px;z-index:25;transition:all 0.3s ease}.quality-indicator.warning{background:rgba(255, 152, 0, 0.9)}.quality-indicator.good{background:rgba(76, 175, 80, 0.9)}.quality-score{color:#fff;font-size:12px;font-weight:600;min-width:30px;text-align:center}.quality-status{width:20px;height:20px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:bold;color:#fff;transition:all 0.3s ease}.quality-status.ready{background:#4CAF50}.quality-status.not-ready{background:#f44336}.card-outline.quality-warning{animation:qualityWarning 1s ease-in-out infinite alternate}@keyframes qualityWarning{0%{box-shadow:0 0 0 3px rgba(255, 152, 0, 0.6)}100%{box-shadow:0 0 0 6px rgba(255, 152, 0, 0.3)}}.capture-animation{position:absolute;top:0;left:0;width:100%;height:100%;background:#fff;opacity:0;z-index:30;pointer-events:none;animation:captureFlash 0.6s ease-out}@keyframes captureFlash{0%{opacity:0}15%{opacity:0.8}30%{opacity:0}45%{opacity:0.4}60%{opacity:0}100%{opacity:0}}.card-outline.capturing{animation:pulseGreen 0.6s ease-out}@keyframes pulseGreen{0%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}50%{border-color:#28a745;box-shadow:0 0 0 8px rgba(40, 167, 69, 0.6)}100%{border-color:#28a745;box-shadow:0 0 0 4px rgba(40, 167, 69, 0)}}.flip-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showFlipInstruction 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.id-card-icon{width:80px;height:50px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:8px;position:relative;animation:flipCard 2s ease-in-out infinite;box-shadow:0 4px 12px rgba(0, 0, 0, 0.3)}.id-card-icon::before{content:'';position:absolute;top:8px;left:8px;width:16px;height:12px;background:rgba(255, 255, 255, 0.9);border-radius:2px}.id-card-icon::after{content:'';position:absolute;top:25px;left:8px;width:64px;height:3px;background:rgba(255, 255, 255, 0.7);border-radius:1px;box-shadow:0 6px 0 rgba(255, 255, 255, 0.7), 0 12px 0 rgba(255, 255, 255, 0.7)}.flip-text{margin-top:12px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px}@keyframes showFlipInstruction{0%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.8)}}@keyframes flipCard{0%{transform:rotateY(0deg)}50%{transform:rotateY(180deg)}100%{transform:rotateY(360deg)}}.success-animation{position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);z-index:35;pointer-events:none;opacity:0;animation:showSuccessMessage 3s ease-in-out;display:flex;flex-direction:column;align-items:center;justify-content:center}.check-icon{width:80px;height:80px;background:linear-gradient(135deg, #6c757d 0%, #495057 100%);border-radius:50%;position:relative;animation:bounceSuccess 0.6s ease-out;box-shadow:0 4px 16px rgba(108, 117, 125, 0.4);display:flex;align-items:center;justify-content:center}.check-icon::before{content:'';position:absolute;width:20px;height:35px;border:4px solid #fff;border-top:none;border-left:none;transform:rotate(45deg);animation:drawCheck 0.4s ease-out 0.2s both}.success-text{margin-top:16px;color:#fff;font-size:14px;font-weight:600;text-align:center;background:rgba(128, 128, 128, 0.8);padding:12px 20px;border-radius:20px;max-width:300px;animation:fadeInUp 0.5s ease-out 0.4s both}@keyframes showSuccessMessage{0%{opacity:0;transform:translate(-50%, -50%) scale(0.5)}15%{opacity:1;transform:translate(-50%, -50%) scale(1)}85%{opacity:1;transform:translate(-50%, -50%) scale(1)}100%{opacity:0;transform:translate(-50%, -50%) scale(0.9)}}@keyframes bounceSuccess{0%{transform:scale(0)}50%{transform:scale(1.1)}100%{transform:scale(1)}}@keyframes drawCheck{0%{width:0;height:0}50%{width:20px;height:0}100%{width:20px;height:35px}}@keyframes fadeInUp{0%{opacity:0;transform:translateY(20px)}100%{opacity:1;transform:translateY(0)}}.skip-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.back-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:320px}.back-capture-buttons{display:flex;gap:12px;align-items:center;justify-content:center;flex-wrap:wrap}.capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.capture-button:hover{background:#f8f9fa}.capture-button:active{background:#e9ecef;transform:translateY(1px)}.capture-button:disabled,.capture-button.primary-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.back-capture-section{bottom:16px;max-width:300px}.back-capture-buttons{flex-direction:column;gap:8px;width:100%}.capture-button,.back-capture-buttons .skip-button{width:100%;max-width:200px;padding:10px 20px;font-size:13px}.capture-button:disabled,.capture-button.primary-button:disabled,.skip-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}.skip-explanation{background:rgba(0, 0, 0, 0.5);color:#ffffff;padding:10px 16px;border-radius:8px;font-size:14px;font-weight:500;text-align:center;margin-bottom:12px;box-shadow:0 2px 8px rgba(0, 0, 0, 0.2);backdrop-filter:blur(12px);border:1px solid rgba(255, 255, 255, 0.1);animation:fadeIn 0.3s ease-in-out}@keyframes fadeIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}.guide-text.performance-warning-text{animation:gentlePulse 2s ease-in-out infinite;background:rgba(255, 107, 107, 0.3);border:1px solid rgba(255, 107, 107, 0.5)}@keyframes gentlePulse{0%,100%{transform:translate(-50%, -50%) scale(1);background:rgba(255, 107, 107, 0.3)}50%{transform:translate(-50%, -50%) scale(1.02);background:rgba(255, 107, 107, 0.4)}}.skip-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.skip-button:hover{background:#f8f9fa}.skip-button:active{background:#e9ecef;transform:translateY(1px)}.skip-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}.camera-controls{position:absolute;top:16px;right:16px;z-index:25;display:flex;gap:8px;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}.camera-selector-button{height:32px;padding:0 10px;border:none;border-radius:8px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(12px);color:#ffffff;font-size:12px;font-weight:500;cursor:pointer;transition:all 0.2s ease;display:flex;align-items:center;justify-content:center;border:1px solid rgba(255, 255, 255, 0.1);white-space:nowrap;min-width:fit-content}.camera-selector-button:hover{background:rgba(0, 0, 0, 0.8);border-color:rgba(255, 255, 255, 0.2);transform:translateY(-1px)}.camera-selector-button:active{transform:translateY(0);background:rgba(0, 0, 0, 0.9)}.camera-selector-button:disabled,.camera-selector-button.loading{opacity:0.7;cursor:not-allowed;pointer-events:none}.camera-selector-button:disabled:hover,.camera-selector-button.loading:hover{transform:none;background:rgba(0, 0, 0, 0.6);border-color:rgba(255, 255, 255, 0.1)}.button-spinner{width:16px;height:16px;border:2px solid rgba(0, 0, 0, 0.2);border-top:2px solid #333333;border-radius:50%;animation:spin 1s linear infinite;display:inline-block;margin-right:8px;vertical-align:middle}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.camera-selector-dropdown{position:absolute;top:56px;right:16px;z-index:30;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;min-width:260px;max-width:300px;border:1px solid rgba(255, 255, 255, 0.1);overflow:hidden;pointer-events:auto;animation:slideInFromTop 0.3s ease-out}@keyframes slideInFromTop{0%{opacity:0;transform:translateY(-8px) scale(0.95)}100%{opacity:1;transform:translateY(0) scale(1)}}@keyframes slideInFromTopCentered{0%{opacity:0;transform:translate(-50%, -50%) translateY(-8px) scale(0.95)}100%{opacity:1;transform:translate(-50%, -50%) translateY(0) scale(1)}}.camera-selector-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid rgba(255, 255, 255, 0.1)}.camera-selector-header span{font-weight:500;color:#ffffff;font-size:13px;opacity:0.9}.close-selector{width:20px;height:20px;border:none;background:none;color:rgba(255, 255, 255, 0.7);font-size:16px;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;transition:all 0.2s ease}.close-selector:hover{background:rgba(255, 255, 255, 0.1);color:#ffffff}.camera-list{padding:4px 0;max-height:240px;overflow-y:auto}.camera-option{width:100%;padding:8px 12px;border:none;background:none;text-align:left;cursor:pointer;transition:all 0.2s ease;display:flex;justify-content:flex-start;align-items:center;gap:8px;color:rgba(255, 255, 255, 0.9)}.camera-option:hover{background:rgba(255, 255, 255, 0.08)}.camera-option.selected{background:rgba(255, 255, 255, 0.12);color:#ffffff}.camera-label{font-size:13px;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-right:0;font-weight:400;display:flex;align-items:center;gap:6px}.camera-label .autofocus-icon{font-size:12px;color:#ffffff !important;opacity:0.8;flex-shrink:0}.selected-indicator{font-size:14px;color:#ffffff;opacity:0.9;flex-shrink:0}.device-info{padding:6px 12px;border-top:1px solid rgba(255, 255, 255, 0.1);background:rgba(255, 255, 255, 0.05)}.device-info small{color:rgba(255, 255, 255, 0.6);font-size:11px;text-transform:capitalize;font-weight:400}@media (max-width: 480px){.camera-controls{top:12px;right:12px;gap:6px}.camera-selector-button{height:36px;padding:0 12px;font-size:11px;border-radius:6px}.camera-selector-dropdown{right:12px;top:48px;min-width:240px;max-width:calc(100vw - 24px)}.camera-selector-header{padding:6px 10px}.camera-option{padding:6px 10px}.device-info{padding:4px 10px}}.watermark{position:absolute;bottom:12px;right:12px;z-index:15;pointer-events:none;opacity:0.7}.watermark img{height:24px;width:auto;filter:drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3))}.component-status{position:absolute;top:16px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);display:flex;align-items:center;gap:6px;padding:6px 10px;z-index:40;height:32px;width:fit-content;animation:slideInFromTop 0.3s ease-out}.status-spinner{width:16px;height:16px;border:1px solid rgba(255, 255, 255, 0.3);border-top:1px solid #ffffff;border-radius:50%;animation:statusSpin 1s linear infinite;flex-shrink:0}.status-content{display:flex;flex-direction:column;gap:1px}.status-message{color:#ffffff;font-size:12px;font-weight:500;margin:0}.status-description{color:rgba(255, 255, 255, 0.7);font-size:10px;line-height:1.2;margin:0}@keyframes statusSpin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@media (max-width: 480px){.component-status{top:12px;left:12px;padding:4px 8px;gap:4px;height:28px;border-radius:8px}.status-spinner{width:14px;height:14px}.status-message{font-size:11px}.status-description{font-size:9px}.guide-text{font-size:11px;padding:4px 8px;border-radius:8px}}.loading-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.85);backdrop-filter:blur(4px);display:flex;flex-direction:column;align-items:center;justify-content:center;z-index:30;border-radius:8px}.loading-spinner{width:50px;height:50px;border:3px solid rgba(255, 255, 255, 0.15);border-top:3px solid #28a745;border-radius:50%;animation:spin 1s ease-in-out infinite;margin-bottom:16px}.loading-text{color:#ffffff;font-size:14px;font-weight:500;text-align:center;opacity:0.9;margin-bottom:4px}.loading-description{color:rgba(255, 255, 255, 0.7);font-size:12px;text-align:center;opacity:0.8}@keyframes spin{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.performance-monitor{position:absolute;top:70px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromTop 0.3s ease-out;transition:all 0.3s ease}@keyframes slideInFromLeft{0%{opacity:0;transform:translateX(-20px) scale(0.95)}100%{opacity:1;transform:translateX(0) scale(1)}}.performance-expanded{padding:6px 10px}.metrics-row{display:flex;gap:8px;margin-bottom:4px}.metrics-row:last-child{margin-bottom:0}.metric-compact{display:flex;flex-direction:column;align-items:center;gap:2px;min-width:50px}.metric-label{font-size:9px;color:rgba(255, 255, 255, 0.6);font-weight:500;text-transform:uppercase;letter-spacing:0.3px}.metric-value{font-size:10px;font-weight:600;font-family:'Monaco', 'Menlo', 'Consolas', monospace;padding:2px 4px;border-radius:3px;text-align:center;white-space:nowrap}.metric-value.good{color:#4ade80;background:rgba(74, 222, 128, 0.1);border:1px solid rgba(74, 222, 128, 0.2)}.metric-value.warning{color:#fbbf24;background:rgba(251, 191, 36, 0.1);border:1px solid rgba(251, 191, 36, 0.2)}.metric-value.danger{color:#f87171;background:rgba(248, 113, 113, 0.1);border:1px solid rgba(248, 113, 113, 0.2)}@media (max-width: 480px){.performance-monitor{top:60px;left:12px;width:fit-content}.performance-expanded{padding:4px 8px}.metrics-row{gap:6px;margin-bottom:3px}.metric-compact{min-width:45px;gap:1px}.metric-label{font-size:8px}.metric-value{font-size:9px;padding:1px 3px}}.quality-monitor{position:absolute;top:200px;left:16px;background:rgba(0, 0, 0, 0.25);backdrop-filter:blur(20px);border-radius:12px;border:1px solid rgba(255, 255, 255, 0.1);z-index:35;width:fit-content;animation:slideInFromLeft 0.3s ease-out;transition:all 0.3s ease}.quality-text{padding:6px 10px;font-size:11px;color:white;font-family:'Monaco', 'Menlo', 'Consolas', monospace;line-height:1.4}.quality-fail{color:#ff9999}@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.7}}.metric-value.danger{animation:pulse 2s infinite}@media (max-width: 480px){.quality-monitor{top:160px;left:12px}.quality-text{padding:4px 8px;font-size:10px}}.manual-capture-section{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);z-index:25;display:flex;flex-direction:column;align-items:center;width:100%;max-width:300px}.manual-capture-button{pointer-events:auto;background:#fff;color:#333;border:none;border-radius:25px;padding:12px 24px;font-size:14px;font-weight:600;cursor:pointer;transition:all 0.3s ease}.manual-capture-button:hover{background:#f8f9fa}.manual-capture-button:active{background:#e9ecef;transform:translateY(1px)}.manual-capture-button:disabled{cursor:not-allowed !important;transform:none !important;opacity:0.7 !important;transition:none !important}@media (max-width: 480px){.manual-capture-section{bottom:16px;max-width:280px}.manual-capture-button{padding:10px 20px;font-size:13px}.manual-capture-button:disabled{opacity:0.7 !important;cursor:not-allowed !important}}";
|
|
1093
1121
|
|
|
1094
1122
|
const JaakStamps = class {
|
|
1095
1123
|
constructor(hostRef) {
|
|
@@ -1147,6 +1175,8 @@ const JaakStamps = class {
|
|
|
1147
1175
|
showManualCaptureButton = false;
|
|
1148
1176
|
performanceDegradedMode = false; // Auto-switched to manual mode due to performance
|
|
1149
1177
|
showPerformanceMessage = false; // Show performance message temporarily
|
|
1178
|
+
captureStateVersion = 0; // Triggers re-render when StateManager changes
|
|
1179
|
+
processingButton = null; // Track which button is processing
|
|
1150
1180
|
// Services
|
|
1151
1181
|
serviceContainer;
|
|
1152
1182
|
eventBus;
|
|
@@ -1198,14 +1228,19 @@ const JaakStamps = class {
|
|
|
1198
1228
|
canvasPool = [];
|
|
1199
1229
|
MAX_CANVAS_POOL_SIZE = 3;
|
|
1200
1230
|
async componentDidLoad() {
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
this.
|
|
1231
|
+
try {
|
|
1232
|
+
this.updateStatus('Preparando capturador...', 'Configurando herramientas de captura', 'initializing');
|
|
1233
|
+
await this.initializeServices();
|
|
1234
|
+
this.updateStatus('Preparando funciones...', 'Configurando herramientas de trabajo', 'initializing');
|
|
1235
|
+
await this.setupEventListeners();
|
|
1236
|
+
this.updateStatus('Configurando cámara...', 'Detectando dispositivos disponibles', 'initializing');
|
|
1237
|
+
await this.initializeComponent();
|
|
1238
|
+
if (this.debug) {
|
|
1239
|
+
this.initializePerformanceMonitor();
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
catch (error) {
|
|
1243
|
+
this.updateStatus('Error de inicialización', error.message, 'error');
|
|
1209
1244
|
}
|
|
1210
1245
|
}
|
|
1211
1246
|
async initializeServices() {
|
|
@@ -1352,6 +1387,9 @@ const JaakStamps = class {
|
|
|
1352
1387
|
this.updateMaskDimensions(rect);
|
|
1353
1388
|
}
|
|
1354
1389
|
}
|
|
1390
|
+
triggerRerender() {
|
|
1391
|
+
this.captureStateVersion = this.captureStateVersion + 1;
|
|
1392
|
+
}
|
|
1355
1393
|
getGuideText(step) {
|
|
1356
1394
|
if (step === 'completed') {
|
|
1357
1395
|
return 'Proceso completado';
|
|
@@ -1517,8 +1555,14 @@ const JaakStamps = class {
|
|
|
1517
1555
|
}
|
|
1518
1556
|
}
|
|
1519
1557
|
async skipBackCapture() {
|
|
1558
|
+
console.log('🟡 Botón clicked: Saltar reverso');
|
|
1559
|
+
// Set processing state immediately
|
|
1560
|
+
this.processingButton = 'skip-back';
|
|
1561
|
+
// Add small delay to show spinner
|
|
1562
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
1520
1563
|
const readyCheck = this.isComponentReady();
|
|
1521
1564
|
if (!readyCheck.ready) {
|
|
1565
|
+
this.processingButton = null;
|
|
1522
1566
|
return { success: false, error: readyCheck.message };
|
|
1523
1567
|
}
|
|
1524
1568
|
try {
|
|
@@ -1535,6 +1579,10 @@ const JaakStamps = class {
|
|
|
1535
1579
|
catch (error) {
|
|
1536
1580
|
return { success: false, error: error.message };
|
|
1537
1581
|
}
|
|
1582
|
+
finally {
|
|
1583
|
+
// Always clear processing state when done
|
|
1584
|
+
this.processingButton = null;
|
|
1585
|
+
}
|
|
1538
1586
|
}
|
|
1539
1587
|
async getStatus() {
|
|
1540
1588
|
const readyCheck = this.isComponentReady();
|
|
@@ -1712,9 +1760,53 @@ const JaakStamps = class {
|
|
|
1712
1760
|
// Always allow getting capture delay, even during initialization
|
|
1713
1761
|
return this.captureDelay;
|
|
1714
1762
|
}
|
|
1763
|
+
// Memory and device capability detection
|
|
1764
|
+
checkDeviceCapabilities() {
|
|
1765
|
+
const deviceMemory = navigator.deviceMemory;
|
|
1766
|
+
const hardwareConcurrency = navigator.hardwareConcurrency || 1;
|
|
1767
|
+
const isLowEndDevice = hardwareConcurrency <= 2;
|
|
1768
|
+
const isMobile = /Android|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
|
1769
|
+
const isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
|
|
1770
|
+
// Si tenemos info de memoria del dispositivo
|
|
1771
|
+
if (deviceMemory && deviceMemory < 4) {
|
|
1772
|
+
return {
|
|
1773
|
+
canUseML: false,
|
|
1774
|
+
reason: `Memoria del dispositivo (${deviceMemory}GB) insuficiente para detección automática. Modo manual activado para mejor rendimiento.`,
|
|
1775
|
+
memoryMB: deviceMemory * 1024
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
// Dispositivos móviles de gama baja
|
|
1779
|
+
if (isMobile && isLowEndDevice) {
|
|
1780
|
+
return {
|
|
1781
|
+
canUseML: false,
|
|
1782
|
+
reason: 'Dispositivo móvil optimizado detectado. Modo manual activado para mejor rendimiento y duración de batería.',
|
|
1783
|
+
memoryMB: null
|
|
1784
|
+
};
|
|
1785
|
+
}
|
|
1786
|
+
// Safari tiene limitaciones conocidas con WASM
|
|
1787
|
+
if (isSafari) {
|
|
1788
|
+
return {
|
|
1789
|
+
canUseML: false,
|
|
1790
|
+
reason: 'Safari detectado. Modo manual activado por compatibilidad optimizada con este navegador.',
|
|
1791
|
+
memoryMB: null
|
|
1792
|
+
};
|
|
1793
|
+
}
|
|
1794
|
+
return {
|
|
1795
|
+
canUseML: true,
|
|
1796
|
+
reason: 'Dispositivo compatible con detección automática.',
|
|
1797
|
+
memoryMB: deviceMemory ? deviceMemory * 1024 : null
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1715
1800
|
// DETECTION METHODS
|
|
1716
1801
|
async startDetection() {
|
|
1717
1802
|
try {
|
|
1803
|
+
// Verificar capacidades del dispositivo antes de cargar modelos
|
|
1804
|
+
const capabilities = this.checkDeviceCapabilities();
|
|
1805
|
+
// Si el dispositivo no puede usar ML o tenemos problemas de memoria, usar modo manual
|
|
1806
|
+
if (!capabilities.canUseML && this.useDocumentDetector) {
|
|
1807
|
+
this.switchToManualModeWithWarning(capabilities.reason);
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1718
1810
|
// Paso 1: Verificar y cargar modelos si es necesario
|
|
1719
1811
|
if (!this.detectionService.isModelLoaded()) {
|
|
1720
1812
|
const loadStartTime = performance.now();
|
|
@@ -1724,16 +1816,32 @@ const JaakStamps = class {
|
|
|
1724
1816
|
await this.detectionService.loadModel();
|
|
1725
1817
|
}
|
|
1726
1818
|
catch (modelError) {
|
|
1727
|
-
|
|
1728
|
-
|
|
1819
|
+
// Si es un error de memoria, cambiar a modo manual con mensaje específico
|
|
1820
|
+
if (modelError.message.includes('Out of memory') || modelError.message.includes('no available backend')) {
|
|
1821
|
+
const memoryInfo = navigator.deviceMemory ? `(${navigator.deviceMemory}GB disponible)` : '';
|
|
1822
|
+
this.switchToManualModeWithWarning(`Memoria insuficiente para detección automática ${memoryInfo}. Modo manual activado - funciona igual de bien!`);
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
else {
|
|
1826
|
+
this.switchToManualModeWithError('Error al cargar modelo de detección');
|
|
1827
|
+
throw modelError;
|
|
1828
|
+
}
|
|
1729
1829
|
}
|
|
1730
1830
|
this.updateStatus('Optimizando detección...', 'Configurando reconocimiento de documentos', 'loading');
|
|
1731
1831
|
try {
|
|
1732
1832
|
await this.detectionService.loadClassificationModel();
|
|
1733
1833
|
}
|
|
1734
1834
|
catch (classificationError) {
|
|
1735
|
-
|
|
1736
|
-
|
|
1835
|
+
// Si es un error de memoria, cambiar a modo manual con mensaje específico
|
|
1836
|
+
if (classificationError.message.includes('Out of memory') || classificationError.message.includes('no available backend')) {
|
|
1837
|
+
const memoryInfo = navigator.deviceMemory ? `(${navigator.deviceMemory}GB disponible)` : '';
|
|
1838
|
+
this.switchToManualModeWithWarning(`Memoria insuficiente para clasificación automática ${memoryInfo}. Modo manual activado para optimizar rendimiento.`);
|
|
1839
|
+
return;
|
|
1840
|
+
}
|
|
1841
|
+
else {
|
|
1842
|
+
this.switchToManualModeWithError('Error al cargar modelo de clasificación');
|
|
1843
|
+
throw classificationError;
|
|
1844
|
+
}
|
|
1737
1845
|
}
|
|
1738
1846
|
const loadEndTime = performance.now();
|
|
1739
1847
|
const loadTime = loadEndTime - loadStartTime;
|
|
@@ -1744,11 +1852,27 @@ const JaakStamps = class {
|
|
|
1744
1852
|
}
|
|
1745
1853
|
// Paso 2: Detectar y configurar dispositivos
|
|
1746
1854
|
this.updateStatus('Configurando cámara...', 'Buscando dispositivos disponibles', 'loading');
|
|
1747
|
-
|
|
1748
|
-
|
|
1855
|
+
try {
|
|
1856
|
+
await this.cameraService.enumerateDevices();
|
|
1857
|
+
}
|
|
1858
|
+
catch (enumerateError) {
|
|
1859
|
+
throw new Error(`Error al enumerar dispositivos: ${enumerateError.message}`);
|
|
1860
|
+
}
|
|
1861
|
+
try {
|
|
1862
|
+
await this.updateCameraInfoWithAutofocus();
|
|
1863
|
+
}
|
|
1864
|
+
catch (cameraInfoError) {
|
|
1865
|
+
throw new Error(`Error al actualizar información de cámara: ${cameraInfoError.message}`);
|
|
1866
|
+
}
|
|
1749
1867
|
// Paso 3: Configurar cámara seleccionada
|
|
1750
1868
|
this.updateStatus('Ajustando cámara...', 'Configurando calidad de imagen', 'loading');
|
|
1751
|
-
|
|
1869
|
+
let stream;
|
|
1870
|
+
try {
|
|
1871
|
+
stream = await this.cameraService.setupCamera();
|
|
1872
|
+
}
|
|
1873
|
+
catch (setupError) {
|
|
1874
|
+
throw new Error(`Error al configurar cámara: ${setupError.message}`);
|
|
1875
|
+
}
|
|
1752
1876
|
// Paso 4: Inicializar video y mostrar estado de análisis inicial
|
|
1753
1877
|
if (this.useDocumentDetector) {
|
|
1754
1878
|
this.updateStatus('Analizando estabilidad...', 'Evaluando rendimiento del sistema', 'loading');
|
|
@@ -1756,7 +1880,12 @@ const JaakStamps = class {
|
|
|
1756
1880
|
else {
|
|
1757
1881
|
this.updateStatus('Captura activa', 'Posicione su documento y use el botón para capturar', 'active');
|
|
1758
1882
|
}
|
|
1759
|
-
|
|
1883
|
+
try {
|
|
1884
|
+
await this.initializeVideoStream(stream);
|
|
1885
|
+
}
|
|
1886
|
+
catch (videoError) {
|
|
1887
|
+
throw new Error(`Error al inicializar video: ${videoError.message}`);
|
|
1888
|
+
}
|
|
1760
1889
|
// Paso 5: Calibrar máscara
|
|
1761
1890
|
if (this.detectionContainer) {
|
|
1762
1891
|
const container = this.detectionContainer.parentElement;
|
|
@@ -1980,7 +2109,7 @@ const JaakStamps = class {
|
|
|
1980
2109
|
isCapturing: false
|
|
1981
2110
|
};
|
|
1982
2111
|
const cameraInfo = this.cameraInfoWithAutofocus;
|
|
1983
|
-
return (h("div", { key: '
|
|
2112
|
+
return (h("div", { key: '51cc6d0f873691852f938940b131732252b970c1', class: "detector-container" }, h("div", { key: '009480499c0a2833bf9f6bd28003142ca3dd3750', class: "video-container" }, h("video", { key: '88a99a1a90c8d817e40549a255324b2da342797f', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), h("div", { key: '7ede15ccd6f67b3081d907777de7b0d1a1b4cfd6', 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: {
|
|
1984
2113
|
position: 'absolute',
|
|
1985
2114
|
left: `${box.x}px`,
|
|
1986
2115
|
top: `${box.y}px`,
|
|
@@ -1989,9 +2118,9 @@ const JaakStamps = class {
|
|
|
1989
2118
|
border: '2px solid #32406C',
|
|
1990
2119
|
pointerEvents: 'none',
|
|
1991
2120
|
boxSizing: 'border-box'
|
|
1992
|
-
} })))), this.isMaskReady && (h("div", { key: '
|
|
2121
|
+
} })))), this.isMaskReady && (h("div", { key: '63beb4330ab171a5e63237b1d83dcace61422018', class: "overlay-mask" }, h("div", { key: '93cfac6898de6ece6c7dd8f02ba2b79ce6591755', class: "card-outline" }, h("div", { key: '3087d3c51f42ea8d720cea4170dcb68e8bb385e1', class: "side side-top" }), h("div", { key: '992e311b895da161d3b5c49dde346ae378139641', class: "side side-right" }), h("div", { key: '5fb3d7b704f08177b2b9c6e4fbaf685f251a3e53', class: "side side-bottom" }), h("div", { key: '76f6e2cb856632c58809ccdabdf3f7d9a588c9da', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: '142dfc187e07100278e16b19018e4b5fb96d964a', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'bba078ce4c9585631b6a8154f878464b1f779c8b', class: "back-capture-section" }, h("div", { key: 'ec94c9ba2cb373a539f0e6cc3eb356294cebf3ea', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode) && (h("button", { key: '30561e1fc88090c6bb4d0cd7909a33a9525b0ac2', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-back' && (h("span", { key: '4b3e3356507c7f654705425e201d0303d727db72', class: "button-spinner" })), "Capturar Reverso")), h("button", { key: '1abfada41312658eab4966d8fcdb711a6c4762e6', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'skip-back' && (h("span", { key: '3cab3ce751cb38174b6d061170a66ac654a90a38', class: "button-spinner" })), this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
|
|
1993
2122
|
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
1994
|
-
: 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: '
|
|
2123
|
+
: 'Saltar reverso')))), captureState.isVideoActive && (h("div", { key: 'b773fe579cc039fd90ff5e61976752bcf631d16e', class: "camera-controls" }, h("button", { key: '8535463b13cc02e0030d14c1d57390e560572b4f', 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: 'c4b159cf28c24ba2ec0a658bf6f1296c6aba47e3', class: "camera-selector-dropdown" }, h("div", { key: '033273241b77cedc414dee00b70926c3a659910a', class: "camera-selector-header" }, h("span", { key: '83fb4c7ae2387b85134a3ca0c5a156beaf73e481' }, "Seleccionar C\u00E1mara"), h("button", { key: 'f65b6e994603e616af8d69df198c3d8471125695', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), h("div", { key: 'fd90d4c4db1e910c5d05b9ce19a252967c71ad1f', 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}`, camera.hasAutofocus && (h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (h("span", { class: "selected-indicator" }, "\u2713")))))), h("div", { key: '49faa944b3c0c052e18f48e9dda2758cd2c0ae6b', class: "device-info" }, h("small", { key: '15e95207aef60a78b2912a6c00a1b61ab760b72d' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (h("div", { key: 'a67a3795837adcd307fa3666c338376cecae16d0', class: "manual-capture-section" }, h("button", { key: '7f21ccd9b622d97bfce80962038de8be7cd6e33d', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: this.processingButton !== null }, this.processingButton === 'capture-front' && (h("span", { key: 'a4b5e865f373cc0e7787098eedd2d4df413d310f', class: "button-spinner" })), "Capturar Frente"))))), captureState.isCapturing && (h("div", { key: '0b02e81963136dfda62a8980bc5a1f5662509fb8', class: "capture-animation" })), captureState.showFlipAnimation && (h("div", { key: '5eb16e12a7ce16720ca7bdd11aefd902ba772e24', class: "flip-animation" }, h("div", { key: '4c6f3ed33c5080e9e18d17c4594cf394250c3517', class: "id-card-icon" }), h("div", { key: 'd848d7a98540988a8f491bcf8f6f6ad9c5dccfd4', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (h("div", { key: '94863e6d0c404188d548db428af918274d882652', class: "success-animation" }, h("div", { key: 'a90b777e7b7eb533fabec2c15f79a4bd18778f0b', class: "check-icon" }), h("div", { key: '2152e5a3756f58f996c520b58cb1b6cca1763e94', class: "success-text" }, "\u00A1Proceso completado!"))), h("div", { key: 'ae18e06bf291429a74d1b6c8a0c4d37d473f7b30', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (h("div", { key: 'b6b03ed285868d7d3350a2a73e59cb1d65a47401', class: "status-spinner" })), h("div", { key: 'dc85b49dd1cfcddf7300fb3f327d2e1de8ab9bff', class: "status-content" }, h("div", { key: '82461ed0c6d70a0c95ae6b7144ff1d8b8371c6fc', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (h("div", { key: '24aa77ec92ca5a48d1bed4cf98ae591bdbff74f0', class: "status-description" }, this.currentStatus.description)))), this.debug && (h("div", { key: '3b56a0b305ca07407c09a73624a4040cf6625b56', class: "performance-monitor" }, h("div", { key: '52f975da1502f6b08a0b2c828bfd0be8d10e36f8', class: "performance-expanded" }, h("div", { key: 'ea2f444255add0415c7f88cdea2733e1244b17bd', class: "metrics-row" }, h("div", { key: 'e3c2370f1a900594940cb321d5b1661690018025', class: "metric-compact" }, h("span", { key: '25c2f402c9b69f21736c494420e7a396673e9893', class: "metric-label" }, "FPS"), h("span", { key: '505de593f7927544cd874332127e84c72131da72', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), h("div", { key: '5cb1ff4bc1ac33988404e59dac3d01d5a55893b9', class: "metric-compact" }, h("span", { key: 'ce701538abbfe797b288520ab4c277bf7a1d6a05', class: "metric-label" }, "MEM"), h("span", { key: 'efc383e993ad72c20cbfc630e20b2bf9a617a02d', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), h("div", { key: 'b6b6b832740c44d4f78cddf99ba1d139dc3d4739', class: "metrics-row" }, h("div", { key: '3a8903a05aed8adb1626f93bee6ba258fbea9a7d', class: "metric-compact" }, h("span", { key: 'aabc56057156217b3be771ab3b1e92590fa886c5', class: "metric-label" }, "INF"), h("span", { key: '1080df34860cc891cda94c5aacc754cbde18a138', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), h("div", { key: 'ac152093d4c0cc25862aac638fc4693dd0c51a69', class: "metric-compact" }, h("span", { key: 'b23712dbc0b9b8e9cb6e2c659e5af3844ec0ebe7', class: "metric-label" }, "FRAME"), h("span", { key: '461f88519b339fbad6444f009312f72efbc6e450', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), h("div", { key: '8f99afe2c94f37fd3a6feb082cc9aa96f54fc5e1', class: "metrics-row" }, h("div", { key: 'da7ac0fd842f38bbdcac01550764f9fe1bd666a2', class: "metric-compact" }, h("span", { key: 'a5dcd9c8753ba42038f869efa50ae9602cdf6256', class: "metric-label" }, "DET"), h("span", { key: 'e98b91ea98a41637baea1fcfda0bb590cf5d24a0', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), h("div", { key: '3ac54161a712d305a098eae0a3b5d21a731c6019', class: "metric-compact" }, h("span", { key: '3c8cc465433be3b490887457a6c3967dbbda6a7d', class: "metric-label" }, "RATE"), h("span", { key: 'f2e083118fe107c7dc2a675e3f661466cea6d479', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), h("div", { key: '10b6c32b0460e194d680c63b30a078c51a26e9c9', class: "watermark" }, h("img", { key: 'f5954a0ba3f90a642e0d5c6c14d5b549cd193018', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
|
|
1995
2124
|
}
|
|
1996
2125
|
// Utility methods
|
|
1997
2126
|
updateDetectionBoxes(boxes) {
|
|
@@ -2107,9 +2236,24 @@ const JaakStamps = class {
|
|
|
2107
2236
|
}
|
|
2108
2237
|
}
|
|
2109
2238
|
async takeManualScreenshot() {
|
|
2110
|
-
|
|
2239
|
+
console.log('🔵 Botón clicked: Capturar (Frente/Reverso)');
|
|
2240
|
+
// Set processing state immediately
|
|
2241
|
+
const captureState = this.stateManager?.getCaptureState();
|
|
2242
|
+
if (captureState?.step === 'front') {
|
|
2243
|
+
this.processingButton = 'capture-front';
|
|
2244
|
+
}
|
|
2245
|
+
else if (captureState?.step === 'back') {
|
|
2246
|
+
this.processingButton = 'capture-back';
|
|
2247
|
+
}
|
|
2248
|
+
console.log('🔵 processingButton set to:', this.processingButton);
|
|
2249
|
+
// Add small delay to show spinner
|
|
2250
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
2251
|
+
if (!this.videoRef) {
|
|
2252
|
+
this.processingButton = null;
|
|
2111
2253
|
return;
|
|
2254
|
+
}
|
|
2112
2255
|
// When using manual capture, use mask coordinates for cropping
|
|
2256
|
+
// Note: processingButton will be cleared inside takeScreenshotWithMaskCoordinates
|
|
2113
2257
|
await this.takeScreenshotWithMaskCoordinates();
|
|
2114
2258
|
}
|
|
2115
2259
|
async takeScreenshotWithMaskCoordinates() {
|
|
@@ -2185,6 +2329,8 @@ const JaakStamps = class {
|
|
|
2185
2329
|
this.completeProcess(true);
|
|
2186
2330
|
this.returnCanvasToPool(captureCanvas);
|
|
2187
2331
|
this.returnCanvasToPool(croppedCanvas);
|
|
2332
|
+
// Clear processing button when passport is detected
|
|
2333
|
+
this.processingButton = null;
|
|
2188
2334
|
return;
|
|
2189
2335
|
}
|
|
2190
2336
|
}
|
|
@@ -2197,12 +2343,16 @@ const JaakStamps = class {
|
|
|
2197
2343
|
isDetectionPaused: true,
|
|
2198
2344
|
showFlipAnimation: true
|
|
2199
2345
|
});
|
|
2346
|
+
this.triggerRerender();
|
|
2200
2347
|
setTimeout(() => {
|
|
2201
2348
|
this.stateManager.updateCaptureState({
|
|
2202
2349
|
showFlipAnimation: false,
|
|
2203
2350
|
isDetectionPaused: false
|
|
2204
2351
|
});
|
|
2352
|
+
this.triggerRerender();
|
|
2205
2353
|
this.startBackDocumentTimer();
|
|
2354
|
+
// Clear processing button after animation completes
|
|
2355
|
+
this.processingButton = null;
|
|
2206
2356
|
}, 3000);
|
|
2207
2357
|
}
|
|
2208
2358
|
else if (captureState.step === 'back') {
|
|
@@ -2213,6 +2363,8 @@ const JaakStamps = class {
|
|
|
2213
2363
|
}
|
|
2214
2364
|
});
|
|
2215
2365
|
this.completeProcess(false);
|
|
2366
|
+
// Clear processing button after back capture completes
|
|
2367
|
+
this.processingButton = null;
|
|
2216
2368
|
}
|
|
2217
2369
|
// Return canvases to pool after use
|
|
2218
2370
|
this.returnCanvasToPool(captureCanvas);
|
|
@@ -2306,6 +2458,9 @@ const JaakStamps = class {
|
|
|
2306
2458
|
this.stopPerformanceMonitoring();
|
|
2307
2459
|
// Liberar recursos de ONNX
|
|
2308
2460
|
this.releaseOnnxResources();
|
|
2461
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
2462
|
+
this.resetMaskToWhite();
|
|
2463
|
+
this.detectionBoxes = [];
|
|
2309
2464
|
this.hasAutoSwitchedToManual = true;
|
|
2310
2465
|
this.performanceDegradedMode = true;
|
|
2311
2466
|
this.showManualCaptureButton = true;
|
|
@@ -2316,6 +2471,75 @@ const JaakStamps = class {
|
|
|
2316
2471
|
}, 5000);
|
|
2317
2472
|
}
|
|
2318
2473
|
// Método para cambiar a modo manual por errores de ONNX
|
|
2474
|
+
switchToManualModeWithWarning(warningMessage) {
|
|
2475
|
+
// Solo cambiar si el detector está habilitado y no se ha cambiado ya
|
|
2476
|
+
if (!this.useDocumentDetector || this.hasAutoSwitchedToManual) {
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2479
|
+
// No necesitamos liberar recursos ONNX porque no se han cargado aún
|
|
2480
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
2481
|
+
this.resetMaskToWhite();
|
|
2482
|
+
this.detectionBoxes = [];
|
|
2483
|
+
// Cambiar a modo manual
|
|
2484
|
+
this.hasAutoSwitchedToManual = true;
|
|
2485
|
+
this.performanceDegradedMode = true;
|
|
2486
|
+
this.showManualCaptureButton = true;
|
|
2487
|
+
this.useDocumentDetector = false; // Desactivar detector automático
|
|
2488
|
+
// Actualizar el estado con mensaje informativo (no error)
|
|
2489
|
+
this.updateStatus('Modo manual activado', warningMessage, 'active');
|
|
2490
|
+
// Continuar con la configuración de cámara
|
|
2491
|
+
this.continueWithCameraSetup();
|
|
2492
|
+
}
|
|
2493
|
+
async continueWithCameraSetup() {
|
|
2494
|
+
try {
|
|
2495
|
+
// Paso 2: Detectar y configurar dispositivos
|
|
2496
|
+
this.updateStatus('Configurando cámara...', 'Buscando dispositivos disponibles', 'loading');
|
|
2497
|
+
try {
|
|
2498
|
+
await this.cameraService.enumerateDevices();
|
|
2499
|
+
}
|
|
2500
|
+
catch (enumerateError) {
|
|
2501
|
+
throw new Error(`Error al enumerar dispositivos: ${enumerateError.message}`);
|
|
2502
|
+
}
|
|
2503
|
+
try {
|
|
2504
|
+
await this.updateCameraInfoWithAutofocus();
|
|
2505
|
+
}
|
|
2506
|
+
catch (cameraInfoError) {
|
|
2507
|
+
throw new Error(`Error al actualizar información de cámara: ${cameraInfoError.message}`);
|
|
2508
|
+
}
|
|
2509
|
+
// Paso 3: Configurar cámara seleccionada
|
|
2510
|
+
this.updateStatus('Ajustando cámara...', 'Configurando calidad de imagen', 'loading');
|
|
2511
|
+
let stream;
|
|
2512
|
+
try {
|
|
2513
|
+
stream = await this.cameraService.setupCamera();
|
|
2514
|
+
}
|
|
2515
|
+
catch (setupError) {
|
|
2516
|
+
throw new Error(`Error al configurar cámara: ${setupError.message}`);
|
|
2517
|
+
}
|
|
2518
|
+
// Paso 4: Inicializar video
|
|
2519
|
+
this.updateStatus('Captura manual', 'Posicione su documento y use el botón para capturar', 'active');
|
|
2520
|
+
try {
|
|
2521
|
+
await this.initializeVideoStream(stream);
|
|
2522
|
+
}
|
|
2523
|
+
catch (videoError) {
|
|
2524
|
+
throw new Error(`Error al inicializar video: ${videoError.message}`);
|
|
2525
|
+
}
|
|
2526
|
+
// Paso 5: Calibrar máscara
|
|
2527
|
+
if (this.detectionContainer) {
|
|
2528
|
+
const container = this.detectionContainer.parentElement;
|
|
2529
|
+
const rect = container.getBoundingClientRect();
|
|
2530
|
+
this.updateMaskDimensions(rect);
|
|
2531
|
+
}
|
|
2532
|
+
// Finalizar
|
|
2533
|
+
this.startTime = Date.now();
|
|
2534
|
+
this.stateManager.updateCaptureState({ isLoading: false });
|
|
2535
|
+
// Mostrar botón manual (ya debe estar habilitado)
|
|
2536
|
+
this.showManualCaptureButton = true;
|
|
2537
|
+
}
|
|
2538
|
+
catch (error) {
|
|
2539
|
+
this.updateStatus('Error de cámara', error.message, 'error');
|
|
2540
|
+
throw error;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2319
2543
|
switchToManualModeWithError(errorMessage) {
|
|
2320
2544
|
// Solo cambiar si el detector está habilitado y no se ha cambiado ya
|
|
2321
2545
|
if (!this.useDocumentDetector || this.hasAutoSwitchedToManual) {
|
|
@@ -2323,6 +2547,9 @@ const JaakStamps = class {
|
|
|
2323
2547
|
}
|
|
2324
2548
|
// Liberar recursos de ONNX inmediatamente
|
|
2325
2549
|
this.releaseOnnxResources();
|
|
2550
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
2551
|
+
this.resetMaskToWhite();
|
|
2552
|
+
this.detectionBoxes = [];
|
|
2326
2553
|
// Cambiar a modo manual
|
|
2327
2554
|
this.hasAutoSwitchedToManual = true;
|
|
2328
2555
|
this.performanceDegradedMode = true;
|
|
@@ -2573,6 +2800,24 @@ const JaakStamps = class {
|
|
|
2573
2800
|
// Performance is good, use base frame skip
|
|
2574
2801
|
return this.BASE_FRAME_SKIP;
|
|
2575
2802
|
}
|
|
2803
|
+
// Método para resetear la máscara a color blanco
|
|
2804
|
+
resetMaskToWhite() {
|
|
2805
|
+
const cardOutline = this.el.shadowRoot?.querySelector('.card-outline');
|
|
2806
|
+
const corners = this.el.shadowRoot?.querySelectorAll('.corner');
|
|
2807
|
+
const topSide = this.el.shadowRoot?.querySelector('.side-top');
|
|
2808
|
+
const rightSide = this.el.shadowRoot?.querySelector('.side-right');
|
|
2809
|
+
const bottomSide = this.el.shadowRoot?.querySelector('.side-bottom');
|
|
2810
|
+
const leftSide = this.el.shadowRoot?.querySelector('.side-left');
|
|
2811
|
+
// Remover todas las clases de alineación y estado perfecto
|
|
2812
|
+
cardOutline?.classList.remove('perfect-match');
|
|
2813
|
+
corners?.forEach(corner => corner.classList.remove('perfect-match'));
|
|
2814
|
+
topSide?.classList.remove('aligned');
|
|
2815
|
+
rightSide?.classList.remove('aligned');
|
|
2816
|
+
bottomSide?.classList.remove('aligned');
|
|
2817
|
+
leftSide?.classList.remove('aligned');
|
|
2818
|
+
// Resetear estado de alineación
|
|
2819
|
+
this.sideAlignment = { top: false, right: false, bottom: false, left: false };
|
|
2820
|
+
}
|
|
2576
2821
|
// Canvas pool management for screenshots
|
|
2577
2822
|
getPooledCanvas(width, height) {
|
|
2578
2823
|
// Try to find a canvas with matching dimensions
|