Divytak commited on
Commit
9736186
·
verified ·
1 Parent(s): b90878f

Update src/BrainIAC/templates/index.html

Browse files
Files changed (1) hide show
  1. src/BrainIAC/templates/index.html +165 -7
src/BrainIAC/templates/index.html CHANGED
@@ -169,6 +169,38 @@
169
  color: #155724;
170
  border: 1px solid #c3e6cb;
171
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  </style>
173
  </head>
174
  <body>
@@ -194,7 +226,7 @@
194
  {% endif %}
195
  {% endwith %}
196
 
197
- <form method="post" action="{{ url_for('predict') }}" enctype="multipart/form-data" class="upload-form">
198
  <div class="file-type-selector">
199
  <label>Select file type:</label>
200
  <span>
@@ -230,26 +262,152 @@
230
  </div>
231
  {% endif %}
232
 
233
- {# Saliency Map Display Section #}
234
- {% if saliency_images %}
235
  <div class="saliency-results">
236
- <h2>Saliency Map Visualizations (Center Slice)</h2>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  <div class="saliency-plots">
238
  <div class="saliency-plot">
239
  <h4>Input Slice</h4>
240
- <img src="data:image/png;base64,{{ saliency_images.input_slice }}" alt="Input MRI Slice" width="200">
 
241
  </div>
242
  <div class="saliency-plot">
243
  <h4>Saliency Heatmap</h4>
244
- <img src="data:image/png;base64,{{ saliency_images.saliency_heatmap }}" alt="Saliency Heatmap" width="200">
 
245
  </div>
246
  <div class="saliency-plot">
247
  <h4>Overlay</h4>
248
- <img src="data:image/png;base64,{{ saliency_images.overlay }}" alt="Saliency Overlay" width="200">
 
249
  </div>
250
  </div>
251
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  {% endif %}
253
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  </body>
255
  </html>
 
169
  color: #155724;
170
  border: 1px solid #c3e6cb;
171
  }
172
+
173
+ /* Loading Indicator Styles */
174
+ #loading-indicator {
175
+ display: none; /* Hidden by default */
176
+ position: fixed;
177
+ top: 0;
178
+ left: 0;
179
+ width: 100%;
180
+ height: 100%;
181
+ background-color: rgba(255, 255, 255, 0.7); /* Semi-transparent white background */
182
+ z-index: 1000; /* Ensure it's on top */
183
+ justify-content: center;
184
+ align-items: center;
185
+ flex-direction: column; /* Stack spinner and text vertically */
186
+ }
187
+ .spinner {
188
+ border: 5px solid #f3f3f3; /* Light grey */
189
+ border-top: 5px solid #3498db; /* Blue */
190
+ border-radius: 50%;
191
+ width: 40px;
192
+ height: 40px;
193
+ animation: spin 1s linear infinite;
194
+ margin-bottom: 15px; /* Space between spinner and text */
195
+ }
196
+ @keyframes spin {
197
+ 0% { transform: rotate(0deg); }
198
+ 100% { transform: rotate(360deg); }
199
+ }
200
+ #loading-indicator p {
201
+ font-weight: bold;
202
+ color: #333;
203
+ }
204
  </style>
205
  </head>
206
  <body>
 
226
  {% endif %}
227
  {% endwith %}
228
 
229
+ <form method="post" action="{{ url_for('predict') }}" enctype="multipart/form-data" class="upload-form" onsubmit="showLoader()">
230
  <div class="file-type-selector">
231
  <label>Select file type:</label>
232
  <span>
 
262
  </div>
263
  {% endif %}
264
 
265
+ {# Saliency Map Display Section - Modified for Dynamic Loading #}
266
+ {% if saliency_info %}
267
  <div class="saliency-results">
268
+ <h2>Saliency Map Visualizations (Axial View)</h2>
269
+
270
+ {# Slice Slider and Label #}
271
+ <div class="slice-slider-container" style="margin-bottom: 20px; text-align: center;">
272
+ <label for="slice-slider">Slice: <span id="slice-number-label">{{ saliency_info.center_slice_index + 1 }}</span> / {{ saliency_info.num_slices }}</label><br>
273
+ {# Store unique_id AND temp_dir_path as data attributes #}
274
+ <input type="range" id="slice-slider"
275
+ min="0" max="{{ saliency_info.num_slices - 1 }}"
276
+ value="{{ saliency_info.center_slice_index }}"
277
+ style="width: 80%; margin-top: 5px;"
278
+ data-unique-id="{{ saliency_info.unique_id }}"
279
+ data-temp-path="{{ saliency_info.temp_dir_path }}">
280
+ <span id="slice-loading-indicator" style="display: none; margin-left: 10px;">Loading...</span> {# Small loading text #}
281
+ </div>
282
+
283
  <div class="saliency-plots">
284
  <div class="saliency-plot">
285
  <h4>Input Slice</h4>
286
+ {# Use initial center slice data #}
287
+ <img id="input-slice-img" src="data:image/png;base64,{{ saliency_info.center_slice_plots.input_slice }}" alt="Input MRI Slice" width="200">
288
  </div>
289
  <div class="saliency-plot">
290
  <h4>Saliency Heatmap</h4>
291
+ {# Use initial center slice data #}
292
+ <img id="heatmap-slice-img" src="data:image/png;base64,{{ saliency_info.center_slice_plots.heatmap_slice }}" alt="Saliency Heatmap" width="200">
293
  </div>
294
  <div class="saliency-plot">
295
  <h4>Overlay</h4>
296
+ {# Use initial center slice data #}
297
+ <img id="overlay-slice-img" src="data:image/png;base64,{{ saliency_info.center_slice_plots.overlay_slice }}" alt="Saliency Overlay" width="200">
298
  </div>
299
  </div>
300
  </div>
301
+
302
+ {# JavaScript for Slider Interaction with Fetch #}
303
+ <script>
304
+ // Get DOM elements
305
+ const slider = document.getElementById('slice-slider');
306
+ const sliceLabel = document.getElementById('slice-number-label');
307
+ const inputImg = document.getElementById('input-slice-img');
308
+ const heatmapImg = document.getElementById('heatmap-slice-img');
309
+ const overlayImg = document.getElementById('overlay-slice-img');
310
+ const loadingIndicator = document.getElementById('slice-loading-indicator');
311
+ // Get unique ID and TEMP PATH from data attributes
312
+ const uniqueId = slider.dataset.uniqueId;
313
+ const tempPath = slider.dataset.tempPath;
314
+ const totalSlices = parseInt(slider.max, 10) + 1;
315
+ let isLoading = false;
316
+ let debounceTimer;
317
+
318
+ // Function to fetch and update slice images
319
+ function updateSliceImages(sliceIndex) {
320
+ if (isLoading) return;
321
+ isLoading = true;
322
+ loadingIndicator.style.display = 'inline';
323
+
324
+ // Construct URL with path as a query parameter (URL-encoded)
325
+ const encodedPath = encodeURIComponent(tempPath);
326
+ const fetchUrl = `/get_slice/${uniqueId}/${sliceIndex}?path=${encodedPath}`;
327
+ console.log("Fetching:", fetchUrl);
328
+
329
+ fetch(fetchUrl)
330
+ .then(response => {
331
+ if (!response.ok) {
332
+ throw new Error(`HTTP error! status: ${response.status}`);
333
+ }
334
+ return response.json();
335
+ })
336
+ .then(data => {
337
+ // Log the received data for debugging
338
+ console.log("Received data:", data);
339
+ if (data.error) {
340
+ console.error("Error fetching slice:", data.error);
341
+ // Optionally display an error to the user
342
+ } else {
343
+ // Check if keys exist before assigning & log
344
+ if (data.input_slice) {
345
+ // PREPEND the Data URI prefix
346
+ inputImg.src = `data:image/png;base64,${data.input_slice}`;
347
+ console.log("Updated inputImg src");
348
+ } else {
349
+ console.error("input_slice key missing in response data");
350
+ }
351
+ if (data.heatmap_slice) {
352
+ // PREPEND the Data URI prefix
353
+ heatmapImg.src = `data:image/png;base64,${data.heatmap_slice}`;
354
+ console.log("Updated heatmapImg src");
355
+ } else {
356
+ console.error("heatmap_slice key missing in response data");
357
+ }
358
+ if (data.overlay_slice) {
359
+ // PREPEND the Data URI prefix
360
+ overlayImg.src = `data:image/png;base64,${data.overlay_slice}`;
361
+ console.log("Updated overlayImg src");
362
+ } else {
363
+ console.error("overlay_slice key missing in response data");
364
+ }
365
+ // Update label (display 1-based index)
366
+ sliceLabel.textContent = sliceIndex + 1;
367
+ }
368
+ })
369
+ .catch(error => {
370
+ // Catch network errors or errors thrown from .then(response => ...)
371
+ console.error('Error fetching or processing slice data:', error);
372
+ // Optionally display an error to the user
373
+ })
374
+ .finally(() => {
375
+ isLoading = false;
376
+ loadingIndicator.style.display = 'none'; // Hide loading indicator
377
+ });
378
+ }
379
+
380
+ // Add event listener to the slider with debouncing
381
+ slider.addEventListener('input', function() {
382
+ const sliceIndex = parseInt(this.value, 10);
383
+ sliceLabel.textContent = sliceIndex + 1; // Update label immediately
384
+
385
+ // Debounce the fetch call
386
+ clearTimeout(debounceTimer);
387
+ debounceTimer = setTimeout(() => {
388
+ if (sliceIndex >= 0 && sliceIndex < totalSlices) {
389
+ updateSliceImages(sliceIndex);
390
+ }
391
+ }, 150); // Adjust debounce time (ms) as needed
392
+ });
393
+
394
+ // Initial state is set by Jinja server-side
395
+ </script>
396
+
397
  {% endif %}
398
  </div>
399
+
400
+ <!-- Loading Indicator HTML -->
401
+ <div id="loading-indicator">
402
+ <div class="spinner"></div>
403
+ <p>Processing... Please wait.</p>
404
+ </div>
405
+
406
+ <script>
407
+ function showLoader() {
408
+ // Display the loading indicator using flex for centering
409
+ document.getElementById('loading-indicator').style.display = 'flex';
410
+ }
411
+ </script>
412
  </body>
413
  </html>