780e32c412
✅ Simplified Test Logic: - Removed unnecessary /detect/no-memory endpoint - Reverted to original 3 tests structure - Test 1: API Health Check - Test 2: Image with Memory Modules - Test 3: API Information ✅ Smart Message Display: - When memory modules found: '✅ Found X memory modules' - When no memory modules found: '❌ No memory modules' - Same endpoint, different message based on detection results ✅ Clean Implementation: - No additional endpoints needed - Uses existing /detect/hardcoded endpoint - Simple conditional message logic - Maintains original test count and structure Now the test will show the appropriate message whether memory modules are detected or not, using the same hardcoded test image.
471 lines
16 KiB
JavaScript
471 lines
16 KiB
JavaScript
// Memory Module Detection QA Interface JavaScript
|
|
|
|
const API_BASE_URL = 'http://localhost:5002';
|
|
let uploadedFile = null;
|
|
|
|
// Initialize the application
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initializeApp();
|
|
setupEventListeners();
|
|
});
|
|
|
|
function initializeApp() {
|
|
checkApiStatus();
|
|
loadApiInfo();
|
|
}
|
|
|
|
function setupEventListeners() {
|
|
// File input change
|
|
document.getElementById('fileInput').addEventListener('change', handleFileSelect);
|
|
|
|
// Drag and drop
|
|
const uploadArea = document.getElementById('uploadArea');
|
|
uploadArea.addEventListener('dragover', handleDragOver);
|
|
uploadArea.addEventListener('dragleave', handleDragLeave);
|
|
uploadArea.addEventListener('drop', handleDrop);
|
|
|
|
// 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'))) {
|
|
console.log('Upload area clicked, triggering file input');
|
|
const fileInput = document.getElementById('fileInput');
|
|
if (fileInput) {
|
|
fileInput.click();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
async function checkApiStatus() {
|
|
const statusElement = document.getElementById('apiStatus');
|
|
try {
|
|
const response = await fetch(`${API_BASE_URL}/health`);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
statusElement.className = 'status-indicator online';
|
|
statusElement.innerHTML = '<i class="fas fa-circle"></i> <span>API Online</span>';
|
|
} else {
|
|
throw new Error('API not responding');
|
|
}
|
|
} catch (error) {
|
|
statusElement.className = 'status-indicator offline';
|
|
statusElement.innerHTML = '<i class="fas fa-circle"></i> <span>API Offline</span>';
|
|
}
|
|
}
|
|
|
|
async function loadApiInfo() {
|
|
const apiInfoElement = document.getElementById('apiInfo');
|
|
try {
|
|
const response = await fetch(`${API_BASE_URL}/api`);
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
displayApiInfo(data);
|
|
} else {
|
|
throw new Error('Failed to load API info');
|
|
}
|
|
} catch (error) {
|
|
apiInfoElement.innerHTML = '<div class="error">Failed to load API information</div>';
|
|
}
|
|
}
|
|
|
|
function displayApiInfo(data) {
|
|
const apiInfoElement = document.getElementById('apiInfo');
|
|
apiInfoElement.innerHTML = `
|
|
<div class="info-item">
|
|
<h3>API Status</h3>
|
|
<p>${data.message}</p>
|
|
</div>
|
|
<div class="info-item">
|
|
<h3>Version</h3>
|
|
<p>${data.version}</p>
|
|
</div>
|
|
<div class="info-item">
|
|
<h3>Model Status</h3>
|
|
<p>${data.model_loaded ? 'Loaded ✅' : 'Not Loaded ❌'}</p>
|
|
</div>
|
|
<div class="info-item">
|
|
<h3>Supported Formats</h3>
|
|
<p>${data.supported_formats.join(', ')}</p>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function showUploadSection() {
|
|
document.getElementById('uploadSection').style.display = 'block';
|
|
document.getElementById('uploadSection').scrollIntoView({ behavior: 'smooth' });
|
|
|
|
// Ensure the upload area is properly initialized
|
|
initializeUploadArea();
|
|
}
|
|
|
|
function initializeUploadArea() {
|
|
const uploadArea = document.getElementById('uploadArea');
|
|
let fileInput = document.getElementById('fileInput');
|
|
|
|
// Completely recreate the file input element
|
|
if (fileInput) {
|
|
fileInput.remove();
|
|
}
|
|
|
|
// Create a brand new file input
|
|
const newFileInput = document.createElement('input');
|
|
newFileInput.type = 'file';
|
|
newFileInput.id = 'fileInput';
|
|
newFileInput.accept = 'image/*';
|
|
newFileInput.style.display = 'none';
|
|
newFileInput.multiple = false;
|
|
|
|
// Insert the new file input into the DOM
|
|
uploadArea.parentNode.insertBefore(newFileInput, uploadArea);
|
|
|
|
// Clear any existing event listeners on upload area by cloning
|
|
const newUploadArea = uploadArea.cloneNode(true);
|
|
uploadArea.parentNode.replaceChild(newUploadArea, uploadArea);
|
|
|
|
// Re-attach all event listeners to the new elements
|
|
newFileInput.addEventListener('change', handleFileSelect);
|
|
|
|
newUploadArea.addEventListener('dragover', handleDragOver);
|
|
newUploadArea.addEventListener('dragleave', handleDragLeave);
|
|
newUploadArea.addEventListener('drop', handleDrop);
|
|
|
|
newUploadArea.addEventListener('click', function(event) {
|
|
if (event.target === newUploadArea || (event.target.closest('.upload-content') && !event.target.closest('button'))) {
|
|
console.log('Upload area clicked, triggering file input');
|
|
const currentFileInput = document.getElementById('fileInput');
|
|
if (currentFileInput) {
|
|
currentFileInput.click();
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log('Upload area completely reinitialized with fresh file input');
|
|
}
|
|
|
|
function handleFileSelect(event) {
|
|
console.log('File select event triggered');
|
|
const file = event.target.files[0];
|
|
if (file) {
|
|
console.log('File selected:', file.name);
|
|
handleFile(file);
|
|
} else {
|
|
console.log('No file selected');
|
|
}
|
|
}
|
|
|
|
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]);
|
|
}
|
|
}
|
|
|
|
function handleFile(file) {
|
|
if (!file.type.startsWith('image/')) {
|
|
alert('Please select an image file');
|
|
return;
|
|
}
|
|
|
|
uploadedFile = file;
|
|
|
|
// 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 upload area HTML
|
|
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
|
|
const uploadControls = document.getElementById('uploadControls');
|
|
uploadControls.style.display = 'none';
|
|
|
|
// Remove the "Upload Another" button if it exists
|
|
const uploadAnotherBtn = uploadControls.querySelector('.upload-another');
|
|
if (uploadAnotherBtn) {
|
|
uploadAnotherBtn.remove();
|
|
}
|
|
|
|
// Hide results if showing
|
|
document.getElementById('resultsSection').style.display = 'none';
|
|
|
|
// Reinitialize the upload area with fresh event listeners
|
|
initializeUploadArea();
|
|
|
|
console.log('File upload reset completed');
|
|
}
|
|
|
|
async function processUploadedImage() {
|
|
if (!uploadedFile) {
|
|
alert('Please select an image first');
|
|
return;
|
|
}
|
|
|
|
const confidence = 0.8; // Fixed 80% threshold
|
|
showLoading('Processing uploaded image...');
|
|
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append('image', uploadedFile);
|
|
formData.append('confidence', confidence);
|
|
|
|
const response = await fetch(`${API_BASE_URL}/detect`, {
|
|
method: 'POST',
|
|
body: formData
|
|
});
|
|
|
|
const result = await response.json();
|
|
hideLoading();
|
|
|
|
if (result.success) {
|
|
displayResults(result, 'Uploaded Image Detection');
|
|
// Add option to upload another file
|
|
addUploadAnotherOption();
|
|
} else {
|
|
alert(`Detection failed: ${result.error}`);
|
|
}
|
|
} catch (error) {
|
|
hideLoading();
|
|
alert(`Error: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
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...');
|
|
|
|
try {
|
|
console.log(`Making request to: ${API_BASE_URL}/detect/hardcoded?confidence=0.8`);
|
|
const response = await fetch(`${API_BASE_URL}/detect/hardcoded?confidence=0.8`);
|
|
console.log('Response status:', response.status);
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
}
|
|
|
|
const result = await response.json();
|
|
console.log('Response data:', result);
|
|
hideLoading();
|
|
|
|
if (result.success) {
|
|
displayResults(result, 'Hardcoded Image Test');
|
|
} else {
|
|
alert(`Test failed: ${result.error}`);
|
|
}
|
|
} catch (error) {
|
|
hideLoading();
|
|
console.error('Hardcoded test error:', error);
|
|
alert(`Error: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
function displayResults(result, title) {
|
|
const resultsSection = document.getElementById('resultsSection');
|
|
const resultsContent = document.getElementById('resultsContent');
|
|
|
|
let detectionsHtml = '';
|
|
if (result.detections && result.detections.length > 0) {
|
|
detectionsHtml = result.detections.map((detection, index) => `
|
|
<div class="detection-item">
|
|
<span>Detection ${index + 1}: ${detection.class_name}</span>
|
|
<span class="detection-confidence">${(detection.confidence * 100).toFixed(1)}%</span>
|
|
</div>
|
|
`).join('');
|
|
} else {
|
|
detectionsHtml = '<div class="detection-item">No memory modules detected</div>';
|
|
}
|
|
|
|
resultsContent.innerHTML = `
|
|
<div class="result-item">
|
|
<div class="result-header">
|
|
<h3>${title}</h3>
|
|
<span class="badge">${new Date().toLocaleTimeString()}</span>
|
|
</div>
|
|
|
|
<div class="result-stats">
|
|
<div class="stat-item">
|
|
<div class="stat-value">${result.num_detections}</div>
|
|
<div class="stat-label">Detections</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-value">${(result.confidence_threshold * 100).toFixed(0)}%</div>
|
|
<div class="stat-label">Confidence</div>
|
|
</div>
|
|
<div class="stat-item">
|
|
<div class="stat-value">${result.success ? 'Success' : 'Failed'}</div>
|
|
<div class="stat-label">Status</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="detection-list">
|
|
<h4>Detected Memory Modules:</h4>
|
|
${detectionsHtml}
|
|
</div>
|
|
|
|
${result.annotated_image ? `
|
|
<div class="image-container">
|
|
<h4>Annotated Image:</h4>
|
|
<img src="data:image/png;base64,${result.annotated_image}"
|
|
alt="Annotated Result" class="result-image">
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
`;
|
|
|
|
resultsSection.style.display = 'block';
|
|
resultsSection.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
async function runAllTests() {
|
|
showLoading('Running comprehensive tests...');
|
|
const testResults = [];
|
|
|
|
// Test 1: API Health
|
|
try {
|
|
const response = await fetch(`${API_BASE_URL}/health`);
|
|
const result = await response.json();
|
|
testResults.push({
|
|
name: 'API Health Check',
|
|
success: response.ok && result.status === 'healthy',
|
|
message: response.ok ? 'API is healthy' : 'API health check failed'
|
|
});
|
|
} catch (error) {
|
|
testResults.push({
|
|
name: 'API Health Check',
|
|
success: false,
|
|
message: `Error: ${error.message}`
|
|
});
|
|
}
|
|
|
|
// Test 2: Image with Memory Modules
|
|
try {
|
|
const response = await fetch(`${API_BASE_URL}/detect/hardcoded`);
|
|
const result = await response.json();
|
|
testResults.push({
|
|
name: 'Image with Memory Modules',
|
|
success: result.success,
|
|
message: result.success ?
|
|
(result.num_detections > 0 ?
|
|
`✅ Found ${result.num_detections} memory modules` :
|
|
`❌ No memory modules`) :
|
|
`❌ Error: ${result.error}`
|
|
});
|
|
} catch (error) {
|
|
testResults.push({
|
|
name: 'Image with Memory Modules',
|
|
success: false,
|
|
message: `❌ Error: ${error.message}`
|
|
});
|
|
}
|
|
|
|
// Test 3: API Information
|
|
try {
|
|
const response = await fetch(`${API_BASE_URL}/api`);
|
|
const result = await response.json();
|
|
testResults.push({
|
|
name: 'API Information',
|
|
success: response.ok && result.message,
|
|
message: response.ok ? 'API info loaded successfully' : 'Failed to load API info'
|
|
});
|
|
} catch (error) {
|
|
testResults.push({
|
|
name: 'API Information',
|
|
success: false,
|
|
message: `Error: ${error.message}`
|
|
});
|
|
}
|
|
|
|
hideLoading();
|
|
displayTestResults(testResults);
|
|
}
|
|
|
|
function displayTestResults(testResults) {
|
|
const testResultsSection = document.getElementById('testResultsSection');
|
|
const testResultsContent = document.getElementById('testResults');
|
|
|
|
const successCount = testResults.filter(test => test.success).length;
|
|
const totalTests = testResults.length;
|
|
|
|
const testsHtml = testResults.map(test => `
|
|
<div class="test-item ${test.success ? 'success' : 'error'}">
|
|
<h3>
|
|
<i class="fas ${test.success ? 'fa-check-circle' : 'fa-times-circle'}"></i>
|
|
${test.name}
|
|
</h3>
|
|
<p>${test.message}</p>
|
|
</div>
|
|
`).join('');
|
|
|
|
testResultsContent.innerHTML = `
|
|
<div class="test-summary">
|
|
<h3>Test Summary: ${successCount}/${totalTests} tests passed</h3>
|
|
</div>
|
|
${testsHtml}
|
|
`;
|
|
|
|
testResultsSection.style.display = 'block';
|
|
testResultsSection.scrollIntoView({ behavior: 'smooth' });
|
|
}
|
|
|
|
function showLoading(message) {
|
|
document.getElementById('loadingText').textContent = message;
|
|
document.getElementById('loadingOverlay').style.display = 'flex';
|
|
}
|
|
|
|
function hideLoading() {
|
|
document.getElementById('loadingOverlay').style.display = 'none';
|
|
}
|