@jaak.ai/stamps 2.1.0-dev.6 → 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 +264 -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 +233 -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 +265 -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 +264 -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 +5 -0
- package/package.json +1 -1
- package/dist/jaak-stamps-webcomponent/p-d05dc382.entry.js +0 -2
- package/dist/jaak-stamps-webcomponent/p-d05dc382.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],"captureStateVersion":[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) {
|
|
@@ -1148,6 +1176,7 @@ const JaakStamps = class {
|
|
|
1148
1176
|
performanceDegradedMode = false; // Auto-switched to manual mode due to performance
|
|
1149
1177
|
showPerformanceMessage = false; // Show performance message temporarily
|
|
1150
1178
|
captureStateVersion = 0; // Triggers re-render when StateManager changes
|
|
1179
|
+
processingButton = null; // Track which button is processing
|
|
1151
1180
|
// Services
|
|
1152
1181
|
serviceContainer;
|
|
1153
1182
|
eventBus;
|
|
@@ -1199,14 +1228,19 @@ const JaakStamps = class {
|
|
|
1199
1228
|
canvasPool = [];
|
|
1200
1229
|
MAX_CANVAS_POOL_SIZE = 3;
|
|
1201
1230
|
async componentDidLoad() {
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
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');
|
|
1210
1244
|
}
|
|
1211
1245
|
}
|
|
1212
1246
|
async initializeServices() {
|
|
@@ -1521,8 +1555,14 @@ const JaakStamps = class {
|
|
|
1521
1555
|
}
|
|
1522
1556
|
}
|
|
1523
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));
|
|
1524
1563
|
const readyCheck = this.isComponentReady();
|
|
1525
1564
|
if (!readyCheck.ready) {
|
|
1565
|
+
this.processingButton = null;
|
|
1526
1566
|
return { success: false, error: readyCheck.message };
|
|
1527
1567
|
}
|
|
1528
1568
|
try {
|
|
@@ -1539,6 +1579,10 @@ const JaakStamps = class {
|
|
|
1539
1579
|
catch (error) {
|
|
1540
1580
|
return { success: false, error: error.message };
|
|
1541
1581
|
}
|
|
1582
|
+
finally {
|
|
1583
|
+
// Always clear processing state when done
|
|
1584
|
+
this.processingButton = null;
|
|
1585
|
+
}
|
|
1542
1586
|
}
|
|
1543
1587
|
async getStatus() {
|
|
1544
1588
|
const readyCheck = this.isComponentReady();
|
|
@@ -1716,9 +1760,53 @@ const JaakStamps = class {
|
|
|
1716
1760
|
// Always allow getting capture delay, even during initialization
|
|
1717
1761
|
return this.captureDelay;
|
|
1718
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
|
+
}
|
|
1719
1800
|
// DETECTION METHODS
|
|
1720
1801
|
async startDetection() {
|
|
1721
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
|
+
}
|
|
1722
1810
|
// Paso 1: Verificar y cargar modelos si es necesario
|
|
1723
1811
|
if (!this.detectionService.isModelLoaded()) {
|
|
1724
1812
|
const loadStartTime = performance.now();
|
|
@@ -1728,16 +1816,32 @@ const JaakStamps = class {
|
|
|
1728
1816
|
await this.detectionService.loadModel();
|
|
1729
1817
|
}
|
|
1730
1818
|
catch (modelError) {
|
|
1731
|
-
|
|
1732
|
-
|
|
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
|
+
}
|
|
1733
1829
|
}
|
|
1734
1830
|
this.updateStatus('Optimizando detección...', 'Configurando reconocimiento de documentos', 'loading');
|
|
1735
1831
|
try {
|
|
1736
1832
|
await this.detectionService.loadClassificationModel();
|
|
1737
1833
|
}
|
|
1738
1834
|
catch (classificationError) {
|
|
1739
|
-
|
|
1740
|
-
|
|
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
|
+
}
|
|
1741
1845
|
}
|
|
1742
1846
|
const loadEndTime = performance.now();
|
|
1743
1847
|
const loadTime = loadEndTime - loadStartTime;
|
|
@@ -1748,11 +1852,27 @@ const JaakStamps = class {
|
|
|
1748
1852
|
}
|
|
1749
1853
|
// Paso 2: Detectar y configurar dispositivos
|
|
1750
1854
|
this.updateStatus('Configurando cámara...', 'Buscando dispositivos disponibles', 'loading');
|
|
1751
|
-
|
|
1752
|
-
|
|
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
|
+
}
|
|
1753
1867
|
// Paso 3: Configurar cámara seleccionada
|
|
1754
1868
|
this.updateStatus('Ajustando cámara...', 'Configurando calidad de imagen', 'loading');
|
|
1755
|
-
|
|
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
|
+
}
|
|
1756
1876
|
// Paso 4: Inicializar video y mostrar estado de análisis inicial
|
|
1757
1877
|
if (this.useDocumentDetector) {
|
|
1758
1878
|
this.updateStatus('Analizando estabilidad...', 'Evaluando rendimiento del sistema', 'loading');
|
|
@@ -1760,7 +1880,12 @@ const JaakStamps = class {
|
|
|
1760
1880
|
else {
|
|
1761
1881
|
this.updateStatus('Captura activa', 'Posicione su documento y use el botón para capturar', 'active');
|
|
1762
1882
|
}
|
|
1763
|
-
|
|
1883
|
+
try {
|
|
1884
|
+
await this.initializeVideoStream(stream);
|
|
1885
|
+
}
|
|
1886
|
+
catch (videoError) {
|
|
1887
|
+
throw new Error(`Error al inicializar video: ${videoError.message}`);
|
|
1888
|
+
}
|
|
1764
1889
|
// Paso 5: Calibrar máscara
|
|
1765
1890
|
if (this.detectionContainer) {
|
|
1766
1891
|
const container = this.detectionContainer.parentElement;
|
|
@@ -1984,7 +2109,7 @@ const JaakStamps = class {
|
|
|
1984
2109
|
isCapturing: false
|
|
1985
2110
|
};
|
|
1986
2111
|
const cameraInfo = this.cameraInfoWithAutofocus;
|
|
1987
|
-
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: {
|
|
1988
2113
|
position: 'absolute',
|
|
1989
2114
|
left: `${box.x}px`,
|
|
1990
2115
|
top: `${box.y}px`,
|
|
@@ -1993,9 +2118,9 @@ const JaakStamps = class {
|
|
|
1993
2118
|
border: '2px solid #32406C',
|
|
1994
2119
|
pointerEvents: 'none',
|
|
1995
2120
|
boxSizing: 'border-box'
|
|
1996
|
-
} })))), 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
|
|
1997
2122
|
? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
|
|
1998
|
-
: '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" })))));
|
|
1999
2124
|
}
|
|
2000
2125
|
// Utility methods
|
|
2001
2126
|
updateDetectionBoxes(boxes) {
|
|
@@ -2111,9 +2236,24 @@ const JaakStamps = class {
|
|
|
2111
2236
|
}
|
|
2112
2237
|
}
|
|
2113
2238
|
async takeManualScreenshot() {
|
|
2114
|
-
|
|
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;
|
|
2115
2253
|
return;
|
|
2254
|
+
}
|
|
2116
2255
|
// When using manual capture, use mask coordinates for cropping
|
|
2256
|
+
// Note: processingButton will be cleared inside takeScreenshotWithMaskCoordinates
|
|
2117
2257
|
await this.takeScreenshotWithMaskCoordinates();
|
|
2118
2258
|
}
|
|
2119
2259
|
async takeScreenshotWithMaskCoordinates() {
|
|
@@ -2189,6 +2329,8 @@ const JaakStamps = class {
|
|
|
2189
2329
|
this.completeProcess(true);
|
|
2190
2330
|
this.returnCanvasToPool(captureCanvas);
|
|
2191
2331
|
this.returnCanvasToPool(croppedCanvas);
|
|
2332
|
+
// Clear processing button when passport is detected
|
|
2333
|
+
this.processingButton = null;
|
|
2192
2334
|
return;
|
|
2193
2335
|
}
|
|
2194
2336
|
}
|
|
@@ -2209,6 +2351,8 @@ const JaakStamps = class {
|
|
|
2209
2351
|
});
|
|
2210
2352
|
this.triggerRerender();
|
|
2211
2353
|
this.startBackDocumentTimer();
|
|
2354
|
+
// Clear processing button after animation completes
|
|
2355
|
+
this.processingButton = null;
|
|
2212
2356
|
}, 3000);
|
|
2213
2357
|
}
|
|
2214
2358
|
else if (captureState.step === 'back') {
|
|
@@ -2219,6 +2363,8 @@ const JaakStamps = class {
|
|
|
2219
2363
|
}
|
|
2220
2364
|
});
|
|
2221
2365
|
this.completeProcess(false);
|
|
2366
|
+
// Clear processing button after back capture completes
|
|
2367
|
+
this.processingButton = null;
|
|
2222
2368
|
}
|
|
2223
2369
|
// Return canvases to pool after use
|
|
2224
2370
|
this.returnCanvasToPool(captureCanvas);
|
|
@@ -2312,6 +2458,9 @@ const JaakStamps = class {
|
|
|
2312
2458
|
this.stopPerformanceMonitoring();
|
|
2313
2459
|
// Liberar recursos de ONNX
|
|
2314
2460
|
this.releaseOnnxResources();
|
|
2461
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
2462
|
+
this.resetMaskToWhite();
|
|
2463
|
+
this.detectionBoxes = [];
|
|
2315
2464
|
this.hasAutoSwitchedToManual = true;
|
|
2316
2465
|
this.performanceDegradedMode = true;
|
|
2317
2466
|
this.showManualCaptureButton = true;
|
|
@@ -2322,6 +2471,75 @@ const JaakStamps = class {
|
|
|
2322
2471
|
}, 5000);
|
|
2323
2472
|
}
|
|
2324
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
|
+
}
|
|
2325
2543
|
switchToManualModeWithError(errorMessage) {
|
|
2326
2544
|
// Solo cambiar si el detector está habilitado y no se ha cambiado ya
|
|
2327
2545
|
if (!this.useDocumentDetector || this.hasAutoSwitchedToManual) {
|
|
@@ -2329,6 +2547,9 @@ const JaakStamps = class {
|
|
|
2329
2547
|
}
|
|
2330
2548
|
// Liberar recursos de ONNX inmediatamente
|
|
2331
2549
|
this.releaseOnnxResources();
|
|
2550
|
+
// Resetear máscara a blanco y limpiar detecciones
|
|
2551
|
+
this.resetMaskToWhite();
|
|
2552
|
+
this.detectionBoxes = [];
|
|
2332
2553
|
// Cambiar a modo manual
|
|
2333
2554
|
this.hasAutoSwitchedToManual = true;
|
|
2334
2555
|
this.performanceDegradedMode = true;
|
|
@@ -2579,6 +2800,24 @@ const JaakStamps = class {
|
|
|
2579
2800
|
// Performance is good, use base frame skip
|
|
2580
2801
|
return this.BASE_FRAME_SKIP;
|
|
2581
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
|
+
}
|
|
2582
2821
|
// Canvas pool management for screenshots
|
|
2583
2822
|
getPooledCanvas(width, height) {
|
|
2584
2823
|
// Try to find a canvas with matching dimensions
|