Spaces:
Sleeping
Sleeping
| // Initialize Lucide icons | |
| lucide.createIcons(); | |
| // Global variables | |
| let uploadedImageData = null; | |
| let uploadedMetadata = null; | |
| let currentThreshold = 0.5; | |
| let showGradCAM = false; | |
| // DOM elements | |
| const fileInput = document.getElementById('fileInput'); | |
| const metadataInput = document.getElementById('metadataInput'); | |
| const uploadArea = document.getElementById('uploadArea'); | |
| const uploadContent = document.getElementById('uploadContent'); | |
| const uploadedContent = document.getElementById('uploadedContent'); | |
| const uploadedImage = document.getElementById('uploadedImage'); | |
| const metadataStatus = document.getElementById('metadataStatus'); | |
| const analyzeBtn = document.getElementById('analyzeBtn'); | |
| const analyzingBtn = document.getElementById('analyzingBtn'); | |
| const thresholdSlider = document.getElementById('threshold'); | |
| const thresholdValue = document.getElementById('thresholdValue'); | |
| const resultsSection = document.getElementById('resultsSection'); | |
| const readyState = document.getElementById('readyState'); | |
| const toggleGradCAM = document.getElementById('toggleGradCAM'); | |
| const gradcamContent = document.getElementById('gradcamContent'); | |
| const predictionResult = document.getElementById('predictionResult'); | |
| const confidenceScore = document.getElementById('confidenceScore'); | |
| const confidenceBar = document.getElementById('confidenceBar'); | |
| const processingTime = document.getElementById('processingTime'); | |
| const gradcamOriginal = document.getElementById('gradcamOriginal'); | |
| const gradcamHeatmap = document.getElementById('gradcamHeatmap'); | |
| const metadataSection = document.getElementById('metadataSection'); | |
| const metadataContent = document.getElementById('metadataContent'); | |
| // Threshold slider handler | |
| thresholdSlider.addEventListener('input', function() { | |
| currentThreshold = parseFloat(this.value); | |
| thresholdValue.textContent = Math.round(currentThreshold * 100) + '%'; | |
| thresholdSlider.setAttribute('aria-valuenow', currentThreshold); | |
| document.getElementById('thresholdDisplay').textContent = `Threshold: ${Math.round(currentThreshold * 100)}%`; | |
| }); | |
| // File upload handlers | |
| fileInput.addEventListener('change', handleFileUpload); | |
| metadataInput.addEventListener('change', handleMetadataUpload); | |
| // Drag and drop handlers | |
| uploadArea.addEventListener('dragenter', handleDrag); | |
| uploadArea.addEventListener('dragover', handleDrag); | |
| uploadArea.addEventListener('dragleave', handleDragLeave); | |
| uploadArea.addEventListener('drop', handleDrop); | |
| // Analyze button handler | |
| analyzeBtn.addEventListener('click', analyzeDocument); | |
| // Grad-CAM toggle | |
| toggleGradCAM.addEventListener('click', function() { | |
| showGradCAM = !showGradCAM; | |
| if (showGradCAM) { | |
| gradcamContent.classList.remove('hidden'); | |
| this.querySelector('span').textContent = 'Hide Analysis'; | |
| } else { | |
| gradcamContent.classList.add('hidden'); | |
| this.querySelector('span').textContent = 'Show Analysis'; | |
| } | |
| }); | |
| function handleDrag(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| uploadArea.classList.add('drag-over'); | |
| } | |
| function handleDragLeave(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| uploadArea.classList.remove('drag-over'); | |
| } | |
| function handleDrop(e) { | |
| e.preventDefault(); | |
| e.stopPropagation(); | |
| uploadArea.classList.remove('drag-over'); | |
| const files = e.dataTransfer.files; | |
| for (let file of files) { | |
| if (file.type.startsWith('image/')) { | |
| processFile(file, 'image'); | |
| } else if (file.name.endsWith('.xlsx')) { | |
| processFile(file, 'metadata'); | |
| } | |
| } | |
| } | |
| function handleFileUpload(e) { | |
| const file = e.target.files[0]; | |
| if (file) { | |
| processFile(file, 'image'); | |
| } | |
| } | |
| function handleMetadataUpload(e) { | |
| const file = e.target.files[0]; | |
| if (file) { | |
| processFile(file, 'metadata'); | |
| } | |
| } | |
| function processFile(file, type) { | |
| if (type === 'image') { | |
| // Validate image | |
| if (!file.type.startsWith('image/')) { | |
| alert('Please select an image file (JPG, JPEG, PNG)'); | |
| return; | |
| } | |
| if (file.size > 10 * 1024 * 1024) { | |
| alert('Image file size must be less than 10MB'); | |
| return; | |
| } | |
| // Display uploaded image | |
| const reader = new FileReader(); | |
| reader.onload = function(e) { | |
| uploadedImageData = e.target.result; | |
| uploadedImage.src = uploadedImageData; | |
| // Update UI | |
| uploadContent.classList.add('hidden'); | |
| uploadedContent.classList.remove('hidden'); | |
| uploadArea.classList.add('uploaded'); | |
| analyzeBtn.classList.remove('hidden'); | |
| // Hide results | |
| resultsSection.classList.add('hidden'); | |
| readyState.classList.remove('hidden'); | |
| }; | |
| reader.readAsDataURL(file); | |
| fileInput.file = file; // Store file for analysis | |
| } else if (type === 'metadata') { | |
| // Validate metadata | |
| if (!file.name.endsWith('.xlsx')) { | |
| alert('Please select an XLSX file for metadata'); | |
| return; | |
| } | |
| if (file.size > 10 * 1024 * 1024) { | |
| alert('Metadata file size must be less than 10MB'); | |
| return; | |
| } | |
| // Store metadata file | |
| uploadedMetadata = file; | |
| metadataStatus.classList.remove('hidden'); | |
| metadataStatus.textContent = `Metadata file uploaded: ${file.name}`; | |
| } | |
| } | |
| function analyzeDocument() { | |
| if (!uploadedImageData || !fileInput.file) { | |
| alert('Please upload an image first'); | |
| return; | |
| } | |
| // Show analyzing state | |
| analyzeBtn.classList.add('hidden'); | |
| analyzingBtn.classList.remove('hidden'); | |
| // Prepare form data | |
| const formData = new FormData(); | |
| formData.append('file', fileInput.file); | |
| formData.append('threshold', currentThreshold); | |
| if (uploadedMetadata) { | |
| formData.append('metadata', uploadedMetadata); | |
| } | |
| // Send to Flask backend | |
| fetch('/analyze', { | |
| method: 'POST', | |
| body: formData | |
| }) | |
| .then(response => response.json()) | |
| .then(data => { | |
| if (data.error) { | |
| alert(data.error); | |
| throw new Error(data.error); | |
| } | |
| // Update results | |
| confidenceScore.textContent = data.confidence + '%'; | |
| processingTime.textContent = data.processing_time + 'ms'; | |
| confidenceBar.style.width = data.confidence + '%'; | |
| confidenceBar.className = `h-3 rounded-full transition-all duration-500 ${data.is_authentic ? 'bg-green-500' : 'bg-red-500'}`; | |
| // Update prediction | |
| predictionResult.className = `p-4 sm:p-6 rounded-xl border-2 ${data.is_authentic ? 'bg-green-50 border-green-200' : 'bg-red-50 border-red-200'}`; | |
| predictionResult.innerHTML = ` | |
| <div class="flex items-center space-x-3"> | |
| <i data-lucide="${data.is_authentic ? 'check-circle' : 'alert-triangle'}" class="h-6 sm:h-8 w-6 sm:w-8 ${data.is_authentic ? 'text-green-600' : 'text-red-600'}"></i> | |
| <div> | |
| <h4 class="text-base sm:text-lg font-semibold ${data.is_authentic ? 'text-green-800' : 'text-red-800'}"> | |
| Document is ${data.is_authentic ? 'Authentic' : 'Possibly Fake'} | |
| </h4> | |
| <p class="text-xs sm:text-sm ${data.is_authentic ? 'text-green-600' : 'text-red-600'}"> | |
| ${data.is_authentic ? 'High similarity to verified land title documents in our database.' : 'Low similarity suggests potential forgery or document type mismatch.'} | |
| </p> | |
| </div> | |
| </div> | |
| `; | |
| // Update Grad-CAM | |
| gradcamOriginal.src = data.original_image; | |
| gradcamHeatmap.src = data.heatmap_image; | |
| // Update metadata | |
| if (data.metadata) { | |
| metadataSection.classList.remove('hidden'); | |
| metadataContent.textContent = data.metadata; | |
| } else { | |
| metadataSection.classList.add('hidden'); | |
| } | |
| // Show results | |
| readyState.classList.add('hidden'); | |
| resultsSection.classList.remove('hidden'); | |
| // Reset buttons | |
| analyzingBtn.classList.add('hidden'); | |
| analyzeBtn.classList.remove('hidden'); | |
| // Re-initialize icons | |
| lucide.createIcons(); | |
| }) | |
| .catch(error => { | |
| console.error('Error:', error); | |
| alert('Error analyzing document'); | |
| analyzingBtn.classList.add('hidden'); | |
| analyzeBtn.classList.remove('hidden'); | |
| }); | |
| } |