Spaces:
Running
Running
| window.Results = { | |
| currentImageUrl: null, | |
| render: function (result, file) { | |
| this._hideAll(); | |
| Utils.$('#results-data').classList.remove('hidden'); | |
| if (file) { | |
| this.showImagePreview(file); | |
| } | |
| this.renderOverallResult(result); | |
| this.renderExtractionInfo(result); | |
| this.renderFields(result); | |
| this.renderChecks(result.checks || {}); | |
| this.renderConfidence(result.confidence || {}, result.doc_type); | |
| this.renderRawText(result.raw_text || []); | |
| this.renderMachineData(result); | |
| }, | |
| showImagePreview: function (file) { | |
| if (this.currentImageUrl) { | |
| URL.revokeObjectURL(this.currentImageUrl); | |
| } | |
| var container = Utils.$('#image-preview-container'); | |
| container.classList.remove('hidden'); | |
| this.currentImageUrl = URL.createObjectURL(file); | |
| Utils.$('#image-preview').src = this.currentImageUrl; | |
| }, | |
| hideImagePreview: function () { | |
| Utils.$('#image-preview-container').classList.add('hidden'); | |
| }, | |
| renderOverallResult: function (result) { | |
| var banner = Utils.$('#overall-result-banner'); | |
| var overall = result.overall_result || 'unknown'; | |
| banner.className = 'overall-result-banner result-' + overall; | |
| var icon = overall === 'pass' ? '✓' : overall === 'fail' ? '✗' : '⚠'; | |
| var label = overall === 'pass' ? 'PASS' : overall === 'fail' ? 'FAIL' : 'INCONCLUSIVE'; | |
| banner.innerHTML = '<span class="result-icon">' + icon + '</span> ' + label; | |
| }, | |
| renderExtractionInfo: function (result) { | |
| var el = Utils.$('#extraction-info'); | |
| var parts = []; | |
| if (result.doc_type) { | |
| parts.push('<span class="info-tag">' + Utils.docTypeLabel(result.doc_type) + '</span>'); | |
| } | |
| if (result.extraction_method) { | |
| parts.push('<span class="info-tag method">' + result.extraction_method + '</span>'); | |
| } | |
| el.innerHTML = parts.join(' '); | |
| }, | |
| renderFields: function (result) { | |
| var tbody = Utils.$('#fields-table tbody'); | |
| tbody.innerHTML = ''; | |
| var fields = result.fields || {}; | |
| var fieldOrder = Utils.fieldsForDocType(result.doc_type); | |
| for (var i = 0; i < fieldOrder.length; i++) { | |
| var key = fieldOrder[i]; | |
| var value = fields[key]; | |
| var tr = document.createElement('tr'); | |
| var tdLabel = document.createElement('td'); | |
| tdLabel.textContent = Utils.fieldLabel(key); | |
| var tdValue = document.createElement('td'); | |
| if (value) { | |
| tdValue.textContent = value; | |
| } else { | |
| tdValue.textContent = 'Not detected'; | |
| tdValue.className = 'field-missing'; | |
| } | |
| tr.appendChild(tdLabel); | |
| tr.appendChild(tdValue); | |
| tbody.appendChild(tr); | |
| } | |
| }, | |
| renderChecks: function (checks) { | |
| var section = Utils.$('#checks-section'); | |
| section.innerHTML = ''; | |
| var checkOrder = ['image_quality', 'id_number_valid', 'barcode_valid', 'mrz_valid', 'data_crosscheck', 'dob_crosscheck', 'gender_crosscheck']; | |
| for (var i = 0; i < checkOrder.length; i++) { | |
| var key = checkOrder[i]; | |
| var val = checks[key]; | |
| if (val === undefined) continue; | |
| var span = document.createElement('span'); | |
| if (val === 'passed') { | |
| span.className = 'validation-check pass'; | |
| span.innerHTML = '✓ ' + Utils.checkLabel(key); | |
| } else if (val === 'failed') { | |
| span.className = 'validation-check fail'; | |
| span.innerHTML = '✗ ' + Utils.checkLabel(key); | |
| } else { | |
| span.className = 'validation-check na'; | |
| span.innerHTML = '— ' + Utils.checkLabel(key); | |
| } | |
| section.appendChild(span); | |
| } | |
| }, | |
| renderConfidence: function (confidence, docType) { | |
| var section = Utils.$('#confidence-section'); | |
| section.innerHTML = ''; | |
| var fieldOrder = Utils.fieldsForDocType(docType); | |
| for (var i = 0; i < fieldOrder.length; i++) { | |
| var key = fieldOrder[i]; | |
| var val = confidence[key]; | |
| if (val === undefined || val === null) continue; | |
| var row = document.createElement('div'); | |
| row.className = 'confidence-row'; | |
| var label = document.createElement('span'); | |
| label.className = 'confidence-label'; | |
| label.textContent = Utils.fieldLabel(key); | |
| var bar = document.createElement('div'); | |
| bar.className = 'confidence-bar'; | |
| var fill = document.createElement('div'); | |
| fill.className = 'confidence-fill ' + Utils.confidenceLevel(val); | |
| fill.style.width = Utils.formatConfidence(val); | |
| fill.textContent = Utils.formatConfidence(val); | |
| bar.appendChild(fill); | |
| row.appendChild(label); | |
| row.appendChild(bar); | |
| section.appendChild(row); | |
| } | |
| }, | |
| renderRawText: function (rawText) { | |
| var content = Utils.$('#raw-text-content'); | |
| content.innerHTML = ''; | |
| for (var i = 0; i < rawText.length; i++) { | |
| var line = document.createElement('div'); | |
| line.textContent = rawText[i]; | |
| content.appendChild(line); | |
| } | |
| }, | |
| renderMachineData: function (result) { | |
| var section = Utils.$('#machine-data-section'); | |
| var content = Utils.$('#machine-data-content'); | |
| content.innerHTML = ''; | |
| var data = result.barcode_data || result.mrz_data; | |
| if (!data) { | |
| section.classList.add('hidden'); | |
| return; | |
| } | |
| section.classList.remove('hidden'); | |
| var label = result.barcode_data ? 'Barcode Data' : 'MRZ Data'; | |
| Utils.$('#machine-data-section summary').textContent = label; | |
| var pre = document.createElement('pre'); | |
| pre.textContent = JSON.stringify(data, null, 2); | |
| content.appendChild(pre); | |
| }, | |
| showLoading: function (file) { | |
| this._hideAll(); | |
| if (file) { | |
| this.showImagePreview(file); | |
| } | |
| Utils.$('#results-loading').classList.remove('hidden'); | |
| this._startTimer(); | |
| }, | |
| hideLoading: function () { | |
| Utils.$('#results-loading').classList.add('hidden'); | |
| this._stopTimer(); | |
| }, | |
| showEmpty: function () { | |
| this._hideAll(); | |
| Utils.$('#results-empty').classList.remove('hidden'); | |
| }, | |
| showError: function (message) { | |
| this._hideAll(); | |
| Utils.$('#results-error').classList.remove('hidden'); | |
| Utils.$('#error-message').textContent = message; | |
| }, | |
| renderSerial: function (result, file) { | |
| this._hideAll(); | |
| Utils.$('#serial-results').classList.remove('hidden'); | |
| if (file) this.showImagePreview(file); | |
| // Banner | |
| var banner = Utils.$('#serial-result-banner'); | |
| var hasSerial = !!result.serial_number; | |
| banner.className = 'overall-result-banner ' + (hasSerial ? 'result-pass' : 'result-fail'); | |
| banner.innerHTML = hasSerial | |
| ? '<span class="result-icon">✓</span> SERIAL NUMBER FOUND' | |
| : '<span class="result-icon">✗</span> ' + (result.failure_reason || 'NO SERIAL NUMBER DETECTED'); | |
| // Failure guidance | |
| var failGuidance = Utils.$('#serial-fail-guidance'); | |
| if (!hasSerial) { | |
| failGuidance.classList.remove('hidden'); | |
| failGuidance.innerHTML = ''; | |
| var tips = []; | |
| if (result.quality && result.quality.issues && result.quality.issues.length > 0) { | |
| for (var q = 0; q < result.quality.issues.length; q++) { | |
| tips.push(result.quality.issues[q]); | |
| } | |
| } | |
| if (result.quality && !result.quality.usable) { | |
| tips.push('Image quality is too low for reliable extraction'); | |
| } | |
| if (tips.length === 0) { | |
| tips.push('Try better lighting, hold the label steady, or move closer'); | |
| } | |
| var ul = document.createElement('ul'); | |
| for (var t = 0; t < tips.length; t++) { | |
| var li = document.createElement('li'); | |
| li.textContent = tips[t]; | |
| ul.appendChild(li); | |
| } | |
| failGuidance.appendChild(ul); | |
| } else { | |
| failGuidance.classList.add('hidden'); | |
| failGuidance.innerHTML = ''; | |
| } | |
| // Cropped image preview | |
| var cropContainer = Utils.$('#serial-crop-container'); | |
| if (result.cropped_image) { | |
| cropContainer.classList.remove('hidden'); | |
| Utils.$('#serial-crop-preview').src = 'data:image/jpeg;base64,' + result.cropped_image; | |
| } else { | |
| cropContainer.classList.add('hidden'); | |
| } | |
| // Fields table | |
| var tbody = Utils.$('#serial-fields-table tbody'); | |
| tbody.innerHTML = ''; | |
| var confidenceClass = ''; | |
| if (result.confidence === 'high') confidenceClass = 'confidence-high'; | |
| else if (result.confidence === 'medium') confidenceClass = 'confidence-medium'; | |
| else if (result.confidence === 'low') confidenceClass = 'confidence-low'; | |
| var rows = [ | |
| ['Serial Number', result.serial_number || 'Not detected', !result.serial_number ? 'field-missing' : ''], | |
| ['Extraction Source', result.extraction_source || '-', ''], | |
| ['Confidence', result.confidence || '-', confidenceClass], | |
| ]; | |
| for (var i = 0; i < rows.length; i++) { | |
| var tr = document.createElement('tr'); | |
| var tdLabel = document.createElement('td'); | |
| tdLabel.textContent = rows[i][0]; | |
| var tdValue = document.createElement('td'); | |
| tdValue.textContent = rows[i][1]; | |
| if (rows[i][2]) tdValue.className = rows[i][2]; | |
| tr.appendChild(tdLabel); | |
| tr.appendChild(tdValue); | |
| tbody.appendChild(tr); | |
| } | |
| // Validation details (styled pills instead of raw JSON) | |
| var valContent = Utils.$('#serial-validation-content'); | |
| valContent.innerHTML = ''; | |
| if (result.validation) { | |
| var validPill = document.createElement('span'); | |
| validPill.className = 'validation-pill ' + (result.validation.valid ? 'pill-pass' : 'pill-fail'); | |
| validPill.textContent = result.validation.valid ? 'Valid' : 'Invalid'; | |
| valContent.appendChild(validPill); | |
| if (result.validation.prefix_match) { | |
| var prefixPill = document.createElement('span'); | |
| prefixPill.className = 'validation-pill pill-info'; | |
| prefixPill.textContent = result.validation.prefix_match; | |
| valContent.appendChild(prefixPill); | |
| } | |
| if (result.validation.issues && result.validation.issues.length > 0) { | |
| for (var j = 0; j < result.validation.issues.length; j++) { | |
| var issuePill = document.createElement('span'); | |
| issuePill.className = 'validation-pill pill-warn'; | |
| issuePill.textContent = result.validation.issues[j]; | |
| valContent.appendChild(issuePill); | |
| } | |
| } | |
| } else { | |
| valContent.textContent = 'No validation data'; | |
| } | |
| }, | |
| _hideAll: function () { | |
| Utils.$('#results-empty').classList.add('hidden'); | |
| Utils.$('#results-loading').classList.add('hidden'); | |
| Utils.$('#results-data').classList.add('hidden'); | |
| Utils.$('#serial-results').classList.add('hidden'); | |
| Utils.$('#results-error').classList.add('hidden'); | |
| Utils.$('#image-preview-container').classList.add('hidden'); | |
| this._stopTimer(); | |
| }, | |
| _timerInterval: null, | |
| _timerStart: 0, | |
| _startTimer: function () { | |
| this._timerStart = performance.now(); | |
| var el = Utils.$('#elapsed-timer'); | |
| var self = this; | |
| el.textContent = 'Elapsed: 0s'; | |
| this._timerInterval = setInterval(function () { | |
| var secs = Math.floor((performance.now() - self._timerStart) / 1000); | |
| el.textContent = 'Elapsed: ' + secs + 's'; | |
| }, 1000); | |
| }, | |
| _stopTimer: function () { | |
| if (this._timerInterval) { | |
| clearInterval(this._timerInterval); | |
| this._timerInterval = null; | |
| } | |
| }, | |
| }; | |