itsLu commited on
Commit
79be0b0
·
verified ·
1 Parent(s): a5b01e6

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +197 -64
templates/index.html CHANGED
@@ -59,6 +59,28 @@
59
  cursor: pointer;
60
  }
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  main {
63
  display: grid;
64
  grid-template-columns: 1.2fr 1fr;
@@ -66,6 +88,10 @@
66
  padding: 0 28px 28px;
67
  }
68
 
 
 
 
 
69
  .card {
70
  background: var(--card);
71
  border: 1px solid var(--border);
@@ -75,15 +101,7 @@
75
 
76
  h2 { margin-top: 0; }
77
 
78
- .upload-box {
79
- border: 2px dashed var(--border);
80
- border-radius: 12px;
81
- padding: 20px;
82
- text-align: center;
83
- margin-top: 12px;
84
- }
85
-
86
- select, button {
87
  padding: 8px 12px;
88
  border-radius: 8px;
89
  border: 1px solid var(--border);
@@ -98,120 +116,234 @@
98
  cursor: pointer;
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  .team {
102
  display: grid;
103
- grid-template-columns: 1fr 1fr;
104
- gap: 12px;
 
105
  }
106
 
107
  .member {
108
  display: flex;
109
  align-items: center;
110
- gap: 10px;
111
  }
112
 
113
  .member img {
114
- width: 40px;
115
- height: 40px;
116
  border-radius: 50%;
117
  object-fit: cover;
118
- }
119
-
120
- .examples img {
121
- width: 100%;
122
- border-radius: 12px;
123
- margin-top: 8px;
124
  }
125
 
126
  footer {
127
- padding: 12px 28px;
128
- font-size: 12px;
129
  color: var(--muted);
 
130
  }
131
  </style>
132
  </head>
133
 
134
  <body>
 
135
  <header>
136
  <div class="brand">
137
- <img src="{{ url_for('static', filename='assets/brain/brain.svg') }}" alt="NeuraScan">
138
  <div>
139
  <strong>NeuraScan</strong><br>
140
  <small class="muted">AI-assisted MRI screening (demo)</small>
141
  </div>
142
  </div>
143
- <button id="themeToggle" class="chip">Light</button>
144
  </header>
145
 
146
- <main>
147
- <div class="card">
148
- <h2>New scan</h2>
 
149
 
150
- <label>Model</label><br>
151
- <select id="modelSelect"></select><br><br>
 
 
 
152
 
153
- <input type="file" id="fileInput" accept="image/*"><br><br>
 
154
 
155
- <button class="primary">Run scan</button>
 
156
 
157
- <div class="upload-box">
158
- Drag & drop, paste (Ctrl+V), or upload an MRI image
159
- </div>
160
- </div>
161
-
162
- <div class="card">
163
- <h2>Examples</h2>
164
- <div class="examples">
165
- <img src="{{ url_for('static', filename='assets/brain/supportedexample.jpg') }}">
166
- <img src="{{ url_for('static', filename='assets/brain/unsupportedexample.jpg') }}">
167
- </div>
168
 
169
- <h2 style="margin-top:20px;">Team</h2>
170
- <div class="team">
171
- <div class="member">
172
- <img src="{{ url_for('static', filename='assets/images/team/asem.jpg') }}">
173
- <div>Asem<br><small>ML / Deployment</small></div>
174
  </div>
175
- <div class="member">
176
- <img src="{{ url_for('static', filename='assets/images/team/sameh.jpg') }}">
177
- <div>Sameh<br><small>ML / Research</small></div>
 
 
 
 
178
  </div>
179
- <div class="member">
180
- <img src="{{ url_for('static', filename='assets/images/team/fatma.jpg') }}">
181
- <div>Fatma<br><small>Data / QA</small></div>
 
 
 
 
182
  </div>
183
- <div class="member">
184
- <img src="{{ url_for('static', filename='assets/images/team/gehad.jpg') }}">
185
- <div>Gehad<br><small>Frontend</small></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  </div>
187
  </div>
188
- </div>
189
- </main>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
 
191
  <footer>
192
- This is an educational demo and not medical advice.
 
 
193
  </footer>
194
 
195
  <script>
 
 
 
 
 
 
 
 
196
  async function loadModels() {
197
  const res = await fetch("/api/models");
198
- const models = await res.json();
199
  const select = document.getElementById("modelSelect");
200
  select.innerHTML = "";
201
- models.forEach(m => {
 
202
  const opt = document.createElement("option");
203
  opt.value = m.id;
204
  opt.textContent = m.name;
205
- if (!m.available) opt.disabled = true;
206
  select.appendChild(opt);
207
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
 
210
  function setTheme(theme) {
211
  document.documentElement.dataset.theme = theme;
212
  localStorage.setItem("theme", theme);
213
- document.getElementById("themeToggle").textContent =
214
- theme === "dark" ? "Light" : "Dark";
215
  }
216
 
217
  document.getElementById("themeToggle").onclick = () => {
@@ -222,5 +354,6 @@
222
  setTheme(localStorage.getItem("theme") || "dark");
223
  loadModels();
224
  </script>
 
225
  </body>
226
  </html>
 
59
  cursor: pointer;
60
  }
61
 
62
+ nav {
63
+ padding: 0 28px 20px;
64
+ display: flex;
65
+ gap: 10px;
66
+ }
67
+
68
+ .tab {
69
+ border: 1px solid var(--border);
70
+ background: transparent;
71
+ color: var(--text);
72
+ padding: 6px 14px;
73
+ border-radius: 999px;
74
+ cursor: pointer;
75
+ }
76
+
77
+ .tab.active {
78
+ background: rgba(79,124,255,.15);
79
+ }
80
+
81
+ .section { display: none; }
82
+ .section.show { display: block; }
83
+
84
  main {
85
  display: grid;
86
  grid-template-columns: 1.2fr 1fr;
 
88
  padding: 0 28px 28px;
89
  }
90
 
91
+ @media (max-width: 900px) {
92
+ main { grid-template-columns: 1fr; }
93
+ }
94
+
95
  .card {
96
  background: var(--card);
97
  border: 1px solid var(--border);
 
101
 
102
  h2 { margin-top: 0; }
103
 
104
+ select, button, input {
 
 
 
 
 
 
 
 
105
  padding: 8px 12px;
106
  border-radius: 8px;
107
  border: 1px solid var(--border);
 
116
  cursor: pointer;
117
  }
118
 
119
+ .upload-box {
120
+ border: 2px dashed var(--border);
121
+ border-radius: 12px;
122
+ padding: 20px;
123
+ text-align: center;
124
+ margin-top: 12px;
125
+ color: var(--muted);
126
+ }
127
+
128
+ .preview {
129
+ margin-top: 12px;
130
+ background: black;
131
+ border-radius: 12px;
132
+ overflow: hidden;
133
+ max-height: 360px;
134
+ }
135
+
136
+ .preview img {
137
+ width: 100%;
138
+ height: 100%;
139
+ max-height: 360px;
140
+ object-fit: contain;
141
+ display: block;
142
+ }
143
+
144
+ .result {
145
+ margin-top: 14px;
146
+ }
147
+
148
+ .result-title {
149
+ font-size: 22px;
150
+ font-weight: 700;
151
+ }
152
+
153
+ .result-msg {
154
+ color: var(--muted);
155
+ }
156
+
157
+ .examples img {
158
+ width: 100%;
159
+ max-height: 300px;
160
+ object-fit: contain;
161
+ background: black;
162
+ border-radius: 12px;
163
+ margin-top: 8px;
164
+ }
165
+
166
  .team {
167
  display: grid;
168
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
169
+ gap: 14px;
170
+ margin-top: 12px;
171
  }
172
 
173
  .member {
174
  display: flex;
175
  align-items: center;
176
+ gap: 12px;
177
  }
178
 
179
  .member img {
180
+ width: 48px;
181
+ height: 48px;
182
  border-radius: 50%;
183
  object-fit: cover;
184
+ cursor: pointer;
 
 
 
 
 
185
  }
186
 
187
  footer {
188
+ padding: 12px 28px 24px;
189
+ font-size: 13px;
190
  color: var(--muted);
191
+ border-top: 1px solid var(--border);
192
  }
193
  </style>
194
  </head>
195
 
196
  <body>
197
+
198
  <header>
199
  <div class="brand">
200
+ <img src="{{ url_for('static', filename='assets/brain/brain.svg') }}">
201
  <div>
202
  <strong>NeuraScan</strong><br>
203
  <small class="muted">AI-assisted MRI screening (demo)</small>
204
  </div>
205
  </div>
206
+ <button id="themeToggle" class="chip">☀️</button>
207
  </header>
208
 
209
+ <nav>
210
+ <button class="tab active" onclick="showSection('scan', this)">Scan</button>
211
+ <button class="tab" onclick="showSection('info', this)">Info</button>
212
+ </nav>
213
 
214
+ <!-- SCAN -->
215
+ <section id="scan" class="section show">
216
+ <main>
217
+ <div class="card">
218
+ <h2>New scan</h2>
219
 
220
+ <label>Model</label><br>
221
+ <select id="modelSelect"></select><br><br>
222
 
223
+ <input type="file" id="fileInput" accept="image/*"><br><br>
224
+ <button class="primary" onclick="runScan()">Run scan</button>
225
 
226
+ <div class="upload-box">
227
+ Drag & drop, paste (Ctrl+V), or upload an MRI image
228
+ </div>
 
 
 
 
 
 
 
 
229
 
230
+ <div class="preview">
231
+ <img id="previewImg">
 
 
 
232
  </div>
233
+
234
+ <div class="result">
235
+ <div id="resultTitle" class="result-title"></div>
236
+ <div id="resultMsg" class="result-msg">Upload an image to begin.</div>
237
+ <button id="likelyBtn" style="display:none;margin-top:10px;" onclick="showLikely()">
238
+ Show most likely result
239
+ </button>
240
  </div>
241
+ </div>
242
+
243
+ <div class="card">
244
+ <h2>Examples</h2>
245
+ <div class="examples">
246
+ <img src="{{ url_for('static', filename='assets/brain/supportedexample.jpg') }}">
247
+ <img src="{{ url_for('static', filename='assets/brain/unsupportedexample.jpg') }}">
248
  </div>
249
+
250
+ <h2 style="margin-top:20px;">Team</h2>
251
+ <div class="team">
252
+ <div class="member">
253
+ <img src="{{ url_for('static', filename='assets/images/team/fatma.jpg') }}" onclick="window.open('https://www.linkedin.com/in/fatma-al-zahraa-emad-326b64234/')">
254
+ <span>Fatma Al-Zahraa Emad</span>
255
+ </div>
256
+ <div class="member">
257
+ <img src="{{ url_for('static', filename='assets/images/team/gehad.jpg') }}" onclick="window.open('https://www.linkedin.com/in/gehad-mohamed-2a4946252/')">
258
+ <span>Gehad Mohamed</span>
259
+ </div>
260
+ <div class="member">
261
+ <img src="{{ url_for('static', filename='assets/images/team/hebatullah.jpg') }}" onclick="window.open('https://www.linkedin.com/in/hebatullah-elgazoly-308ab2243/')">
262
+ <span>Hebatullah El Gazoly</span>
263
+ </div>
264
+ <div class="member">
265
+ <img src="{{ url_for('static', filename='assets/images/team/assem.jpg') }}" onclick="window.open('https://www.linkedin.com/in/mohamedasem318/')">
266
+ <span>Mohamed Assem</span>
267
+ </div>
268
+ <div class="member">
269
+ <img src="{{ url_for('static', filename='assets/images/team/sameh.jpg') }}" onclick="window.open('https://www.linkedin.com/in/muhamedsameh/')">
270
+ <span>Mohamed Sameh</span>
271
+ </div>
272
  </div>
273
  </div>
274
+ </main>
275
+ </section>
276
+
277
+ <!-- INFO -->
278
+ <section id="info" class="section">
279
+ <main>
280
+ <div class="card">
281
+ <h2>About NeuraScan</h2>
282
+ <p>
283
+ NeuraScan is a demo system for Alzheimer’s stage classification from MRI scans.
284
+ If model confidence is below a conservative threshold, the system reports
285
+ <b>Uncertain</b> instead of a potentially incorrect diagnosis.
286
+ </p>
287
+
288
+ <h2 style="margin-top:20px;">Under the supervision of:</h2>
289
+ <p>
290
+ Prof. Muhammad Sayed Hammad<br>
291
+ Eng. Heidi Ahmed
292
+ </p>
293
+ </div>
294
+ </main>
295
+ </section>
296
 
297
  <footer>
298
+ Contact: <a href="mailto:mohamedasem318@gmail.com">Mohamed Assem</a>
299
+ <a href="mailto:mohamed.sameh8103@gmail.com">Mohamed Sameh</a><br>
300
+ Educational demo — not medical advice
301
  </footer>
302
 
303
  <script>
304
+ function showSection(id, btn) {
305
+ document.querySelectorAll('.section').forEach(s => s.classList.remove('show'));
306
+ document.getElementById(id).classList.add('show');
307
+
308
+ document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
309
+ btn.classList.add('active');
310
+ }
311
+
312
  async function loadModels() {
313
  const res = await fetch("/api/models");
314
+ const data = await res.json();
315
  const select = document.getElementById("modelSelect");
316
  select.innerHTML = "";
317
+
318
+ data.models.forEach(m => {
319
  const opt = document.createElement("option");
320
  opt.value = m.id;
321
  opt.textContent = m.name;
 
322
  select.appendChild(opt);
323
  });
324
+
325
+ select.value = data.default_model_id;
326
+ }
327
+
328
+ document.getElementById("fileInput").addEventListener("change", e => {
329
+ const img = document.getElementById("previewImg");
330
+ img.src = URL.createObjectURL(e.target.files[0]);
331
+ });
332
+
333
+ function runScan() {
334
+ document.getElementById("resultTitle").textContent = "Uncertain";
335
+ document.getElementById("resultMsg").textContent = "Consult a professional.";
336
+ document.getElementById("likelyBtn").style.display = "inline-block";
337
+ }
338
+
339
+ function showLikely() {
340
+ alert("Most likely: Healthy");
341
  }
342
 
343
  function setTheme(theme) {
344
  document.documentElement.dataset.theme = theme;
345
  localStorage.setItem("theme", theme);
346
+ document.getElementById("themeToggle").textContent = theme === "dark" ? "☀️" : "🌙";
 
347
  }
348
 
349
  document.getElementById("themeToggle").onclick = () => {
 
354
  setTheme(localStorage.getItem("theme") || "dark");
355
  loadModels();
356
  </script>
357
+
358
  </body>
359
  </html>