CoffeeHealth-AI / static /script.js
SucoCafe's picture
Refine Bicho Mineiro advanced stage diagnostic and update UI
e665abb
document.addEventListener('DOMContentLoaded', () => {
const uploadArea = document.getElementById('upload-area');
const fileInput = document.getElementById('file-input');
const imagePreview = document.getElementById('image-preview');
const uploadContent = document.querySelector('.upload-content');
const analyzeBtn = document.getElementById('analyze-btn');
const btnText = document.querySelector('.btn-text');
const loader = document.querySelector('.loader');
const resultsPlaceholder = document.getElementById('results-placeholder');
const resultsContent = document.getElementById('results-content');
const mainDisease = document.getElementById('main-disease');
const chartCanvas = document.getElementById('resultsChart');
const cropsGallery = document.getElementById('crops-gallery');
let selectedFile = null;
let chartInstance = null;
// Theming Colors for the Chart
const chartColors = [
'#2f855a', // Green
'#8b5a2b', // Brown
'#48bb78', // Light Green
'#b7791f', // Yellow-Brown
'#276749' // Dark Green
];
// Drag and Drop Events
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
uploadArea.addEventListener(eventName, preventDefaults, false);
});
function preventDefaults(e) {
e.preventDefault();
e.stopPropagation();
}
['dragenter', 'dragover'].forEach(eventName => {
uploadArea.addEventListener(eventName, () => uploadArea.classList.add('dragover'), false);
});
['dragleave', 'drop'].forEach(eventName => {
uploadArea.addEventListener(eventName, () => uploadArea.classList.remove('dragover'), false);
});
uploadArea.addEventListener('drop', handleDrop, false);
uploadArea.addEventListener('click', () => fileInput.click());
fileInput.addEventListener('change', handleFileSelect);
function handleDrop(e) {
const dt = e.dataTransfer;
const file = dt.files[0];
handleFile(file);
}
function handleFileSelect(e) {
const file = e.target.files[0];
handleFile(file);
}
function handleFile(file) {
if (file && file.type.startsWith('image/')) {
selectedFile = file;
// Show preview
const reader = new FileReader();
reader.onload = (e) => {
imagePreview.src = e.target.result;
imagePreview.classList.remove('hidden');
uploadContent.classList.add('hidden');
analyzeBtn.disabled = false;
}
reader.readAsDataURL(file);
} else {
alert('Por favor, selecione um arquivo de imagem válido.');
}
}
analyzeBtn.addEventListener('click', async () => {
if (!selectedFile) return;
// UI Loading State
analyzeBtn.disabled = true;
btnText.innerHTML = '<i class="ph-bold ph-scan"></i> Analisando...';
loader.classList.remove('hidden');
resultsPlaceholder.querySelector('p').textContent = 'Processando IA (pode levar alguns segundos)...';
resultsContent.classList.add('hidden');
resultsPlaceholder.classList.remove('hidden');
const formData = new FormData();
formData.append('file', selectedFile);
try {
const response = await fetch('/predict', {
method: 'POST',
body: formData
});
if (!response.ok) {
const errData = await response.json();
throw new Error(errData.error || 'Erro na análise da imagem.');
}
const data = await response.json();
updateResults(data);
} catch (error) {
alert(error.message);
resultsPlaceholder.querySelector('p').textContent = 'Falha na análise. Tente novamente.';
} finally {
analyzeBtn.disabled = false;
btnText.innerHTML = '<i class="ph-bold ph-scan"></i> Analisar Folha';
loader.classList.add('hidden');
}
});
function updateResults(data) {
// Hide placeholder, show results
resultsPlaceholder.classList.add('hidden');
resultsContent.classList.remove('hidden');
// Update Text
mainDisease.textContent = data.mais_frequente;
// Render Chart
renderChart(data.contagem);
// Render Crops
renderCrops(data.imagens || []);
}
function renderCrops(imagens) {
cropsGallery.innerHTML = '';
if (imagens.length === 0) {
cropsGallery.innerHTML = '<p style="color:var(--text-secondary); width: 100%;">Nenhum recorte gerado.</p>';
return;
}
const timestamp = Date.now();
imagens.forEach(imgData => {
const card = document.createElement('div');
card.className = 'crop-card';
const img = document.createElement('img');
// Cache buster for new analyses
img.src = `${imgData.url}?t=${timestamp}`;
img.alt = 'Recorte detectado';
const label = document.createElement('div');
label.className = 'crop-card-label';
label.textContent = imgData.classe;
card.appendChild(img);
card.appendChild(label);
cropsGallery.appendChild(card);
});
}
function renderChart(counts) {
const labels = Object.keys(counts);
const data = Object.values(counts);
if (chartInstance) {
chartInstance.destroy();
}
chartInstance = new Chart(chartCanvas, {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
data: data,
backgroundColor: chartColors,
borderWidth: 0,
hoverOffset: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
labels: {
color: '#4a5568',
font: { family: "'Outfit', sans-serif", size: 10 },
padding: 10,
boxWidth: 12
}
},
tooltip: {
backgroundColor: 'rgba(255, 255, 255, 0.95)',
titleColor: '#2d3748',
bodyColor: '#2d3748',
borderColor: 'rgba(47, 133, 90, 0.2)',
borderWidth: 1,
padding: 10,
titleFont: { family: "'Outfit', sans-serif", size: 12, weight: 'bold' },
bodyFont: { family: "'Outfit', sans-serif", size: 12 }
}
},
cutout: '70%'
}
});
}
});