Fix file upload issues and add Swagger UI API documentation
✅ Frontend File Upload Fixes: - Fixed file upload reset issue - can now upload multiple files without page reload - Added 'Change File' and 'Upload Another Image' buttons for better UX - Fixed double-click file selection issue with proper event handling - Improved drag & drop functionality with proper event propagation - Added visual feedback for file selection and processing states ✅ Swagger UI API Documentation: - Created api_docs.py with comprehensive Swagger UI documentation - Added Flask-RESTX for professional API documentation interface - Documented all 3 detection endpoints with request/response models - Added health check endpoint documentation - Included detailed parameter descriptions and example responses - Available at http://localhost:5003/docs/ for interactive API testing ✅ Enhanced User Experience: - Seamless file upload workflow without page reloads - Clear visual indicators for file selection and processing - Professional API documentation for developers and QA testing - Consistent 80% confidence threshold across all interfaces ✅ Technical Improvements: - Better event handling for file inputs and drag & drop - Proper cleanup of uploaded files and UI state - Comprehensive error handling and user feedback - Interactive API documentation with live testing capabilities
This commit is contained in:
+61
-6
@@ -23,7 +23,14 @@ function setupEventListeners() {
|
||||
uploadArea.addEventListener('dragover', handleDragOver);
|
||||
uploadArea.addEventListener('dragleave', handleDragLeave);
|
||||
uploadArea.addEventListener('drop', handleDrop);
|
||||
uploadArea.addEventListener('click', () => document.getElementById('fileInput').click());
|
||||
|
||||
// Click to upload (only on the upload area, not buttons inside it)
|
||||
uploadArea.addEventListener('click', function(event) {
|
||||
// Only trigger file input if clicking on the upload area itself, not buttons
|
||||
if (event.target === uploadArea || event.target.closest('.upload-content') && !event.target.closest('button')) {
|
||||
document.getElementById('fileInput').click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function checkApiStatus() {
|
||||
@@ -94,17 +101,21 @@ function handleFileSelect(event) {
|
||||
|
||||
function handleDragOver(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.currentTarget.classList.add('dragover');
|
||||
}
|
||||
|
||||
function handleDragLeave(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.currentTarget.classList.remove('dragover');
|
||||
}
|
||||
|
||||
function handleDrop(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.currentTarget.classList.remove('dragover');
|
||||
|
||||
|
||||
const files = event.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
handleFile(files[0]);
|
||||
@@ -116,23 +127,53 @@ function handleFile(file) {
|
||||
alert('Please select an image file');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uploadedFile = file;
|
||||
|
||||
// Show file info
|
||||
|
||||
// Show file info with change file option
|
||||
const uploadArea = document.getElementById('uploadArea');
|
||||
uploadArea.innerHTML = `
|
||||
<div class="upload-content">
|
||||
<i class="fas fa-check-circle upload-icon" style="color: #28a745;"></i>
|
||||
<p><strong>File selected:</strong> ${file.name}</p>
|
||||
<p class="upload-hint">Size: ${(file.size / 1024 / 1024).toFixed(2)} MB</p>
|
||||
<button class="btn btn-outline" onclick="resetFileUpload()" style="margin-top: 10px;">
|
||||
<i class="fas fa-sync-alt"></i> Change File
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
// Show controls
|
||||
document.getElementById('uploadControls').style.display = 'block';
|
||||
}
|
||||
|
||||
function resetFileUpload() {
|
||||
uploadedFile = null;
|
||||
|
||||
// Reset file input
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
fileInput.value = '';
|
||||
|
||||
// Reset upload area
|
||||
const uploadArea = document.getElementById('uploadArea');
|
||||
uploadArea.innerHTML = `
|
||||
<div class="upload-content">
|
||||
<i class="fas fa-cloud-upload-alt upload-icon"></i>
|
||||
<p>Drag and drop an image here or click to select</p>
|
||||
<p class="upload-hint">Supported formats: PNG, JPG, JPEG, GIF, BMP</p>
|
||||
<button class="btn btn-outline" onclick="document.getElementById('fileInput').click()">
|
||||
Select Image
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Hide controls
|
||||
document.getElementById('uploadControls').style.display = 'none';
|
||||
|
||||
// Hide results if showing
|
||||
document.getElementById('resultsSection').style.display = 'none';
|
||||
}
|
||||
|
||||
async function processUploadedImage() {
|
||||
if (!uploadedFile) {
|
||||
alert('Please select an image first');
|
||||
@@ -157,6 +198,8 @@ async function processUploadedImage() {
|
||||
|
||||
if (result.success) {
|
||||
displayResults(result, 'Uploaded Image Detection');
|
||||
// Add option to upload another file
|
||||
addUploadAnotherOption();
|
||||
} else {
|
||||
alert(`Detection failed: ${result.error}`);
|
||||
}
|
||||
@@ -166,6 +209,18 @@ async function processUploadedImage() {
|
||||
}
|
||||
}
|
||||
|
||||
function addUploadAnotherOption() {
|
||||
const uploadControls = document.getElementById('uploadControls');
|
||||
if (!uploadControls.querySelector('.upload-another')) {
|
||||
const uploadAnotherBtn = document.createElement('button');
|
||||
uploadAnotherBtn.className = 'btn btn-secondary upload-another';
|
||||
uploadAnotherBtn.style.marginLeft = '10px';
|
||||
uploadAnotherBtn.innerHTML = '<i class="fas fa-plus"></i> Upload Another Image';
|
||||
uploadAnotherBtn.onclick = resetFileUpload;
|
||||
uploadControls.appendChild(uploadAnotherBtn);
|
||||
}
|
||||
}
|
||||
|
||||
async function testHardcodedImage() {
|
||||
showLoading('Testing hardcoded image...');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user