// 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 = `
${data.is_authentic ? 'High similarity to verified land title documents in our database.' : 'Low similarity suggests potential forgery or document type mismatch.'}