| document.addEventListener('DOMContentLoaded', function() { |
| |
| const radioButtons = document.querySelectorAll('input[name="inputMethod"]'); |
| radioButtons.forEach(radio => { |
| radio.addEventListener('change', toggleInputMethod); |
| }); |
|
|
| |
| initializeSearchAndLabels(); |
| }); |
|
|
| function toggleInputMethod() { |
| const localInputGroup = document.getElementById('localInputGroup'); |
| const urlInputGroup = document.getElementById('urlInputGroup'); |
| const selectedMethod = document.querySelector('input[name="inputMethod"]:checked').value; |
|
|
| if (selectedMethod === 'local') { |
| localInputGroup.style.display = 'block'; |
| urlInputGroup.style.display = 'none'; |
| |
| document.getElementById('urlInput').value = ''; |
| } else { |
| localInputGroup.style.display = 'none'; |
| urlInputGroup.style.display = 'block'; |
| |
| document.getElementById('fileInput').value = ''; |
| } |
| |
| |
| clearPreviewAndResults(); |
| } |
|
|
| function clearPreviewAndResults() { |
| const imagePreview = document.getElementById('imagePreview'); |
| const resultsDiv = document.getElementById('results'); |
| |
| imagePreview.src = ''; |
| resultsDiv.innerHTML = ''; |
| } |
|
|
| |
| document.getElementById('fileInput').addEventListener('change', previewImage); |
| document.getElementById('urlInput').addEventListener('input', debounce(previewImage, 500)); |
|
|
| function debounce(func, wait) { |
| let timeout; |
| return function executedFunction(...args) { |
| const later = () => { |
| clearTimeout(timeout); |
| func(...args); |
| }; |
| clearTimeout(timeout); |
| timeout = setTimeout(later, wait); |
| }; |
| } |
|
|
| function previewImage() { |
| const fileInput = document.getElementById('fileInput'); |
| const urlInput = document.getElementById('urlInput'); |
| const imagePreview = document.getElementById('imagePreview'); |
| const defaultPreviewMessage = document.getElementById('defaultPreviewMessage'); |
|
|
| if (fileInput.files && fileInput.files[0]) { |
| const reader = new FileReader(); |
| reader.onload = function(e) { |
| imagePreview.src = e.target.result; |
| imagePreview.style.display = 'block'; |
| defaultPreviewMessage.style.display = 'none'; |
| }; |
| reader.readAsDataURL(fileInput.files[0]); |
| urlInput.value = ''; |
| } else if (urlInput.value) { |
| imagePreview.src = urlInput.value; |
| imagePreview.style.display = 'block'; |
| defaultPreviewMessage.style.display = 'none'; |
| fileInput.value = ''; |
| } else { |
| |
| imagePreview.style.display = 'none'; |
| defaultPreviewMessage.style.display = 'block'; |
| } |
| } |
|
|
| async function getBase64FromUrl(url) { |
| const response = await fetch(url); |
| const blob = await response.blob(); |
| return new Promise((resolve, reject) => { |
| const reader = new FileReader(); |
| reader.onload = () => { |
| const base64String = reader.result.split(',')[1]; |
| resolve(base64String); |
| }; |
| reader.onerror = reject; |
| reader.readAsDataURL(blob); |
| }); |
| } |
|
|
| async function analyzeImage() { |
| |
| document.getElementById('results').innerHTML = ''; |
| |
| const spinner = document.getElementById('spinner'); |
| const analyzeBtn = document.getElementById('analyzeBtn'); |
| const resultsDiv = document.getElementById('results'); |
| |
| spinner.style.display = 'block'; |
| analyzeBtn.disabled = true; |
| analyzeBtn.textContent = 'Analyzing...'; |
|
|
| const fileInput = document.getElementById('fileInput'); |
| const urlInput = document.getElementById('urlInput'); |
| let base64Image; |
|
|
| try { |
| |
| const defaultLabels = Array.from(document.querySelectorAll('.default-labels input[type="checkbox"]:checked')) |
| .map(checkbox => checkbox.value); |
| |
| const selectedLabels = Array.from(document.querySelectorAll('#selectedLabels .selected-label')) |
| .map(label => label.dataset.label); |
|
|
| |
| const allSelectedLabels = [...defaultLabels, ...selectedLabels]; |
|
|
| if (allSelectedLabels.length === 0) { |
| throw new Error('Please select at least one category'); |
| } |
|
|
| if (fileInput.files && fileInput.files[0]) { |
| |
| const reader = new FileReader(); |
| base64Image = await new Promise((resolve) => { |
| reader.onload = (e) => { |
| resolve(e.target.result.split(',')[1]); |
| }; |
| reader.readAsDataURL(fileInput.files[0]); |
| }); |
| } else if (urlInput.value) { |
| |
| base64Image = await getBase64FromUrl(urlInput.value); |
| } else { |
| throw new Error('Please select a file or enter a URL.'); |
| } |
|
|
| const payload = { |
| images: [base64Image], |
| labels: allSelectedLabels, |
| multilabel: false |
| }; |
|
|
| const response = await fetch('http://localhost:8000/predict', { |
| method: 'POST', |
| headers: { |
| 'Content-Type': 'application/json' |
| }, |
| body: JSON.stringify(payload) |
| }); |
|
|
| const data = await response.json(); |
| displayResults(data.predictions); |
| } catch (error) { |
| console.error('Error:', error); |
| resultsDiv.innerHTML = `<p class="error-message">Error: ${error.message}</p>`; |
| } finally { |
| spinner.style.display = 'none'; |
| analyzeBtn.disabled = false; |
| analyzeBtn.textContent = 'Analyze'; |
| } |
| } |
|
|
| function displayResults(predictions) { |
| const resultsDiv = document.getElementById('results'); |
| resultsDiv.innerHTML = ''; |
|
|
| if (!predictions || predictions.length === 0) { |
| resultsDiv.innerHTML = '<p>No predictions available.</p>'; |
| return; |
| } |
|
|
| predictions.forEach(prediction => { |
| resultsDiv.innerHTML += '<h2>Results:</h2>'; |
| for (const [label, probability] of Object.entries(prediction)) { |
| const percentage = (probability * 100).toFixed(1); |
| resultsDiv.innerHTML += ` |
| <div class="prediction-result"> |
| <strong>${label}:</strong> |
| <div class="progress-bar"> |
| <div class="progress" style="width: ${percentage}%"></div> |
| </div> |
| <span>${percentage}%</span> |
| </div>`; |
| } |
| }); |
| } |
|
|
| |
| const medicalLabels = { |
| 'Others': ['Effusion', 'Edema', 'Scar Tissue', 'Calcification'], |
| 'Pulmonology': ['Pneumonia', 'Asthma', 'COPD', 'Tuberculosis', 'Pulmonary Fibrosis', 'Pleural Effusion', 'Pulmonary Edema', 'Lung Nodule', 'Atelectasis', 'Pneumothorax'], |
| 'Oncology': ['Tumor', 'Breast Cancer', 'Lung Cancer', 'Prostate Cancer', 'Leukemia', 'Lymphoma', 'Melanoma', 'Colorectal Cancer', 'Glioma', 'Metastasis'], |
| 'Orthopedics': ['Fracture', 'Arthritis', 'Osteoporosis', 'Scoliosis', 'Tendonitis', 'Joint Effusion', 'Disc Herniation', 'Osteomyelitis', 'Bursitis', 'Bone Lesion'], |
| 'Cardiology': ['Myocardial Infarction', 'Arrhythmia', 'Heart Failure', 'Cardiomegaly', 'Aortic Aneurysm', 'Valvular Heart Disease', 'Coronary Artery Disease', 'Pericardial Effusion', 'Pulmonary Embolism'], |
| 'Dermatology': ['Urtikaria', 'Akne', 'Eczema', 'Psoriasis', 'Melanoma', 'Basal Cell Carcinoma', 'Squamous Cell Carcinoma', 'Skin Ulcer', 'Rash'], |
| 'Gastroenterology': ['Cirrhosis', 'Hepatitis', 'Ulcer', 'Gastric Cancer', 'Polyp', 'Pancreatitis', 'Cholecystitis', 'Colitis', 'Crohn’s Disease'], |
| 'Neurology': ['Stroke', 'Multiple Sclerosis', 'Parkinson’s Disease', 'Alzheimer’s Disease', 'Epilepsy', 'Brain Tumor', 'Hydrocephalus', 'Meningitis', 'Intracranial Hemorrhage'], |
| 'Endocrinology': ['Diabetes', 'Thyroid Nodule', 'Goiter', 'Adrenal Tumor', 'Pituitary Adenoma', 'Hyperthyroidism', 'Hypothyroidism', 'Parathyroid Hyperplasia'], |
| 'Hematology': ['Anemia', 'Thrombocytopenia', 'Leukemia', 'Lymphoma', 'Hemophilia', 'Polycythemia', 'Sickle Cell Disease'], |
| 'Urology': ['Kidney Stone', 'Bladder Cancer', 'Prostate Cancer', 'Urinary Tract Infection', 'Renal Cyst', 'Hydronephrosis'], |
| 'Ophthalmology': ['Glaucoma', 'Cataract', 'Retinal Detachment', 'Macular Degeneration', 'Diabetic Retinopathy', 'Conjunctivitis'], |
| 'Gynecology': ['Ovarian Cyst', 'Fibroids', 'Endometriosis', 'Breast Cancer', 'Polycystic Ovary Syndrome', 'Cervical Cancer'], |
| 'Rheumatology': ['Rheumatoid Arthritis', 'Lupus', 'Scleroderma', 'Ankylosing Spondylitis', 'Gout', 'Sjogren’s Syndrome'] |
| |
| }; |
|
|
| function initializeSearchAndLabels() { |
| |
| const existingSearchContainers = document.querySelectorAll('.search-container'); |
| existingSearchContainers.forEach(container => container.remove()); |
|
|
| |
| const searchContainer = document.createElement('div'); |
| searchContainer.className = 'search-container'; |
| searchContainer.innerHTML = ` |
| <div class="search-wrapper"> |
| <input type="text" id="labelSearch" class="search-input" placeholder="Search labels..."> |
| <button id="showAllLabels" class="show-all-btn">Show All</button> |
| </div> |
| <div id="labelDropdown" class="label-dropdown" style="display: none;"></div> |
| `; |
|
|
| |
| const defaultLabels = document.querySelector('.default-labels'); |
| if (defaultLabels) { |
| defaultLabels.parentNode.insertBefore(searchContainer, defaultLabels.nextElementSibling); |
| } |
|
|
| |
| const searchInput = document.getElementById('labelSearch'); |
| const labelDropdown = document.getElementById('labelDropdown'); |
| const showAllButton = document.getElementById('showAllLabels'); |
|
|
| |
| searchInput.addEventListener('focus', () => { |
| const searchTerm = searchInput.value.trim().toLowerCase(); |
| showFilteredResults(searchTerm); |
| }); |
|
|
| |
| searchInput.addEventListener('input', (e) => { |
| const searchTerm = e.target.value.trim().toLowerCase(); |
| if (searchTerm) { |
| showFilteredResults(searchTerm); |
| } else { |
| labelDropdown.style.display = 'none'; |
| } |
| }); |
|
|
| |
| showAllButton.addEventListener('click', function(e) { |
| e.stopPropagation(); |
| labelDropdown.style.display = 'block'; |
| showFilteredResults(''); |
| searchInput.value = ''; |
| }); |
|
|
| |
| document.addEventListener('click', (e) => { |
| if (!searchInput.contains(e.target) && |
| !labelDropdown.contains(e.target) && |
| !showAllButton.contains(e.target)) { |
| labelDropdown.style.display = 'none'; |
| } |
| }); |
| } |
|
|
| function showFilteredResults(searchTerm) { |
| const labelDropdown = document.getElementById('labelDropdown'); |
| labelDropdown.innerHTML = ''; |
| let hasResults = false; |
|
|
| |
| const sortedCategories = Object.entries(medicalLabels).sort((a, b) => a[0].localeCompare(b[0])); |
|
|
| |
| sortedCategories.forEach(([category, labels]) => { |
| |
| |
| const matchingLabels = searchTerm === '' ? |
| labels.sort() : |
| labels.filter(label => label.toLowerCase().includes(searchTerm.toLowerCase())); |
|
|
| if (matchingLabels.length > 0) { |
| hasResults = true; |
| |
| |
| const categoryHeader = document.createElement('div'); |
| categoryHeader.className = 'dropdown-category-header'; |
| categoryHeader.textContent = category; |
| labelDropdown.appendChild(categoryHeader); |
|
|
| |
| matchingLabels.forEach(label => { |
| const option = document.createElement('div'); |
| option.className = 'dropdown-option'; |
| |
| const checkbox = document.createElement('input'); |
| checkbox.type = 'checkbox'; |
| checkbox.id = `${category}-${label}`; |
| checkbox.checked = isLabelSelected(category, label); |
| checkbox.addEventListener('change', () => updateSelectedLabels(category, label)); |
|
|
| const labelText = document.createElement('span'); |
| labelText.className = 'label-text'; |
| labelText.textContent = label; |
|
|
| const categoryBadge = document.createElement('span'); |
| categoryBadge.className = 'category-badge'; |
| categoryBadge.textContent = category; |
|
|
| option.appendChild(checkbox); |
| option.appendChild(labelText); |
| option.appendChild(categoryBadge); |
| labelDropdown.appendChild(option); |
| }); |
| } |
| }); |
|
|
| labelDropdown.style.display = hasResults || searchTerm === '' ? 'block' : 'none'; |
| } |
|
|
| function isLabelSelected(category, label) { |
| const selectedLabelsContainer = document.getElementById('selectedLabels'); |
| return !!selectedLabelsContainer.querySelector( |
| `[data-category="${category}"][data-label="${label}"]` |
| ); |
| } |
|
|
| function updateSelectedLabels(category, label) { |
| const selectedLabelsContainer = document.getElementById('selectedLabels'); |
| const checkbox = document.getElementById(`${category}-${label}`); |
| |
| if (checkbox.checked) { |
| const labelElement = document.createElement('span'); |
| labelElement.className = 'selected-label'; |
| labelElement.textContent = `${label}`; |
| labelElement.dataset.category = category; |
| labelElement.dataset.label = label; |
| |
| const categoryBadge = document.createElement('span'); |
| categoryBadge.className = 'category-badge'; |
| categoryBadge.textContent = category; |
| |
| const removeButton = document.createElement('span'); |
| removeButton.className = 'remove-label'; |
| removeButton.innerHTML = '×'; |
| removeButton.onclick = () => { |
| labelElement.remove(); |
| checkbox.checked = false; |
| }; |
| |
| labelElement.appendChild(categoryBadge); |
| labelElement.appendChild(removeButton); |
| selectedLabelsContainer.appendChild(labelElement); |
| } else { |
| const existingLabel = selectedLabelsContainer.querySelector( |
| `[data-category="${category}"][data-label="${label}"]` |
| ); |
| if (existingLabel) { |
| existingLabel.remove(); |
| } |
| } |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', initializeSearchAndLabels); |
|
|
|
|