niru-nny's picture
fix: Update frontend to use relative API URL instead of localhost
5683168
// ========================================
// GPS Verifier - Frontend Application
// ========================================
// Configuration
// Use relative URL to work in any environment (localhost, Hugging Face, etc.)
const API_BASE_URL = window.location.origin;
const API_ENDPOINT = `${API_BASE_URL}/api/v1/validate-image-location`;
// DOM Elements
const dropZone = document.getElementById('dropZone');
const fileInput = document.getElementById('fileInput');
const previewSection = document.getElementById('previewSection');
const imagePreview = document.getElementById('imagePreview');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
const validateBtn = document.getElementById('validateBtn');
const clearBtn = document.getElementById('clearBtn');
const resultsSection = document.getElementById('resultsSection');
const errorSection = document.getElementById('errorSection');
const newValidationBtn = document.getElementById('newValidationBtn');
const retryBtn = document.getElementById('retryBtn');
const downloadBtn = document.getElementById('downloadBtn');
// State
let selectedFile = null;
let validationResults = null;
// ========================================
// Event Listeners
// ========================================
// Drop zone click
dropZone.addEventListener('click', () => {
fileInput.click();
});
// File input change
fileInput.addEventListener('change', (e) => {
handleFileSelect(e.target.files[0]);
});
// Drag and drop
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('drag-over');
});
dropZone.addEventListener('dragleave', () => {
dropZone.classList.remove('drag-over');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
dropZone.classList.remove('drag-over');
const file = e.dataTransfer.files[0];
handleFileSelect(file);
});
// Button clicks
clearBtn.addEventListener('click', resetUI);
validateBtn.addEventListener('click', validateImage);
newValidationBtn.addEventListener('click', resetUI);
retryBtn.addEventListener('click', resetUI);
downloadBtn.addEventListener('click', downloadReport);
// ========================================
// File Handling
// ========================================
function handleFileSelect(file) {
// Validate file
if (!file) return;
if (!file.type.startsWith('image/')) {
showError('Invalid file type', 'Please select an image file (JPG, PNG, WEBP)');
return;
}
if (file.size > 10 * 1024 * 1024) { // 10MB
showError('File too large', 'Please select an image smaller than 10MB');
return;
}
selectedFile = file;
// Display preview
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
fileName.textContent = file.name;
fileSize.textContent = formatFileSize(file.size);
// Show preview section
dropZone.style.display = 'none';
previewSection.style.display = 'block';
resultsSection.style.display = 'none';
errorSection.style.display = 'none';
};
reader.readAsDataURL(file);
}
function formatFileSize(bytes) {
if (bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
}
// ========================================
// Validation
// ========================================
async function validateImage() {
if (!selectedFile) return;
// Show loading state
const btnText = validateBtn.querySelector('.btn-text');
const btnLoader = validateBtn.querySelector('.btn-loader');
btnText.style.display = 'none';
btnLoader.style.display = 'block';
validateBtn.disabled = true;
try {
// Create form data
const formData = new FormData();
formData.append('file', selectedFile);
// Make API request
const response = await fetch(API_ENDPOINT, {
method: 'POST',
body: formData
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.detail || 'Validation failed');
}
// Check if GPS coordinates were found
if (data.error) {
showError(
data.error,
'Please try another image',
data.suggestions || []
);
return;
}
// Display results
displayResults(data);
} catch (error) {
console.error('Validation error:', error);
showError(
'Connection Error',
'Failed to connect to the validation server. Please try again.',
['Check your internet connection', 'Ensure the image contains GPS data', 'Try again in a few moments']
);
} finally {
// Reset button state
btnText.style.display = 'block';
btnLoader.style.display = 'none';
validateBtn.disabled = false;
}
}
// ========================================
// Display Results
// ========================================
function displayResults(data) {
validationResults = data;
// Update status badge
const statusBadge = document.getElementById('statusBadge');
const status = data.validation.status;
statusBadge.textContent = status.toUpperCase();
statusBadge.className = `status-badge ${status}`;
// Update GPS coordinates
document.getElementById('latitude').textContent = data.extracted_gps.latitude.toFixed(6) + '° N';
document.getElementById('longitude').textContent = data.extracted_gps.longitude.toFixed(6) + '° E';
document.getElementById('source').textContent = formatSource(data.extracted_gps.source);
document.getElementById('confidence').textContent = (data.extracted_gps.confidence * 100).toFixed(0) + '%';
// Update zone information
const zoneInfo = document.getElementById('zoneInfo');
if (status === 'valid') {
zoneInfo.style.display = 'block';
document.getElementById('zoneName').textContent = data.validation.zone_name || 'N/A';
document.getElementById('zoneType').textContent = formatZoneType(data.validation.zone_type) || 'N/A';
document.getElementById('department').textContent = data.validation.department || 'N/A';
document.getElementById('contact').textContent = data.validation.contact || 'N/A';
document.getElementById('email').textContent = data.validation.email || 'N/A';
} else {
zoneInfo.style.display = 'none';
}
// Update map link
const mapLink = document.getElementById('mapLink');
const lat = data.extracted_gps.latitude;
const lon = data.extracted_gps.longitude;
mapLink.href = `https://www.google.com/maps?q=${lat},${lon}`;
// Show results section
previewSection.style.display = 'none';
resultsSection.style.display = 'block';
errorSection.style.display = 'none';
// Scroll to results
resultsSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
function formatSource(source) {
const sourceMap = {
'exif': 'EXIF Metadata',
'ocr': 'OCR Text Extraction',
'pattern_recognition': 'Pattern Recognition',
'whatsapp_pattern': 'WhatsApp GPS Overlay'
};
return sourceMap[source] || source;
}
function formatZoneType(type) {
return type.split('_').map(word =>
word.charAt(0).toUpperCase() + word.slice(1)
).join(' ');
}
// ========================================
// Error Handling
// ========================================
function showError(title, message, suggestions = []) {
document.getElementById('errorMessage').textContent = message;
const suggestionsList = document.getElementById('errorSuggestions');
suggestionsList.innerHTML = '';
if (suggestions.length > 0) {
suggestions.forEach(suggestion => {
const li = document.createElement('li');
li.textContent = suggestion;
suggestionsList.appendChild(li);
});
suggestionsList.style.display = 'block';
} else {
suggestionsList.style.display = 'none';
}
// Show error section
previewSection.style.display = 'none';
resultsSection.style.display = 'none';
errorSection.style.display = 'block';
// Scroll to error
errorSection.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
// ========================================
// UI Reset
// ========================================
function resetUI() {
selectedFile = null;
validationResults = null;
fileInput.value = '';
dropZone.style.display = 'block';
previewSection.style.display = 'none';
resultsSection.style.display = 'none';
errorSection.style.display = 'none';
// Scroll to top
window.scrollTo({ top: 0, behavior: 'smooth' });
}
// ========================================
// Download Report
// ========================================
function downloadReport() {
if (!validationResults) return;
const report = {
filename: selectedFile.name,
timestamp: new Date().toISOString(),
gps_coordinates: validationResults.extracted_gps,
validation: validationResults.validation
};
const blob = new Blob([JSON.stringify(report, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `gps-validation-report-${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
// ========================================
// Smooth Scroll for Navigation
// ========================================
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
});
// ========================================
// Initialize
// ========================================
console.log('GPS Verifier UI initialized');
console.log('API Endpoint:', API_ENDPOINT);