frappierer commited on
Commit
0b69d1f
·
verified ·
1 Parent(s): 2f86c79

Upload 3 files

Browse files
Files changed (3) hide show
  1. index.html +30 -5
  2. script.js +204 -38
  3. styles.css +236 -52
index.html CHANGED
@@ -34,17 +34,42 @@
34
  </div>
35
 
36
  <div class="label-section">
37
- <label>Select Categories:</label>
38
- <div class="label-grid" id="labelGrid">
39
- <!-- Labels will be inserted here dynamically -->
 
 
 
 
 
 
 
 
40
  </div>
41
- </div>
42
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  <div class="preview-section">
44
- <img id="imagePreview" src="" alt="Image Preview">
45
  <div class="spinner" id="spinner" style="display: none;">
46
  <div class="spinner-inner"></div>
47
  </div>
 
48
  </div>
49
 
50
  <button onclick="analyzeImage()" id="analyzeBtn">Analyze</button>
 
34
  </div>
35
 
36
  <div class="label-section">
37
+ <!-- Default Labels -->
38
+ <div class="default-labels">
39
+ <label class="label-option">
40
+ <input type="checkbox" name="default" value="Normal" checked>
41
+ Normal
42
+ </label>
43
+ <label class="label-option">
44
+ <input type="checkbox" name="default" value="Unspecified">
45
+ Unspecified
46
+ </label>
47
+ <p class="helper-text">Best Practice is to select Normal since it will compare it to a healthy state.</p>
48
  </div>
 
49
 
50
+ <!-- Search Container with Show All Button -->
51
+ <div class="search-container">
52
+ <div class="search-wrapper">
53
+ <input type="text" id="labelSearch" class="search-input" placeholder="Search labels...">
54
+ <button id="showAllLabels" class="show-all-btn">Show All</button>
55
+ </div>
56
+ <div id="labelDropdown" class="label-dropdown" style="display: none;">
57
+ <!-- Labels will be populated here -->
58
+ </div>
59
+ </div>
60
+ </div>
61
+
62
+ <div id="selectedLabelsContainer" class="selected-labels-container">
63
+ <h3>Selected Labels:</h3>
64
+ <div id="selectedLabels"></div>
65
+ </div>
66
+
67
  <div class="preview-section">
68
+ <img id="imagePreview" src="" alt="Image Preview" style="display: none;">
69
  <div class="spinner" id="spinner" style="display: none;">
70
  <div class="spinner-inner"></div>
71
  </div>
72
+ <p id="defaultPreviewMessage" style="display: block;">No image loaded. Please upload an image or enter a URL.</p>
73
  </div>
74
 
75
  <button onclick="analyzeImage()" id="analyzeBtn">Analyze</button>
script.js CHANGED
@@ -5,8 +5,8 @@ document.addEventListener('DOMContentLoaded', function() {
5
  radio.addEventListener('change', toggleInputMethod);
6
  });
7
 
8
- // Generate labels
9
- generateLabelCheckboxes();
10
  });
11
 
12
  function toggleInputMethod() {
@@ -58,17 +58,26 @@ function previewImage() {
58
  const fileInput = document.getElementById('fileInput');
59
  const urlInput = document.getElementById('urlInput');
60
  const imagePreview = document.getElementById('imagePreview');
 
61
 
62
  if (fileInput.files && fileInput.files[0]) {
63
  const reader = new FileReader();
64
  reader.onload = function(e) {
65
  imagePreview.src = e.target.result;
 
 
66
  };
67
  reader.readAsDataURL(fileInput.files[0]);
68
  urlInput.value = ''; // Clear URL input
69
  } else if (urlInput.value) {
70
  imagePreview.src = urlInput.value;
 
 
71
  fileInput.value = ''; // Clear file input
 
 
 
 
72
  }
73
  }
74
 
@@ -103,11 +112,17 @@ async function analyzeImage() {
103
  let base64Image;
104
 
105
  try {
106
- // Get selected labels from checkboxes
107
- const selectedLabels = Array.from(document.querySelectorAll('.label-option input[type="checkbox"]:checked'))
108
  .map(checkbox => checkbox.value);
 
 
 
 
 
 
109
 
110
- if (selectedLabels.length === 0) {
111
  throw new Error('Please select at least one category');
112
  }
113
 
@@ -129,7 +144,7 @@ async function analyzeImage() {
129
 
130
  const payload = {
131
  images: [base64Image],
132
- labels: selectedLabels,
133
  multilabel: false
134
  };
135
 
@@ -165,46 +180,197 @@ function displayResults(predictions) {
165
  predictions.forEach(prediction => {
166
  resultsDiv.innerHTML += '<h2>Results:</h2>';
167
  for (const [label, probability] of Object.entries(prediction)) {
 
168
  resultsDiv.innerHTML += `
169
  <div class="prediction-result">
170
- <strong>${label}:</strong>
171
  <div class="progress-bar">
172
- <div class="progress" style="width: ${probability * 100}%"></div>
173
  </div>
174
- <span>${(probability * 100).toFixed(2)}%</span>
175
  </div>`;
176
  }
177
  });
178
  }
179
 
180
- // Define your labels
181
- const medicalLabels = [
182
- 'Tumor',
183
- 'Normal',
184
- 'Pneumonia',
185
- 'Fracture',
186
- 'Edema',
187
- 'Effusion',
188
- 'Urtikaria',
189
- 'Eczema',
190
- 'Psoriasis'
191
- // Add as many labels as you need
192
- ];
193
-
194
- // Function to generate label checkboxes
195
- function generateLabelCheckboxes() {
196
- const labelGrid = document.getElementById('labelGrid');
197
- labelGrid.innerHTML = ''; // Clear existing labels
198
-
199
- medicalLabels.forEach(label => {
200
- const labelElement = document.createElement('label');
201
- labelElement.className = 'label-option';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
 
203
- labelElement.innerHTML = `
204
- <input type="checkbox" value="${label}">
205
- <span>${label}</span>
206
- `;
207
 
208
- labelGrid.appendChild(labelElement);
209
- });
210
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  radio.addEventListener('change', toggleInputMethod);
6
  });
7
 
8
+ // Initialize the search and labels functionality
9
+ initializeSearchAndLabels();
10
  });
11
 
12
  function toggleInputMethod() {
 
58
  const fileInput = document.getElementById('fileInput');
59
  const urlInput = document.getElementById('urlInput');
60
  const imagePreview = document.getElementById('imagePreview');
61
+ const defaultPreviewMessage = document.getElementById('defaultPreviewMessage');
62
 
63
  if (fileInput.files && fileInput.files[0]) {
64
  const reader = new FileReader();
65
  reader.onload = function(e) {
66
  imagePreview.src = e.target.result;
67
+ imagePreview.style.display = 'block'; // Show the image
68
+ defaultPreviewMessage.style.display = 'none'; // Hide the default message
69
  };
70
  reader.readAsDataURL(fileInput.files[0]);
71
  urlInput.value = ''; // Clear URL input
72
  } else if (urlInput.value) {
73
  imagePreview.src = urlInput.value;
74
+ imagePreview.style.display = 'block'; // Show the image
75
+ defaultPreviewMessage.style.display = 'none'; // Hide the default message
76
  fileInput.value = ''; // Clear file input
77
+ } else {
78
+ // If no image is loaded, show the default message
79
+ imagePreview.style.display = 'none'; // Hide the image
80
+ defaultPreviewMessage.style.display = 'block'; // Show the default message
81
  }
82
  }
83
 
 
112
  let base64Image;
113
 
114
  try {
115
+ // Get selected labels from both default checkboxes and selected labels container
116
+ const defaultLabels = Array.from(document.querySelectorAll('.default-labels input[type="checkbox"]:checked'))
117
  .map(checkbox => checkbox.value);
118
+
119
+ const selectedLabels = Array.from(document.querySelectorAll('#selectedLabels .selected-label'))
120
+ .map(label => label.dataset.label);
121
+
122
+ // Combine both sets of labels
123
+ const allSelectedLabels = [...defaultLabels, ...selectedLabels];
124
 
125
+ if (allSelectedLabels.length === 0) {
126
  throw new Error('Please select at least one category');
127
  }
128
 
 
144
 
145
  const payload = {
146
  images: [base64Image],
147
+ labels: allSelectedLabels,
148
  multilabel: false
149
  };
150
 
 
180
  predictions.forEach(prediction => {
181
  resultsDiv.innerHTML += '<h2>Results:</h2>';
182
  for (const [label, probability] of Object.entries(prediction)) {
183
+ const percentage = (probability * 100).toFixed(1);
184
  resultsDiv.innerHTML += `
185
  <div class="prediction-result">
186
+ <strong>${label}:</strong>
187
  <div class="progress-bar">
188
+ <div class="progress" style="width: ${percentage}%"></div>
189
  </div>
190
+ <span>${percentage}%</span>
191
  </div>`;
192
  }
193
  });
194
  }
195
 
196
+ // Define your labels with categories
197
+ const medicalLabels = {
198
+ 'Others': ['Effusion', 'Edema', 'Scar Tissue', 'Calcification'],
199
+ 'Pulmonology': ['Pneumonia', 'Asthma', 'COPD', 'Tuberculosis', 'Pulmonary Fibrosis', 'Pleural Effusion', 'Pulmonary Edema', 'Lung Nodule', 'Atelectasis', 'Pneumothorax'],
200
+ 'Oncology': ['Tumor', 'Breast Cancer', 'Lung Cancer', 'Prostate Cancer', 'Leukemia', 'Lymphoma', 'Melanoma', 'Colorectal Cancer', 'Glioma', 'Metastasis'],
201
+ 'Orthopedics': ['Fracture', 'Arthritis', 'Osteoporosis', 'Scoliosis', 'Tendonitis', 'Joint Effusion', 'Disc Herniation', 'Osteomyelitis', 'Bursitis', 'Bone Lesion'],
202
+ 'Cardiology': ['Myocardial Infarction', 'Arrhythmia', 'Heart Failure', 'Cardiomegaly', 'Aortic Aneurysm', 'Valvular Heart Disease', 'Coronary Artery Disease', 'Pericardial Effusion', 'Pulmonary Embolism'],
203
+ 'Dermatology': ['Urtikaria', 'Akne', 'Eczema', 'Psoriasis', 'Melanoma', 'Basal Cell Carcinoma', 'Squamous Cell Carcinoma', 'Skin Ulcer', 'Rash'],
204
+ 'Gastroenterology': ['Cirrhosis', 'Hepatitis', 'Ulcer', 'Gastric Cancer', 'Polyp', 'Pancreatitis', 'Cholecystitis', 'Colitis', 'Crohn’s Disease'],
205
+ 'Neurology': ['Stroke', 'Multiple Sclerosis', 'Parkinson’s Disease', 'Alzheimer’s Disease', 'Epilepsy', 'Brain Tumor', 'Hydrocephalus', 'Meningitis', 'Intracranial Hemorrhage'],
206
+ 'Endocrinology': ['Diabetes', 'Thyroid Nodule', 'Goiter', 'Adrenal Tumor', 'Pituitary Adenoma', 'Hyperthyroidism', 'Hypothyroidism', 'Parathyroid Hyperplasia'],
207
+ 'Hematology': ['Anemia', 'Thrombocytopenia', 'Leukemia', 'Lymphoma', 'Hemophilia', 'Polycythemia', 'Sickle Cell Disease'],
208
+ 'Urology': ['Kidney Stone', 'Bladder Cancer', 'Prostate Cancer', 'Urinary Tract Infection', 'Renal Cyst', 'Hydronephrosis'],
209
+ 'Ophthalmology': ['Glaucoma', 'Cataract', 'Retinal Detachment', 'Macular Degeneration', 'Diabetic Retinopathy', 'Conjunctivitis'],
210
+ 'Gynecology': ['Ovarian Cyst', 'Fibroids', 'Endometriosis', 'Breast Cancer', 'Polycystic Ovary Syndrome', 'Cervical Cancer'],
211
+ 'Rheumatology': ['Rheumatoid Arthritis', 'Lupus', 'Scleroderma', 'Ankylosing Spondylitis', 'Gout', 'Sjogren’s Syndrome']
212
+ // Add more categories and labels as needed
213
+ };
214
+
215
+ function initializeSearchAndLabels() {
216
+ // First, remove any existing search containers to prevent duplicates
217
+ const existingSearchContainers = document.querySelectorAll('.search-container');
218
+ existingSearchContainers.forEach(container => container.remove());
219
+
220
+ // Create search container with show all button
221
+ const searchContainer = document.createElement('div');
222
+ searchContainer.className = 'search-container';
223
+ searchContainer.innerHTML = `
224
+ <div class="search-wrapper">
225
+ <input type="text" id="labelSearch" class="search-input" placeholder="Search labels...">
226
+ <button id="showAllLabels" class="show-all-btn">Show All</button>
227
+ </div>
228
+ <div id="labelDropdown" class="label-dropdown" style="display: none;"></div>
229
+ `;
230
+
231
+ // Insert the search container after the default labels
232
+ const defaultLabels = document.querySelector('.default-labels');
233
+ if (defaultLabels) {
234
+ defaultLabels.parentNode.insertBefore(searchContainer, defaultLabels.nextElementSibling);
235
+ }
236
+
237
+ // Set up event listeners
238
+ const searchInput = document.getElementById('labelSearch');
239
+ const labelDropdown = document.getElementById('labelDropdown');
240
+ const showAllButton = document.getElementById('showAllLabels');
241
+
242
+ // Show dropdown on focus
243
+ searchInput.addEventListener('focus', () => {
244
+ const searchTerm = searchInput.value.trim().toLowerCase();
245
+ showFilteredResults(searchTerm);
246
+ });
247
+
248
+ // Handle input changes
249
+ searchInput.addEventListener('input', (e) => {
250
+ const searchTerm = e.target.value.trim().toLowerCase();
251
+ if (searchTerm) {
252
+ showFilteredResults(searchTerm);
253
+ } else {
254
+ labelDropdown.style.display = 'none';
255
+ }
256
+ });
257
+
258
+ // Show all button click handler
259
+ showAllButton.addEventListener('click', function(e) {
260
+ e.stopPropagation(); // Prevent event from bubbling up
261
+ labelDropdown.style.display = 'block';
262
+ showFilteredResults('');
263
+ searchInput.value = '';
264
+ });
265
+
266
+ // Close dropdown when clicking outside
267
+ document.addEventListener('click', (e) => {
268
+ if (!searchInput.contains(e.target) &&
269
+ !labelDropdown.contains(e.target) &&
270
+ !showAllButton.contains(e.target)) {
271
+ labelDropdown.style.display = 'none';
272
+ }
273
+ });
274
+ }
275
+
276
+ function showFilteredResults(searchTerm) {
277
+ const labelDropdown = document.getElementById('labelDropdown');
278
+ labelDropdown.innerHTML = '';
279
+ let hasResults = false;
280
+
281
+ // Sort categories alphabetically for better organization
282
+ const sortedCategories = Object.entries(medicalLabels).sort((a, b) => a[0].localeCompare(b[0]));
283
+
284
+ // Loop through all medical labels
285
+ sortedCategories.forEach(([category, labels]) => {
286
+ // Always show all labels when searchTerm is empty (Show All button clicked)
287
+ // Otherwise, filter based on search term
288
+ const matchingLabels = searchTerm === '' ?
289
+ labels.sort() : // Sort labels alphabetically
290
+ labels.filter(label => label.toLowerCase().includes(searchTerm.toLowerCase()));
291
+
292
+ if (matchingLabels.length > 0) {
293
+ hasResults = true;
294
+
295
+ // Add category header
296
+ const categoryHeader = document.createElement('div');
297
+ categoryHeader.className = 'dropdown-category-header';
298
+ categoryHeader.textContent = category;
299
+ labelDropdown.appendChild(categoryHeader);
300
+
301
+ // Add labels
302
+ matchingLabels.forEach(label => {
303
+ const option = document.createElement('div');
304
+ option.className = 'dropdown-option';
305
+
306
+ const checkbox = document.createElement('input');
307
+ checkbox.type = 'checkbox';
308
+ checkbox.id = `${category}-${label}`;
309
+ checkbox.checked = isLabelSelected(category, label);
310
+ checkbox.addEventListener('change', () => updateSelectedLabels(category, label));
311
+
312
+ const labelText = document.createElement('span');
313
+ labelText.className = 'label-text';
314
+ labelText.textContent = label;
315
+
316
+ const categoryBadge = document.createElement('span');
317
+ categoryBadge.className = 'category-badge';
318
+ categoryBadge.textContent = category;
319
+
320
+ option.appendChild(checkbox);
321
+ option.appendChild(labelText);
322
+ option.appendChild(categoryBadge);
323
+ labelDropdown.appendChild(option);
324
+ });
325
+ }
326
+ });
327
+
328
+ labelDropdown.style.display = hasResults || searchTerm === '' ? 'block' : 'none';
329
+ }
330
+
331
+ function isLabelSelected(category, label) {
332
+ const selectedLabelsContainer = document.getElementById('selectedLabels');
333
+ return !!selectedLabelsContainer.querySelector(
334
+ `[data-category="${category}"][data-label="${label}"]`
335
+ );
336
+ }
337
+
338
+ function updateSelectedLabels(category, label) {
339
+ const selectedLabelsContainer = document.getElementById('selectedLabels');
340
+ const checkbox = document.getElementById(`${category}-${label}`);
341
+
342
+ if (checkbox.checked) {
343
+ const labelElement = document.createElement('span');
344
+ labelElement.className = 'selected-label';
345
+ labelElement.textContent = `${label}`;
346
+ labelElement.dataset.category = category;
347
+ labelElement.dataset.label = label;
348
 
349
+ const categoryBadge = document.createElement('span');
350
+ categoryBadge.className = 'category-badge';
351
+ categoryBadge.textContent = category;
 
352
 
353
+ const removeButton = document.createElement('span');
354
+ removeButton.className = 'remove-label';
355
+ removeButton.innerHTML = '×';
356
+ removeButton.onclick = () => {
357
+ labelElement.remove();
358
+ checkbox.checked = false;
359
+ };
360
+
361
+ labelElement.appendChild(categoryBadge);
362
+ labelElement.appendChild(removeButton);
363
+ selectedLabelsContainer.appendChild(labelElement);
364
+ } else {
365
+ const existingLabel = selectedLabelsContainer.querySelector(
366
+ `[data-category="${category}"][data-label="${label}"]`
367
+ );
368
+ if (existingLabel) {
369
+ existingLabel.remove();
370
+ }
371
+ }
372
+ }
373
+
374
+ // Initialize when DOM is loaded
375
+ document.addEventListener('DOMContentLoaded', initializeSearchAndLabels);
376
+
styles.css CHANGED
@@ -58,7 +58,17 @@ input[type="text"]:focus {
58
  }
59
 
60
  .label-section {
61
- margin-bottom: 30px;
 
 
 
 
 
 
 
 
 
 
62
  }
63
 
64
  .label-grid {
@@ -86,27 +96,138 @@ input[type="text"]:focus {
86
  margin-right: 10px;
87
  }
88
 
89
- .preview-section {
90
- position: relative;
91
- text-align: center;
92
- margin: 30px 0;
93
- min-height: 200px;
94
- border: 2px dashed #e0e0e0;
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  border-radius: 12px;
96
- padding: 20px;
 
97
  }
98
 
99
- #imagePreview {
100
- max-width: 100%;
101
- max-height: 400px;
102
- border-radius: 8px;
 
 
 
 
103
  }
104
 
105
- button {
 
 
 
 
 
 
 
 
 
 
 
106
  width: 100%;
107
- padding: 15px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  background-color: #1a73e8;
109
- color: #fff;
110
  border: none;
111
  border-radius: 8px;
112
  font-size: 16px;
@@ -115,74 +236,137 @@ button {
115
  transition: background-color 0.3s;
116
  }
117
 
118
- button:hover {
119
- background-color: #1565c0;
120
  }
121
 
122
- .results-section {
123
- margin-top: 20px;
124
- padding: 10px;
125
- background-color: #e9ecef;
126
- border-radius: 4px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  }
128
 
 
129
  .prediction-result {
130
  margin: 10px 0;
131
  padding: 10px;
132
- background: #f8f9fa;
133
- border-radius: 4px;
134
  }
135
 
136
  .progress-bar {
137
- width: 100%;
138
- height: 20px;
139
- background: #e9ecef;
140
- border-radius: 10px;
141
- margin: 5px 0;
142
  overflow: hidden;
 
 
 
143
  }
144
 
145
  .progress {
146
  height: 100%;
147
- background: #007bff;
148
  transition: width 0.3s ease;
149
  }
150
 
151
- .error-message {
152
- color: #dc3545;
153
- background-color: #f8d7da;
154
- border: 1px solid #f5c6cb;
155
- padding: 10px;
156
- border-radius: 4px;
157
  margin: 10px 0;
158
  }
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  .input-method-selection {
161
  margin-bottom: 20px;
162
- display: flex;
163
- gap: 20px;
164
  }
165
 
166
  .radio-label {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
167
  display: flex;
 
168
  align-items: center;
169
- gap: 8px;
170
- cursor: pointer;
171
- padding: 8px 16px;
172
- border: 2px solid #e0e0e0;
173
- border-radius: 8px;
174
- transition: all 0.3s;
175
  }
176
 
177
- .radio-label:hover {
178
- border-color: #1a73e8;
179
  }
180
 
181
- .radio-label input[type="radio"] {
182
- margin: 0;
 
 
 
 
 
 
 
183
  }
184
 
185
- .radio-label input[type="radio"]:checked + .radio-label {
186
- border-color: #1a73e8;
187
- background-color: #f0f7ff;
188
- }
 
 
 
 
 
 
 
 
58
  }
59
 
60
  .label-section {
61
+ margin: 20px 0;
62
+ }
63
+
64
+ .label-category {
65
+ margin-bottom: 20px;
66
+ }
67
+
68
+ .label-category h3 {
69
+ margin-bottom: 10px;
70
+ font-size: 18px;
71
+ color: #1a73e8;
72
  }
73
 
74
  .label-grid {
 
96
  margin-right: 10px;
97
  }
98
 
99
+ .selected-labels-container {
100
+ margin: 20px 0;
101
+ padding: 10px;
102
+ background-color: #f8f9fa;
103
+ border: 1px solid #ddd;
104
+ border-radius: 8px;
105
+ }
106
+
107
+ .selected-labels-container h3 {
108
+ margin: 0 0 10px;
109
+ font-size: 16px;
110
+ color: #1a73e8;
111
+ }
112
+
113
+ .selected-label {
114
+ display: inline-block;
115
+ margin: 4px;
116
+ padding: 5px 10px;
117
+ background-color: #e0f7fa;
118
  border-radius: 12px;
119
+ font-size: 14px;
120
+ color: #00796b;
121
  }
122
 
123
+ .selected-labels-container p {
124
+ color: #666;
125
+ }
126
+
127
+ .default-labels {
128
+ display: flex;
129
+ gap: 10px;
130
+ padding: 2px; /* Smaller padding */
131
  }
132
 
133
+ .default-labels .label-option {
134
+ padding: 2px 5px; /* Smaller padding for individual labels */
135
+ border: 1px solid #ccc;
136
+ border-radius: 4px;
137
+ }
138
+
139
+ .search-container {
140
+ position: relative;
141
+ margin: 20px 0;
142
+ }
143
+
144
+ .search-input {
145
  width: 100%;
146
+ padding: 12px;
147
+ border: 2px solid #e0e0e0;
148
+ border-radius: 8px;
149
+ font-size: 16px;
150
+ }
151
+
152
+ .search-input:focus {
153
+ border-color: #1a73e8;
154
+ outline: none;
155
+ }
156
+
157
+ .label-dropdown {
158
+ position: absolute;
159
+ top: 100%;
160
+ left: 0;
161
+ right: 0;
162
+ background: white;
163
+ border: 1px solid #e0e0e0;
164
+ border-radius: 8px;
165
+ max-height: 400px;
166
+ overflow-y: auto;
167
+ z-index: 1000;
168
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
169
+ }
170
+
171
+ .dropdown-option {
172
+ padding: 8px 12px 8px 24px;
173
+ display: flex;
174
+ align-items: center;
175
+ gap: 12px;
176
+ cursor: pointer;
177
+ border-bottom: 1px solid #f0f0f0;
178
+ }
179
+
180
+ .dropdown-option:hover {
181
+ background-color: #f8f9fa;
182
+ }
183
+
184
+ .dropdown-option:last-child {
185
+ border-bottom: none;
186
+ }
187
+
188
+ .label-text {
189
+ flex: 1;
190
+ }
191
+
192
+ .category-badge {
193
+ background-color: #e8f0fe;
194
+ color: #1a73e8;
195
+ padding: 2px 8px;
196
+ border-radius: 12px;
197
+ font-size: 12px;
198
+ }
199
+
200
+ .selected-label {
201
+ display: inline-flex;
202
+ align-items: center;
203
+ gap: 8px;
204
+ background-color: #e8f0fe;
205
+ border: 1px solid #1a73e8;
206
+ border-radius: 16px;
207
+ padding: 4px 12px;
208
+ margin: 4px;
209
+ font-size: 14px;
210
+ }
211
+
212
+ .remove-label {
213
+ cursor: pointer;
214
+ color: #1a73e8;
215
+ font-weight: bold;
216
+ padding-left: 4px;
217
+ }
218
+
219
+ .remove-label:hover {
220
+ color: #1557b0;
221
+ }
222
+
223
+ /* Analyze Button */
224
+ #analyzeBtn {
225
+ display: block;
226
+ width: 200px;
227
+ margin: 20px auto;
228
+ padding: 12px 24px;
229
  background-color: #1a73e8;
230
+ color: white;
231
  border: none;
232
  border-radius: 8px;
233
  font-size: 16px;
 
236
  transition: background-color 0.3s;
237
  }
238
 
239
+ #analyzeBtn:hover {
240
+ background-color: #1557b0;
241
  }
242
 
243
+ #analyzeBtn:disabled {
244
+ background-color: #ccc;
245
+ cursor: not-allowed;
246
+ }
247
+
248
+ /* Image Preview */
249
+ .preview-section {
250
+ margin: 20px 0;
251
+ text-align: center;
252
+ display: flex;
253
+ flex-direction: column;
254
+ align-items: center;
255
+ }
256
+
257
+ #imagePreview {
258
+ max-width: 100%;
259
+ max-height: 400px;
260
+ object-fit: contain;
261
+ margin: 0 auto;
262
  }
263
 
264
+ /* Results Section */
265
  .prediction-result {
266
  margin: 10px 0;
267
  padding: 10px;
268
+ background-color: #f8f9fa;
269
+ border-radius: 8px;
270
  }
271
 
272
  .progress-bar {
273
+ height: 24px;
274
+ background-color: #e0e0e0;
275
+ border-radius: 12px;
 
 
276
  overflow: hidden;
277
+ margin: 8px 0;
278
+ flex-grow: 1;
279
+ margin-right: 10px;
280
  }
281
 
282
  .progress {
283
  height: 100%;
284
+ background-color: #1a73e8;
285
  transition: width 0.3s ease;
286
  }
287
 
288
+ .prediction-result {
289
+ display: flex;
290
+ align-items: center;
291
+ gap: 10px;
 
 
292
  margin: 10px 0;
293
  }
294
 
295
+ .prediction-result strong {
296
+ min-width: 120px;
297
+ }
298
+
299
+ .prediction-result span {
300
+ min-width: 80px;
301
+ text-align: right;
302
+ }
303
+
304
+ .results-section h2 {
305
+ color: #1a73e8;
306
+ font-size: 20px;
307
+ margin: 20px 0 15px;
308
+ }
309
+
310
+ /* Add spacing after radio buttons */
311
  .input-method-selection {
312
  margin-bottom: 20px;
 
 
313
  }
314
 
315
  .radio-label {
316
+ margin-right: 15px;
317
+ }
318
+
319
+ /* Style the results section to always show */
320
+ .results-section {
321
+ min-height: 100px;
322
+ padding: 15px;
323
+ background-color: #f8f9fa;
324
+ border-radius: 8px;
325
+ margin-top: 20px;
326
+ }
327
+
328
+ .results-section:empty::before {
329
+ content: 'Analysis results will appear here';
330
+ color: #666;
331
+ font-style: italic;
332
+ }
333
+
334
+ .helper-text {
335
+ color: #666;
336
+ font-size: 0.9em;
337
+ margin: 8px 0;
338
+ font-style: italic;
339
+ }
340
+
341
+ .search-wrapper {
342
  display: flex;
343
+ gap: 10px;
344
  align-items: center;
 
 
 
 
 
 
345
  }
346
 
347
+ .search-input {
348
+ flex: 1;
349
  }
350
 
351
+ .show-all-btn {
352
+ padding: 12px 20px;
353
+ background-color: #1a73e8;
354
+ color: white;
355
+ border: none;
356
+ border-radius: 8px;
357
+ cursor: pointer;
358
+ font-size: 14px;
359
+ white-space: nowrap;
360
  }
361
 
362
+ .show-all-btn:hover {
363
+ background-color: #1557b0;
364
+ }
365
+
366
+ .dropdown-category-header {
367
+ padding: 8px 12px;
368
+ background-color: #f0f2f5;
369
+ font-weight: bold;
370
+ color: #1a73e8;
371
+ border-bottom: 1px solid #e0e0e0;
372
+ }