Spaces:
Running
Running
| const dropZone = document.getElementById('drop-zone'); | |
| const fileInput = document.getElementById('file-input'); | |
| const predictBtn = document.getElementById('predict-btn'); | |
| const imageDisplay = document.getElementById('image-display'); | |
| const previewSection = document.getElementById('preview-section'); | |
| const resultSection = document.getElementById('result-section'); | |
| const predictionLabel = document.getElementById('prediction-label'); | |
| const confidenceText = document.getElementById('confidence-text'); | |
| const confidenceBar = document.getElementById('confidence-bar'); | |
| const resetBtn = document.getElementById('reset-btn'); | |
| // Trigger file input on click | |
| dropZone.addEventListener('click', () => fileInput.click()); | |
| // Drag & Drop Handlers | |
| 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'); | |
| if (e.dataTransfer.files.length > 0) { | |
| handleFile(e.dataTransfer.files[0]); | |
| } | |
| }); | |
| fileInput.addEventListener('change', (e) => { | |
| if (e.target.files.length > 0) { | |
| handleFile(e.target.files[0]); | |
| } | |
| }); | |
| function handleFile(file) { | |
| if (!file.type.startsWith('image/')) { | |
| alert('Please upload an image file.'); | |
| return; | |
| } | |
| const reader = new FileReader(); | |
| reader.onload = (e) => { | |
| imageDisplay.src = e.target.result; | |
| dropZone.classList.add('hidden'); | |
| previewSection.classList.remove('hidden'); | |
| }; | |
| reader.readAsDataURL(file); | |
| } | |
| predictBtn.addEventListener('click', async () => { | |
| predictBtn.disabled = true; | |
| predictBtn.innerText = 'Analyzing...'; | |
| const formData = new FormData(); | |
| const file = fileInput.files[0] || null; // Simplified, in practice handle drop files too | |
| // For drop-zone files we might need to get them differently, | |
| // but for this demo let's assume valid file selection. | |
| // Convert base64 preview back to blob if needed, or just use the file | |
| formData.append('file', file); | |
| try { | |
| const response = await fetch('/predict', { | |
| method: 'POST', | |
| body: formData | |
| }); | |
| const data = await response.json(); | |
| if (data.success) { | |
| showResult(data.class, data.confidence); | |
| } else { | |
| alert('Error: ' + data.error); | |
| } | |
| } catch (error) { | |
| console.error('Error:', error); | |
| alert('Failed to connect to backend.'); | |
| } finally { | |
| predictBtn.disabled = false; | |
| predictBtn.innerText = 'Analyze Image'; | |
| } | |
| }); | |
| function showResult(className, confidence) { | |
| previewSection.classList.add('hidden'); | |
| resultSection.style.display = 'block'; | |
| predictionLabel.innerText = className.toUpperCase(); | |
| const confValue = (confidence * 100).toFixed(1); | |
| confidenceText.innerText = `${confValue}%`; | |
| // Trigger animation | |
| setTimeout(() => { | |
| confidenceBar.style.width = `${confValue}%`; | |
| }, 100); | |
| } | |
| resetBtn.addEventListener('click', () => { | |
| resultSection.style.display = 'none'; | |
| dropZone.classList.remove('hidden'); | |
| fileInput.value = ''; | |
| confidenceBar.style.width = '0%'; | |
| }); | |