File size: 8,586 Bytes
e9a924c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// 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');
    });
}