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:
Aherobo Ovie Victor
2025-07-11 21:15:41 +01:00
parent 26a6f6f625
commit db795c5729
2 changed files with 306 additions and 6 deletions
+61 -6
View File
@@ -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...');