@jaak.ai/stamps 2.1.0-dev.2 → 2.1.0-dev.4

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.
@@ -18,7 +18,7 @@ var patchBrowser = () => {
18
18
 
19
19
  patchBrowser().then(async (options) => {
20
20
  await index.globalScripts();
21
- return index.bootstrapLazy([["jaak-stamps.cjs",[[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],"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);
21
+ return index.bootstrapLazy([["jaak-stamps.cjs",[[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);
22
22
  });
23
23
 
24
24
  exports.setNonce = index.setNonce;
@@ -1091,7 +1091,7 @@ class ServiceContainer {
1091
1091
  }
1092
1092
  }
1093
1093
 
1094
- 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)}}.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}}";
1094
+ 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}}";
1095
1095
 
1096
1096
  const JaakStamps = class {
1097
1097
  constructor(hostRef) {
@@ -1147,6 +1147,8 @@ const JaakStamps = class {
1147
1147
  };
1148
1148
  backDocumentTimerRemaining = 0;
1149
1149
  showManualCaptureButton = false;
1150
+ performanceDegradedMode = false; // Auto-switched to manual mode due to performance
1151
+ showPerformanceMessage = false; // Show performance message temporarily
1150
1152
  // Services
1151
1153
  serviceContainer;
1152
1154
  eventBus;
@@ -1170,7 +1172,6 @@ const JaakStamps = class {
1170
1172
  fps: 0,
1171
1173
  inferenceTime: 0,
1172
1174
  memoryUsage: 0,
1173
- cpuUsage: 0,
1174
1175
  onnxLoadTime: 0,
1175
1176
  frameProcessingTime: 0,
1176
1177
  totalDetections: 0,
@@ -1189,6 +1190,12 @@ const JaakStamps = class {
1189
1190
  MIN_INFERENCE_INTERVAL = 50;
1190
1191
  performanceHistory = [];
1191
1192
  PERFORMANCE_HISTORY_SIZE = 10;
1193
+ // Sistema simplificado de monitoreo de rendimiento
1194
+ PERFORMANCE_THRESHOLD_MS = 2000; // Umbral único para todos los frames
1195
+ SLOW_FRAMES_TO_TRIGGER = 2; // Cuántos frames lentos consecutivos antes de cambiar
1196
+ slowFrameCount = 0; // Contador de frames consecutivos lentos
1197
+ processedFramesCount = 0; // Contador total de frames procesados
1198
+ hasAutoSwitchedToManual = false;
1192
1199
  // Canvas pool for optimized screenshot capture
1193
1200
  canvasPool = [];
1194
1201
  MAX_CANVAS_POOL_SIZE = 3;
@@ -1221,14 +1228,8 @@ const JaakStamps = class {
1221
1228
  this.detectionService = this.serviceContainer.getDetectionService();
1222
1229
  }
1223
1230
  async setupEventListeners() {
1224
- this.eventBus.on('state-changed', (data) => {
1225
- this.handleStateChange(data);
1226
- });
1227
- this.eventBus.on('camera-changed', () => {
1228
- // Camera changed event
1229
- });
1230
- this.eventBus.on('error', () => {
1231
- // Handle service errors
1231
+ this.eventBus.on('state-changed', () => {
1232
+ this.handleStateChange();
1232
1233
  });
1233
1234
  }
1234
1235
  async initializeComponent() {
@@ -1335,7 +1336,8 @@ const JaakStamps = class {
1335
1336
  return false;
1336
1337
  }
1337
1338
  }
1338
- handleStateChange(data) {
1339
+ handleStateChange() {
1340
+ // Handle state changes from StateManager if needed
1339
1341
  }
1340
1342
  initializeResizeObserver() {
1341
1343
  if ('ResizeObserver' in window && this.detectionContainer) {
@@ -1356,6 +1358,10 @@ const JaakStamps = class {
1356
1358
  if (step === 'completed') {
1357
1359
  return 'Proceso completado';
1358
1360
  }
1361
+ // Check if we should show performance message
1362
+ if (this.showPerformanceMessage && step === 'front') {
1363
+ return 'Modo manual activado por rendimiento. Use el botón para capturar.';
1364
+ }
1359
1365
  if (step === 'front') {
1360
1366
  // Para el frente, si el detector manual está activo, mostrar instrucciones de captura manual
1361
1367
  if (this.showManualCaptureButton) {
@@ -1585,9 +1591,23 @@ const JaakStamps = class {
1585
1591
  if (this.stateManager) {
1586
1592
  this.stateManager.updateCaptureState({ isLoading: true });
1587
1593
  }
1588
- await this.detectionService.loadModel();
1594
+ try {
1595
+ await this.detectionService.loadModel();
1596
+ }
1597
+ catch (modelError) {
1598
+ console.error('Error cargando modelo de detección:', modelError);
1599
+ this.switchToManualModeWithError('Error al cargar modelo de detección');
1600
+ throw modelError;
1601
+ }
1589
1602
  this.updateStatus('Optimizando detección...', 'Configurando reconocimiento de documentos', 'loading');
1590
- await this.detectionService.loadClassificationModel();
1603
+ try {
1604
+ await this.detectionService.loadClassificationModel();
1605
+ }
1606
+ catch (classificationError) {
1607
+ console.error('Error cargando modelo de clasificación:', classificationError);
1608
+ this.switchToManualModeWithError('Error al cargar modelo de clasificación');
1609
+ throw classificationError;
1610
+ }
1591
1611
  const loadEndTime = performance.now();
1592
1612
  const loadTime = loadEndTime - loadStartTime;
1593
1613
  // Record ONNX load time
@@ -1704,9 +1724,23 @@ const JaakStamps = class {
1704
1724
  const loadStartTime = performance.now();
1705
1725
  this.updateStatus('Preparando reconocimiento...', 'Configurando detección de documentos', 'loading');
1706
1726
  this.stateManager.updateCaptureState({ isLoading: true });
1707
- await this.detectionService.loadModel();
1727
+ try {
1728
+ await this.detectionService.loadModel();
1729
+ }
1730
+ catch (modelError) {
1731
+ console.error('Error cargando modelo de detección:', modelError);
1732
+ this.switchToManualModeWithError('Error al cargar modelo de detección');
1733
+ throw modelError;
1734
+ }
1708
1735
  this.updateStatus('Optimizando detección...', 'Configurando reconocimiento de documentos', 'loading');
1709
- await this.detectionService.loadClassificationModel();
1736
+ try {
1737
+ await this.detectionService.loadClassificationModel();
1738
+ }
1739
+ catch (classificationError) {
1740
+ console.error('Error cargando modelo de clasificación:', classificationError);
1741
+ this.switchToManualModeWithError('Error al cargar modelo de clasificación');
1742
+ throw classificationError;
1743
+ }
1710
1744
  const loadEndTime = performance.now();
1711
1745
  const loadTime = loadEndTime - loadStartTime;
1712
1746
  // Record ONNX load time
@@ -1721,9 +1755,9 @@ const JaakStamps = class {
1721
1755
  // Paso 3: Configurar cámara seleccionada
1722
1756
  this.updateStatus('Ajustando cámara...', 'Configurando calidad de imagen', 'loading');
1723
1757
  const stream = await this.cameraService.setupCamera();
1724
- // Paso 4: Inicializar video y ocultar estado inmediatamente
1758
+ // Paso 4: Inicializar video y mostrar estado de análisis inicial
1725
1759
  if (this.useDocumentDetector) {
1726
- this.updateStatus('Captura activa', 'Buscando documento en el marco de captura', 'active');
1760
+ this.updateStatus('Analizando estabilidad...', 'Evaluando rendimiento del sistema', 'loading');
1727
1761
  }
1728
1762
  else {
1729
1763
  this.updateStatus('Captura activa', 'Posicione su documento y use el botón para capturar', 'active');
@@ -1773,8 +1807,8 @@ const JaakStamps = class {
1773
1807
  const captureState = this.stateManager.getCaptureState();
1774
1808
  if (!this.videoRef || !this.detectionContainer || !this.detectionService.isModelLoaded())
1775
1809
  return;
1776
- // Show manual capture button when document detector is disabled
1777
- if (!this.useDocumentDetector) {
1810
+ // Show manual capture button when document detector is disabled or performance is degraded
1811
+ if (!this.useDocumentDetector || this.performanceDegradedMode) {
1778
1812
  this.showManualCaptureButton = true;
1779
1813
  // Continue the loop for UI updates but skip detection logic
1780
1814
  if (captureState.step !== 'completed') {
@@ -1782,7 +1816,7 @@ const JaakStamps = class {
1782
1816
  }
1783
1817
  return;
1784
1818
  }
1785
- else {
1819
+ else if (!this.performanceDegradedMode) {
1786
1820
  this.showManualCaptureButton = false;
1787
1821
  }
1788
1822
  if (captureState.isDetectionPaused) {
@@ -1812,10 +1846,29 @@ const JaakStamps = class {
1812
1846
  this.lastInferenceTime = currentTime;
1813
1847
  // Measure preprocessing and inference time
1814
1848
  const inferenceStartTime = performance.now();
1815
- const inputTensor = this.detectionService.preprocess(this.videoRef);
1816
- // Standard detection without quality validation
1817
- const detections = await this.detectionService.runInference(inputTensor);
1818
- const inferenceTime = performance.now() - inferenceStartTime;
1849
+ let inputTensor;
1850
+ let detections;
1851
+ let inferenceTime;
1852
+ try {
1853
+ inputTensor = this.detectionService.preprocess(this.videoRef);
1854
+ }
1855
+ catch (preprocessError) {
1856
+ console.error('Error en preprocesamiento:', preprocessError);
1857
+ this.switchToManualModeWithError('Error al procesar imagen');
1858
+ return;
1859
+ }
1860
+ try {
1861
+ // Standard detection without timeout (timeout is handled by frame counting)
1862
+ detections = await this.detectionService.runInference(inputTensor);
1863
+ inferenceTime = performance.now() - inferenceStartTime;
1864
+ }
1865
+ catch (inferenceError) {
1866
+ console.error('Error en inferencia ONNX:', inferenceError);
1867
+ this.switchToManualModeWithError('Error en detección automática');
1868
+ return;
1869
+ }
1870
+ // Increment frame count
1871
+ this.processedFramesCount++;
1819
1872
  // Record ONNX performance metrics
1820
1873
  if (this.debug) {
1821
1874
  this.recordOnnxPerformance(0, inferenceTime);
@@ -1854,9 +1907,30 @@ const JaakStamps = class {
1854
1907
  }
1855
1908
  this.updateMaskColor(detections);
1856
1909
  // Record frame processing metrics
1910
+ const frameEndTime = performance.now();
1911
+ const totalFrameTime = frameEndTime - frameStartTime;
1912
+ // Sistema simplificado: Verificar rendimiento de cada frame (solo si no se ha cambiado a manual)
1913
+ if (this.useDocumentDetector && !this.hasAutoSwitchedToManual) {
1914
+ // Verificar si el frame es lento
1915
+ if (totalFrameTime >= this.PERFORMANCE_THRESHOLD_MS) {
1916
+ this.slowFrameCount++;
1917
+ // Si tenemos suficientes frames lentos consecutivos, cambiar a manual
1918
+ if (this.slowFrameCount >= this.SLOW_FRAMES_TO_TRIGGER) {
1919
+ this.switchToManualMode();
1920
+ }
1921
+ }
1922
+ else {
1923
+ // Frame rápido, reiniciar contador
1924
+ if (this.slowFrameCount > 0) {
1925
+ this.slowFrameCount = 0;
1926
+ }
1927
+ }
1928
+ // Cambiar mensaje de estado después de analizar los primeros 2 frames
1929
+ if (this.processedFramesCount === 2) {
1930
+ this.updateStatus('Captura activa', 'Buscando documento en el marco de captura', 'active');
1931
+ }
1932
+ }
1857
1933
  if (this.debug) {
1858
- const frameEndTime = performance.now();
1859
- const totalFrameTime = frameEndTime - frameStartTime;
1860
1934
  this.recordFrameProcessing(totalFrameTime, detections.length);
1861
1935
  }
1862
1936
  // Continue detection loop
@@ -1892,6 +1966,8 @@ const JaakStamps = class {
1892
1966
  clearTimeout(this.alignmentTimer);
1893
1967
  this.alignmentTimer = undefined;
1894
1968
  }
1969
+ // Liberar recursos de ONNX al limpiar el componente
1970
+ this.releaseOnnxResources();
1895
1971
  if (this.performanceUpdateInterval) {
1896
1972
  clearInterval(this.performanceUpdateInterval);
1897
1973
  this.performanceUpdateInterval = undefined;
@@ -1912,7 +1988,7 @@ const JaakStamps = class {
1912
1988
  isCapturing: false
1913
1989
  };
1914
1990
  const cameraInfo = this.cameraInfoWithAutofocus;
1915
- return (index.h("div", { key: 'e0b32b1b41b58e3a58b552199384080e8f2c069b', class: "detector-container" }, index.h("div", { key: '03c77af311ff12d936994d629d58550cbaae190c', class: "video-container" }, index.h("video", { key: '94f15b34f34367a10d17816a31cd147adb57bc90', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), index.h("div", { key: '982be192792dfaf644eb173bfee9b26ebd229288', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index$1) => (index.h("div", { key: index$1, class: "detection-box", style: {
1991
+ return (index.h("div", { key: '79f84b34f4c6641f0afce6825e9a916c5f1ce1fc', class: "detector-container" }, index.h("div", { key: '1784b74d259071b2c2f879d67bda08cdaf011c76', class: "video-container" }, index.h("video", { key: '48704208b83a9adfd6511266e1848dab8c583b2c', ref: el => this.videoRef = el, autoplay: true, muted: true, playsinline: true, class: this.shouldMirrorVideo ? 'mirror' : '', style: { display: captureState.isVideoActive ? 'block' : 'none' } }), index.h("div", { key: 'b55b96ef64557caee6b0e0c401a96c6b20e3785f', ref: el => this.detectionContainer = el, class: `detection-overlay ${this.shouldMirrorVideo ? 'mirror' : ''}` }, this.debug && this.detectionBoxes.map((box, index$1) => (index.h("div", { key: index$1, class: "detection-box", style: {
1916
1992
  position: 'absolute',
1917
1993
  left: `${box.x}px`,
1918
1994
  top: `${box.y}px`,
@@ -1921,9 +1997,9 @@ const JaakStamps = class {
1921
1997
  border: '2px solid #32406C',
1922
1998
  pointerEvents: 'none',
1923
1999
  boxSizing: 'border-box'
1924
- } })))), this.isMaskReady && (index.h("div", { key: 'f5212ff70db65d2b836a3ac456a1701701630660', class: "overlay-mask" }, index.h("div", { key: '5080217f4962c2c7152def39cc978ba1c40a3a1c', class: "card-outline" }, index.h("div", { key: 'd37f1ca8723d79b10d1c6a3afaf54e2f2657ae79', class: "side side-top" }), index.h("div", { key: 'c5bb4f7d646a991f43598688ffa909c04697bb06', class: "side side-right" }), index.h("div", { key: '4a5040b4a236367dcdf72f4e72d497b8b6dee6c0', class: "side side-bottom" }), index.h("div", { key: 'c74ecef56eee8e92cd9491d693fa89a6c01bdbbd', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: '2a2932b0c03835193ebf86ddb5f13173b1dba367', class: "guide-text" }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: '41fcf2d79106d3ed928fc2842cb6a6725ba4d4f6', class: "back-capture-section" }, index.h("div", { key: '98dbe1bbe454bad42c3e155247f25a9151aaf1f9', class: "back-capture-buttons" }, !this.useDocumentDetector && (index.h("button", { key: '01693bc0d6915a4d02f318268020dfbcf3a70b94', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: captureState.isCapturing }, captureState.isCapturing ? 'Capturando...' : 'Capturar Reverso')), index.h("button", { key: '0a4ba55cbbea867b936a83a16a622a3c36a225f9', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
2000
+ } })))), this.isMaskReady && (index.h("div", { key: 'd398db06f067890474b9ab3fef67fe9712a81948', class: "overlay-mask" }, index.h("div", { key: 'c328eef8a3da4f01aecc2c163b5c3baadee2ab7a', class: "card-outline" }, index.h("div", { key: 'e022c6746096b1b35d4e74295d9872092234fa3e', class: "side side-top" }), index.h("div", { key: '709bd54e7619572b499e8d044ead38e0baab546e', class: "side side-right" }), index.h("div", { key: '330de7072bbb208fad6f10a160c9794438d0dd76', class: "side side-bottom" }), index.h("div", { key: 'a12f18f2c2200ee74809f3bed3ee1218ced498ca', class: "side side-left" })), !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: 'fb049290c464fa7137c174b2a2fcb5f8e1620f5d', class: `guide-text ${this.showPerformanceMessage ? 'performance-warning-text' : ''}` }, this.getGuideText(captureState.step))), captureState.step === 'back' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: '7d027c1dfb1ea855b8d49d5b8934c81be2b73d65', class: "back-capture-section" }, index.h("div", { key: 'cb2f5cbd36d0fa66782a37dc8b00226a35997629', class: "back-capture-buttons" }, (!this.useDocumentDetector || this.performanceDegradedMode) && (index.h("button", { key: '5cee5c2176f23849eb9494505e66e27ca5bbdf6b', class: "capture-button primary-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: captureState.isCapturing }, captureState.isCapturing ? 'Capturando...' : 'Capturar Reverso')), index.h("button", { key: '24b4171ed4a56fad56a61a9daa4529de618a5f94', class: "skip-button", onClick: () => this.skipBackCapture(), type: "button" }, this.enableBackDocumentTimer && this.backDocumentTimerRemaining > 0
1925
2001
  ? `Saltar reverso (${this.backDocumentTimerRemaining}s)`
1926
- : 'Saltar reverso')))), captureState.isVideoActive && (index.h("div", { key: '1db208a53dea37211bdd88254e575142b7abf91f', class: "camera-controls" }, index.h("button", { key: '90755839358f997c3ce2f4c36a8d17d39ea5f8ad', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (index.h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (index.h("div", { key: 'ef7889ab82f9eaabcabec3e3dc3ebb7850818dd4', class: "camera-selector-dropdown" }, index.h("div", { key: 'e28fb005316a742318be3cf8582f520392b71bba', class: "camera-selector-header" }, index.h("span", { key: '97338030b1aedb50c5f5a588ea03c0f19bcb0ddd' }, "Seleccionar C\u00E1mara"), index.h("button", { key: '1537c907dfab17c232a256f9fc9210cbd0125cc6', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), index.h("div", { key: '509178119e6eed5fe0a6ea287904a53bd9fbecbc', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (index.h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, index.h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (index.h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (index.h("span", { class: "selected-indicator" }, "\u2713")))))), index.h("div", { key: '485f7e1a97c43ed280a106bde3c6ee910625025c', class: "device-info" }, index.h("small", { key: 'd76edba943f4e06c14024923496555fa1fe6d845' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: 'c5184dd93aa41cff61b88ea2046b481efc87c1f2', class: "manual-capture-section" }, index.h("button", { key: '6e45d9a0fec60469eb926ff353cb1a440d59f5fe', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: captureState.isCapturing }, captureState.isCapturing ? 'Capturando...' : 'Capturar Frente'))))), captureState.isCapturing && (index.h("div", { key: '9e296a942ba51cc1fd152e76ae406620c84ed721', class: "capture-animation" })), captureState.showFlipAnimation && (index.h("div", { key: '517db50f7273788d94d5e6db6c40f65e00e18784', class: "flip-animation" }, index.h("div", { key: 'fbf6a26c4cc0539bd16b45899d19984af3449610', class: "id-card-icon" }), index.h("div", { key: 'fb3a201864d04531a078074458aa6e7f6580d565', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (index.h("div", { key: '10c694e233d26523d538ff0d2edbf6dcfb8e37c8', class: "success-animation" }, index.h("div", { key: '87e545650825ab805e887667281ecdf8bdb34c45', class: "check-icon" }), index.h("div", { key: '359da71f391d68e9437b749b949ee90685b96b3f', class: "success-text" }, "\u00A1Proceso completado!"))), index.h("div", { key: '7c5533bb875eb3d9cdcc6cfdfc20e4d5bd98d103', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (index.h("div", { key: 'f32df46ab83279387de606eadf53cd4a4009f449', class: "status-spinner" })), index.h("div", { key: 'dd640de5a3b64f5f99363318e2fc70e32ccbc7db', class: "status-content" }, index.h("div", { key: '618c0ab9cb0a24b0af3f6946052beab0d660fe6d', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (index.h("div", { key: 'e52c2a4945c7f5a190a446ac588aa1668c21f26d', class: "status-description" }, this.currentStatus.description)))), this.debug && (index.h("div", { key: '61cea10bc3438fb74aa176d71c4238b070cb0f09', class: "performance-monitor" }, index.h("div", { key: '44f6b1accb56d99a236b22c0769f870638d9c768', class: "performance-expanded" }, index.h("div", { key: '6febc85e319752b0aebc0a4e4050ea6d597375a7', class: "metrics-row" }, index.h("div", { key: '96b81895ad3cd742c96308ed53a2126af76eb619', class: "metric-compact" }, index.h("span", { key: '774a11c6fed6a87db7673b018b3cdc378c5252ef', class: "metric-label" }, "FPS"), index.h("span", { key: 'cb866dcbea661e5f715b82c4dd760f786fd5bb2a', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), index.h("div", { key: 'a935aaadb83ea400bfaa984d1d845bdfd87becc8', class: "metric-compact" }, index.h("span", { key: 'ffacaa2cb7838403a297145b70586e255cc845c7', class: "metric-label" }, "MEM"), index.h("span", { key: 'a1d7a7abec97dc0544d50b11b372f699f750b76f', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), index.h("div", { key: 'bb3d156a46569a8c290bc518c42ec7957bc5b94e', class: "metrics-row" }, index.h("div", { key: '4cadd8f845e4c12120ed549e4a73e02c6cbd9257', class: "metric-compact" }, index.h("span", { key: '1fc5661222f495b79fd7eb126e04f52eecab6fb3', class: "metric-label" }, "INF"), index.h("span", { key: 'eca1f59d1c41ab99158eec81592bc7150bfeabe1', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), index.h("div", { key: 'f708e2757adcb03e633111d96bd6786fb6b80ea6', class: "metric-compact" }, index.h("span", { key: 'a13099ded64180996d6f65bf215483ba83daccbc', class: "metric-label" }, "FRAME"), index.h("span", { key: '2765cd1f7c1a49df9de64639cc1b777c79f89f4c', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), index.h("div", { key: '13aaf85a1b4b66294c4204f02d956b64665aa766', class: "metrics-row" }, index.h("div", { key: '40012f3f646d70c535a606ebbe581a2fe6fd2e50', class: "metric-compact" }, index.h("span", { key: '03f8b17746fe404485820d06a50173678db2fd25', class: "metric-label" }, "DET"), index.h("span", { key: 'c4f87430f142355054d9361330d6a5d508974b70', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), index.h("div", { key: 'cf366a41d7f7cda6046c32cc7c514eb7b46b05d1', class: "metric-compact" }, index.h("span", { key: '925e7de15b96ba4dbbcdbf8a9f0e3173bae49573', class: "metric-label" }, "RATE"), index.h("span", { key: '9701e60c7793f2c205f3c9ffd254b6a115b8a68c', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), index.h("div", { key: '636aeb9b2b8dd992d8a28a8db44b213e12514096', class: "watermark" }, index.h("img", { key: '0407b550d962a6113e05ad75e25a1a1bbd76d9ce', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
2002
+ : 'Saltar reverso')))), captureState.isVideoActive && (index.h("div", { key: 'f0b8bfed998c950e30de0e43662a1965374c6180', class: "camera-controls" }, index.h("button", { key: '7c795a9aa31249f2d42bc45e6d77fba633b7400f', class: `camera-selector-button ${this.isSwitchingCamera ? 'loading' : ''}`, onClick: () => this.toggleCameraSelector(), type: "button", title: "Seleccionar c\u00E1mara", disabled: this.isSwitchingCamera }, this.isSwitchingCamera ? (index.h("div", { class: "button-spinner" })) : ('Cámaras')))), this.showCameraSelector && cameraInfo.availableCameras.length > 0 && (index.h("div", { key: '97ffdf5203e6d7ed1139b7d88088761c1f2adb80', class: "camera-selector-dropdown" }, index.h("div", { key: '0ba533fa51f946abdcc535e07c86f31fd0d1d4bb', class: "camera-selector-header" }, index.h("span", { key: '244b13d266e69326a81228e9b0679fd8264ea91d' }, "Seleccionar C\u00E1mara"), index.h("button", { key: '975c809b348f39bccb6887d710909a58a7222a88', class: "close-selector", onClick: () => this.toggleCameraSelector(), type: "button" }, "\u00D7")), index.h("div", { key: '40df0a7ac0bda961362af72b5a03d448bc4481db', class: "camera-list" }, cameraInfo.availableCameras.map((camera) => (index.h("button", { key: camera.id, class: `camera-option ${cameraInfo.selectedCameraId === camera.id ? 'selected' : ''}`, onClick: () => this.handleCameraSwitch(camera.id), type: "button" }, index.h("span", { class: "camera-label" }, camera.label || `Cámara ${cameraInfo.availableCameras.indexOf(camera) + 1}`, camera.hasAutofocus && (index.h("span", { class: "autofocus-icon", title: "Autofoco disponible" }, "\u29BF"))), cameraInfo.selectedCameraId === camera.id && (index.h("span", { class: "selected-indicator" }, "\u2713")))))), index.h("div", { key: 'ea50280fbc4e96feea026c8ff6dc590ff5e76a59', class: "device-info" }, index.h("small", { key: '19209e350b073e2cc5d3e713c69da863cf98e92e' }, "Dispositivo: ", cameraInfo.deviceType)))), this.showManualCaptureButton && captureState.step === 'front' && !captureState.showFlipAnimation && !captureState.showSuccessAnimation && (index.h("div", { key: '6a91d0c3d72b9bdbf9f0b6d9d33aff440cb3bcb5', class: "manual-capture-section" }, index.h("button", { key: '6474971d1a21f45dfeee90b9c39d5fd7e9f142fa', class: "manual-capture-button", onClick: () => this.takeManualScreenshot(), type: "button", disabled: captureState.isCapturing }, captureState.isCapturing ? 'Capturando...' : 'Capturar Frente'))))), captureState.isCapturing && (index.h("div", { key: '0f2cb967caa746f34f442ed17edbeeeea3be1e2d', class: "capture-animation" })), captureState.showFlipAnimation && (index.h("div", { key: 'a1a6c67d34b27639d4ca6ab3cf790d184aab64bc', class: "flip-animation" }, index.h("div", { key: '4b2d5fe6d18bb77d6515312f53fd189ed2af9db6', class: "id-card-icon" }), index.h("div", { key: '27bd058bd46ecea5ee7bf174a0aa45de519190bf', class: "flip-text" }, "\u00A1Voltea tu identificaci\u00F3n!"))), captureState.showSuccessAnimation && (index.h("div", { key: 'd155e5d2f926c33183f83dabf887bb785d856b14', class: "success-animation" }, index.h("div", { key: 'e57b7c8d6685146ac2215f52a92ff23e3fbd2d97', class: "check-icon" }), index.h("div", { key: '0e3de74b19434f49919b4ef78f91dd89c7a80799', class: "success-text" }, "\u00A1Proceso completado!"))), index.h("div", { key: '8401bf78d349be4900de4e0a23a9fddfafcacc4f', class: `component-status status-${this.currentStatus.type}` }, (this.currentStatus.type === 'loading' || this.currentStatus.type === 'initializing') && (index.h("div", { key: '2b55d22272cd78aa39fd15dd9bdf2317a0737b9f', class: "status-spinner" })), index.h("div", { key: '10dfb478b8803f70c787c9d9412d517de1bcf852', class: "status-content" }, index.h("div", { key: '4cf6feb47ad6c2099219bb73eb0d46e3cbfb2bc3', class: "status-message" }, this.currentStatus.message), this.currentStatus.description && (index.h("div", { key: 'e32df69c147070853977ceae6ec45d8c389e1905', class: "status-description" }, this.currentStatus.description)))), this.debug && (index.h("div", { key: '52a1512ef7b93ecef95cb727c7639661506a7f8d', class: "performance-monitor" }, index.h("div", { key: 'b7dfdeb4453c507338d4156e99a70c8ed8cb5436', class: "performance-expanded" }, index.h("div", { key: '79baa5412635f433400b127353c940d4bd1449c4', class: "metrics-row" }, index.h("div", { key: '12f8d4f530ddea03cbe61bbbf00eb761d55e48b2', class: "metric-compact" }, index.h("span", { key: '3f8d1d37bbb38424ad8def6c2b7f4aa4dfd35876', class: "metric-label" }, "FPS"), index.h("span", { key: '3010d0633a058f703c19776d19c88c753085af01', class: `metric-value ${this.performanceData.fps < 15 ? 'warning' : this.performanceData.fps < 10 ? 'danger' : 'good'}` }, this.performanceData.fps)), index.h("div", { key: 'e5564951b463363ab4965a08f9f8ed37ff202ba2', class: "metric-compact" }, index.h("span", { key: '2b69e25dd1db6f9239c3de12af10a1ce261158c9', class: "metric-label" }, "MEM"), index.h("span", { key: '0e0189eb3f91ed5accc197224c55688ea7e93372', class: `metric-value ${this.performanceData.memoryUsage > 100 ? 'warning' : this.performanceData.memoryUsage > 200 ? 'danger' : 'good'}` }, this.performanceData.memoryUsage, "MB"))), index.h("div", { key: '174c09dbf46186a14d8534a8584c262ba79873fe', class: "metrics-row" }, index.h("div", { key: '7af195560eeacfd310544d607feee9c3f87327b9', class: "metric-compact" }, index.h("span", { key: 'fc8a27ca7484635685acab3b7aa0a0fd4fa9021b', class: "metric-label" }, "INF"), index.h("span", { key: 'bd3ba0e8dd1bf1f21652a986558ccef732572cbc', class: `metric-value ${this.performanceData.inferenceTime > 100 ? 'warning' : this.performanceData.inferenceTime > 200 ? 'danger' : 'good'}` }, this.performanceData.inferenceTime, "ms")), index.h("div", { key: '16109503ddd7bd856d6f82a385bece73f1bacc05', class: "metric-compact" }, index.h("span", { key: '9328438dd8e9c1f0f715f6cfa28baaca27c4244f', class: "metric-label" }, "FRAME"), index.h("span", { key: '8fa3cf73868bc0cbdaaad3cc6bb48b25a809617c', class: `metric-value ${this.performanceData.frameProcessingTime > 50 ? 'warning' : this.performanceData.frameProcessingTime > 100 ? 'danger' : 'good'}` }, this.performanceData.frameProcessingTime, "ms"))), index.h("div", { key: 'dc616be04663364254c38b1f2e96f15ccd52a495', class: "metrics-row" }, index.h("div", { key: '1fa771776e4dc3b0b86c9a195a6d518aa4e7df5f', class: "metric-compact" }, index.h("span", { key: '2f5fb1713ab76b0c84677f9df06f53ac83065cee', class: "metric-label" }, "DET"), index.h("span", { key: 'fd83bda90479a6101593e9b06c7c3fd10da70b67', class: "metric-value good" }, this.performanceData.successfulDetections, "/", this.performanceData.totalDetections)), index.h("div", { key: '7c7f811a14caa371ac08e7945387f58c30039f9f', class: "metric-compact" }, index.h("span", { key: '872b9fa154731d48edf6d08b942bdcea4771fd6c', class: "metric-label" }, "RATE"), index.h("span", { key: '77f9b485a575735159dfbfd846dc2fd2a3dd3413', class: `metric-value ${this.performanceData.detectionRate < 30 ? 'danger' : this.performanceData.detectionRate < 60 ? 'warning' : 'good'}` }, this.performanceData.detectionRate, "%")))))), index.h("div", { key: 'b7ab14e0f956ffb7a6658e6d97a26fe49be94a7f', class: "watermark" }, index.h("img", { key: '3f3807001884966bdf6e1a045d009859f8dcd0f3', src: "https://storage.googleapis.com/jaak-static/commons/powered-by-jaak.png", alt: "Powered by Jaak" })))));
1927
2003
  }
1928
2004
  // Utility methods
1929
2005
  updateDetectionBoxes(boxes) {
@@ -2111,12 +2187,18 @@ const JaakStamps = class {
2111
2187
  });
2112
2188
  // Check if document classification is enabled (independent of detector)
2113
2189
  if (this.useDocumentClassification) {
2114
- const classification = await this.detectionService.classifyDocument(croppedCanvas);
2115
- if (classification && classification.class === 'passport') {
2116
- this.completeProcess(true);
2117
- this.returnCanvasToPool(captureCanvas);
2118
- this.returnCanvasToPool(croppedCanvas);
2119
- return;
2190
+ try {
2191
+ const classification = await this.detectionService.classifyDocument(croppedCanvas);
2192
+ if (classification && classification.class === 'passport') {
2193
+ this.completeProcess(true);
2194
+ this.returnCanvasToPool(captureCanvas);
2195
+ this.returnCanvasToPool(croppedCanvas);
2196
+ return;
2197
+ }
2198
+ }
2199
+ catch (classifyError) {
2200
+ console.error('Error clasificando documento:', classifyError);
2201
+ // No cambiar a manual aquí, solo registrar el error y continuar
2120
2202
  }
2121
2203
  }
2122
2204
  this.stateManager.updateCaptureState({
@@ -2178,10 +2260,16 @@ const JaakStamps = class {
2178
2260
  });
2179
2261
  // Check if document classification is enabled
2180
2262
  if (this.useDocumentClassification) {
2181
- const classification = await this.detectionService.classifyDocument(croppedCanvas);
2182
- if (classification && classification.class === 'passport') {
2183
- this.completeProcess(true);
2184
- return;
2263
+ try {
2264
+ const classification = await this.detectionService.classifyDocument(croppedCanvas);
2265
+ if (classification && classification.class === 'passport') {
2266
+ this.completeProcess(true);
2267
+ return;
2268
+ }
2269
+ }
2270
+ catch (classifyError) {
2271
+ console.error('Error clasificando documento:', classifyError);
2272
+ // No cambiar a manual aquí, solo registrar el error y continuar
2185
2273
  }
2186
2274
  }
2187
2275
  this.stateManager.updateCaptureState({
@@ -2218,6 +2306,64 @@ const JaakStamps = class {
2218
2306
  cardOutline?.classList.remove('capturing');
2219
2307
  }, 600);
2220
2308
  }
2309
+ // Método simplificado para cambio a modo manual
2310
+ switchToManualMode() {
2311
+ // Only switch if detector is enabled and not already switched
2312
+ if (!this.useDocumentDetector || this.hasAutoSwitchedToManual) {
2313
+ return;
2314
+ }
2315
+ // Detener todo el monitoreo de performance
2316
+ this.stopPerformanceMonitoring();
2317
+ // Liberar recursos de ONNX
2318
+ this.releaseOnnxResources();
2319
+ this.hasAutoSwitchedToManual = true;
2320
+ this.performanceDegradedMode = true;
2321
+ this.showManualCaptureButton = true;
2322
+ this.showPerformanceMessage = true;
2323
+ // Hide performance message after 5 seconds
2324
+ setTimeout(() => {
2325
+ this.showPerformanceMessage = false;
2326
+ }, 5000);
2327
+ }
2328
+ // Método para cambiar a modo manual por errores de ONNX
2329
+ switchToManualModeWithError(errorMessage) {
2330
+ console.error(`[ONNX Error] ${errorMessage}`);
2331
+ // Solo cambiar si el detector está habilitado y no se ha cambiado ya
2332
+ if (!this.useDocumentDetector || this.hasAutoSwitchedToManual) {
2333
+ return;
2334
+ }
2335
+ // Liberar recursos de ONNX inmediatamente
2336
+ this.releaseOnnxResources();
2337
+ // Cambiar a modo manual
2338
+ this.hasAutoSwitchedToManual = true;
2339
+ this.performanceDegradedMode = true;
2340
+ this.showManualCaptureButton = true;
2341
+ this.useDocumentDetector = false; // Desactivar detector automático
2342
+ // Actualizar el estado con mensaje de error
2343
+ this.updateStatus('Modo manual activado', errorMessage, 'error');
2344
+ // Ocultar mensaje después de 5 segundos
2345
+ setTimeout(() => {
2346
+ this.updateStatus('Captura manual', 'Use el botón para capturar', 'ready');
2347
+ }, 5000);
2348
+ }
2349
+ stopPerformanceMonitoring() {
2350
+ // Nota: No necesitamos limpiar más variables porque ya no se usarán
2351
+ // El sistema automáticamente saltará la lógica de performance una vez que hasAutoSwitchedToManual = true
2352
+ }
2353
+ // Método para liberar recursos de ONNX cuando se cambia a modo manual
2354
+ releaseOnnxResources() {
2355
+ console.log('[ONNX] Liberando recursos de modelos ONNX...');
2356
+ try {
2357
+ // Liberar recursos del servicio de detección
2358
+ if (this.detectionService) {
2359
+ this.detectionService.cleanup();
2360
+ console.log('[ONNX] Recursos de ONNX liberados exitosamente');
2361
+ }
2362
+ }
2363
+ catch (error) {
2364
+ console.error('[ONNX] Error al liberar recursos:', error);
2365
+ }
2366
+ }
2221
2367
  completeProcess(skippedBack = false) {
2222
2368
  this.stateManager.updateCaptureState({
2223
2369
  step: 'completed',
@@ -2331,6 +2477,13 @@ const JaakStamps = class {
2331
2477
  this.detectionBoxes = [];
2332
2478
  this.alignmentStartTime = undefined;
2333
2479
  this.hasDocumentDetected = false;
2480
+ // Reset sistema simplificado
2481
+ this.processedFramesCount = 0;
2482
+ this.slowFrameCount = 0;
2483
+ // Reset performance degradation state
2484
+ this.hasAutoSwitchedToManual = false;
2485
+ this.performanceDegradedMode = false;
2486
+ this.showPerformanceMessage = false;
2334
2487
  if (this.alignmentTimer) {
2335
2488
  clearTimeout(this.alignmentTimer);
2336
2489
  this.alignmentTimer = undefined;