|
|
|
|
|
|
|
|
let selectedFile = null;
|
|
|
|
|
|
|
|
|
const uploadArea = document.getElementById('uploadArea');
|
|
|
const fileInput = document.getElementById('fileInput');
|
|
|
const previewCard = document.getElementById('previewCard');
|
|
|
const previewImage = document.getElementById('previewImage');
|
|
|
const classifyBtn = document.getElementById('classifyBtn');
|
|
|
const randomBtn = document.getElementById('randomBtn');
|
|
|
const resultsSection = document.getElementById('resultsSection');
|
|
|
const loadingOverlay = document.getElementById('loadingOverlay');
|
|
|
|
|
|
|
|
|
uploadArea.addEventListener('click', () => {
|
|
|
fileInput.click();
|
|
|
});
|
|
|
|
|
|
|
|
|
fileInput.addEventListener('change', (e) => {
|
|
|
const file = e.target.files[0];
|
|
|
if (file) {
|
|
|
handleFile(file);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
uploadArea.addEventListener('dragover', (e) => {
|
|
|
e.preventDefault();
|
|
|
uploadArea.classList.add('drag-over');
|
|
|
});
|
|
|
|
|
|
uploadArea.addEventListener('dragleave', () => {
|
|
|
uploadArea.classList.remove('drag-over');
|
|
|
});
|
|
|
|
|
|
uploadArea.addEventListener('drop', (e) => {
|
|
|
e.preventDefault();
|
|
|
uploadArea.classList.remove('drag-over');
|
|
|
|
|
|
const file = e.dataTransfer.files[0];
|
|
|
if (file && file.type.startsWith('image/')) {
|
|
|
handleFile(file);
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
function handleFile(file) {
|
|
|
selectedFile = file;
|
|
|
|
|
|
const reader = new FileReader();
|
|
|
reader.onload = (e) => {
|
|
|
previewImage.src = e.target.result;
|
|
|
previewCard.style.display = 'block';
|
|
|
resultsSection.style.display = 'none';
|
|
|
};
|
|
|
reader.readAsDataURL(file);
|
|
|
}
|
|
|
|
|
|
|
|
|
classifyBtn.addEventListener('click', async () => {
|
|
|
if (!selectedFile) return;
|
|
|
|
|
|
const formData = new FormData();
|
|
|
formData.append('file', selectedFile);
|
|
|
|
|
|
try {
|
|
|
loadingOverlay.style.display = 'flex';
|
|
|
|
|
|
const response = await fetch('/predict', {
|
|
|
method: 'POST',
|
|
|
body: formData
|
|
|
});
|
|
|
|
|
|
const data = await response.json();
|
|
|
|
|
|
if (data.error) {
|
|
|
alert('Error: ' + data.error);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
displayResults(data);
|
|
|
|
|
|
} catch (error) {
|
|
|
alert('Error: ' + error.message);
|
|
|
} finally {
|
|
|
loadingOverlay.style.display = 'none';
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
randomBtn.addEventListener('click', async () => {
|
|
|
try {
|
|
|
loadingOverlay.style.display = 'flex';
|
|
|
|
|
|
const response = await fetch('/random_sample');
|
|
|
const data = await response.json();
|
|
|
|
|
|
if (data.error) {
|
|
|
alert('Error: ' + data.error);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
const blob = await fetch(data.image).then(r => r.blob());
|
|
|
const file = new File([blob], 'random_sample.png', { type: 'image/png' });
|
|
|
|
|
|
handleFile(file);
|
|
|
|
|
|
} catch (error) {
|
|
|
alert('Error: ' + error.message);
|
|
|
} finally {
|
|
|
loadingOverlay.style.display = 'none';
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
function displayResults(data) {
|
|
|
document.getElementById('predictedClass').textContent = data.predicted_class;
|
|
|
document.getElementById('confidenceValue').textContent = data.confidence.toFixed(2) + '%';
|
|
|
|
|
|
|
|
|
const badge = document.getElementById('confidenceBadge');
|
|
|
if (data.confidence >= 80) {
|
|
|
badge.style.background = 'rgba(79, 172, 254, 0.2)';
|
|
|
badge.style.borderColor = 'rgba(79, 172, 254, 0.4)';
|
|
|
badge.style.color = '#4facfe';
|
|
|
} else if (data.confidence >= 60) {
|
|
|
badge.style.background = 'rgba(240, 147, 251, 0.2)';
|
|
|
badge.style.borderColor = 'rgba(240, 147, 251, 0.4)';
|
|
|
badge.style.color = '#f093fb';
|
|
|
} else {
|
|
|
badge.style.background = 'rgba(245, 87, 108, 0.2)';
|
|
|
badge.style.borderColor = 'rgba(245, 87, 108, 0.4)';
|
|
|
badge.style.color = '#f5576c';
|
|
|
}
|
|
|
|
|
|
|
|
|
const top5Container = document.getElementById('top5Container');
|
|
|
top5Container.innerHTML = '';
|
|
|
|
|
|
data.top5_predictions.forEach((pred, index) => {
|
|
|
const item = document.createElement('div');
|
|
|
item.className = 'prediction-item';
|
|
|
item.style.animationDelay = `${index * 0.1}s`;
|
|
|
|
|
|
item.innerHTML = `
|
|
|
<span class="prediction-item-name">${pred.class}</span>
|
|
|
<div class="prediction-item-bar">
|
|
|
<div class="prediction-item-fill" style="width: ${pred.probability}%"></div>
|
|
|
</div>
|
|
|
<span class="prediction-item-value">${pred.probability.toFixed(2)}%</span>
|
|
|
`;
|
|
|
|
|
|
top5Container.appendChild(item);
|
|
|
});
|
|
|
|
|
|
resultsSection.style.display = 'grid';
|
|
|
|
|
|
|
|
|
resultsSection.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
|
}
|
|
|
|