File size: 15,623 Bytes
a79bfd9
 
 
 
 
 
 
0b69d1f
 
a79bfd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b69d1f
a79bfd9
 
 
 
 
0b69d1f
 
a79bfd9
 
 
 
 
0b69d1f
 
a79bfd9
0b69d1f
 
 
 
a79bfd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b69d1f
 
a79bfd9
0b69d1f
 
 
 
 
 
a79bfd9
0b69d1f
a79bfd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b69d1f
a79bfd9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b69d1f
a79bfd9
 
0b69d1f
a79bfd9
0b69d1f
a79bfd9
0b69d1f
a79bfd9
 
 
 
 
0b69d1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a79bfd9
0b69d1f
 
 
a79bfd9
0b69d1f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
document.addEventListener('DOMContentLoaded', function() {
    // Add listeners for radio buttons
    const radioButtons = document.querySelectorAll('input[name="inputMethod"]');
    radioButtons.forEach(radio => {
        radio.addEventListener('change', toggleInputMethod);
    });

    // Initialize the search and labels functionality
    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';
        // Clear URL input
        document.getElementById('urlInput').value = '';
    } else {
        localInputGroup.style.display = 'none';
        urlInputGroup.style.display = 'block';
        // Clear file input
        document.getElementById('fileInput').value = '';
    }
    
    // Clear preview and results
    clearPreviewAndResults();
}

function clearPreviewAndResults() {
    const imagePreview = document.getElementById('imagePreview');
    const resultsDiv = document.getElementById('results');
    
    imagePreview.src = '';
    resultsDiv.innerHTML = '';
}

// Auto-preview when file input changes
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'; // Show the image
            defaultPreviewMessage.style.display = 'none'; // Hide the default message
        };
        reader.readAsDataURL(fileInput.files[0]);
        urlInput.value = ''; // Clear URL input
    } else if (urlInput.value) {
        imagePreview.src = urlInput.value;
        imagePreview.style.display = 'block'; // Show the image
        defaultPreviewMessage.style.display = 'none'; // Hide the default message
        fileInput.value = ''; // Clear file input
    } else {
        // If no image is loaded, show the default message
        imagePreview.style.display = 'none'; // Hide the image
        defaultPreviewMessage.style.display = 'block'; // Show the default message
    }
}

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() {
    // Clear previous results first
    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 {
        // Get selected labels from both default checkboxes and selected labels container
        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);

        // Combine both sets of labels
        const allSelectedLabels = [...defaultLabels, ...selectedLabels];

        if (allSelectedLabels.length === 0) {
            throw new Error('Please select at least one category');
        }

        if (fileInput.files && fileInput.files[0]) {
            // Convert file to base64
            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) {
            // Convert URL to base64
            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>`;
        }
    });
}

// Define your labels with categories
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']
    // Add more categories and labels as needed
};

function initializeSearchAndLabels() {
    // First, remove any existing search containers to prevent duplicates
    const existingSearchContainers = document.querySelectorAll('.search-container');
    existingSearchContainers.forEach(container => container.remove());

    // Create search container with show all button
    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>
    `;

    // Insert the search container after the default labels
    const defaultLabels = document.querySelector('.default-labels');
    if (defaultLabels) {
        defaultLabels.parentNode.insertBefore(searchContainer, defaultLabels.nextElementSibling);
    }

    // Set up event listeners
    const searchInput = document.getElementById('labelSearch');
    const labelDropdown = document.getElementById('labelDropdown');
    const showAllButton = document.getElementById('showAllLabels');

    // Show dropdown on focus
    searchInput.addEventListener('focus', () => {
        const searchTerm = searchInput.value.trim().toLowerCase();
        showFilteredResults(searchTerm);
    });

    // Handle input changes
    searchInput.addEventListener('input', (e) => {
        const searchTerm = e.target.value.trim().toLowerCase();
        if (searchTerm) {
            showFilteredResults(searchTerm);
        } else {
            labelDropdown.style.display = 'none';
        }
    });

    // Show all button click handler
    showAllButton.addEventListener('click', function(e) {
        e.stopPropagation(); // Prevent event from bubbling up
        labelDropdown.style.display = 'block';
        showFilteredResults('');
        searchInput.value = '';
    });

    // Close dropdown when clicking outside
    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;

    // Sort categories alphabetically for better organization
    const sortedCategories = Object.entries(medicalLabels).sort((a, b) => a[0].localeCompare(b[0]));

    // Loop through all medical labels
    sortedCategories.forEach(([category, labels]) => {
        // Always show all labels when searchTerm is empty (Show All button clicked)
        // Otherwise, filter based on search term
        const matchingLabels = searchTerm === '' ? 
            labels.sort() : // Sort labels alphabetically
            labels.filter(label => label.toLowerCase().includes(searchTerm.toLowerCase()));

        if (matchingLabels.length > 0) {
            hasResults = true;
            
            // Add category header
            const categoryHeader = document.createElement('div');
            categoryHeader.className = 'dropdown-category-header';
            categoryHeader.textContent = category;
            labelDropdown.appendChild(categoryHeader);

            // Add labels
            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();
        }
    }
}

// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', initializeSearchAndLabels);