blackshadow1 commited on
Commit
50e0fe7
·
verified ·
1 Parent(s): d686388

updated the UI code ✅✅

Browse files
Files changed (1) hide show
  1. mediSync/app.py +46 -404
mediSync/app.py CHANGED
@@ -3,391 +3,6 @@ import os
3
  import sys
4
  import tempfile
5
  from pathlib import Path
6
-
7
- import gradio as gr
8
- import matplotlib.pyplot as plt
9
- from PIL import Image
10
-
11
- # Add parent directory to path
12
- parent_dir = os.path.dirname(os.path.abspath(__file__))
13
- sys.path.append(parent_dir)
14
-
15
- # Import our modules
16
- from models.multimodal_fusion import MultimodalFusion
17
- from utils.preprocessing import enhance_xray_image, normalize_report_text
18
- from utils.visualization import (
19
- plot_image_prediction,
20
- plot_multimodal_results,
21
- plot_report_entities,
22
- )
23
-
24
- # Set up logging
25
- logging.basicConfig(
26
- level=logging.INFO,
27
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
28
- handlers=[logging.StreamHandler(), logging.FileHandler("mediSync.log")],
29
- )
30
- logger = logging.getLogger(__name__)
31
-
32
- # Create temporary directory for sample data if it doesn't exist
33
- os.makedirs(os.path.join(parent_dir, "data", "sample"), exist_ok=True)
34
-
35
-
36
- # class MediSyncApp:
37
- # """
38
- # Main application class for the MediSync multi-modal medical analysis system.
39
- # """
40
-
41
- # def __init__(self):
42
- # """Initialize the application and load models."""
43
- # self.logger = logging.getLogger(__name__)
44
- # self.logger.info("Initializing MediSync application")
45
-
46
- # # Initialize models with None for lazy loading
47
- # self.fusion_model = None
48
- # self.image_model = None
49
- # self.text_model = None
50
-
51
- # def load_models(self):
52
- # """
53
- # Load models if not already loaded.
54
-
55
- # Returns:
56
- # bool: True if models loaded successfully, False otherwise
57
- # """
58
- # try:
59
- # if self.fusion_model is None:
60
- # self.logger.info("Loading models...")
61
- # self.fusion_model = MultimodalFusion()
62
- # self.image_model = self.fusion_model.image_analyzer
63
- # self.text_model = self.fusion_model.text_analyzer
64
- # self.logger.info("Models loaded successfully")
65
- # return True
66
-
67
- # except Exception as e:
68
- # self.logger.error(f"Error loading models: {e}")
69
- # return False
70
-
71
- # def analyze_image(self, image):
72
- # """
73
- # Analyze a medical image.
74
-
75
- # Args:
76
- # image: Image file uploaded through Gradio
77
-
78
- # Returns:
79
- # tuple: (image, image_results_html, plot_as_html)
80
- # """
81
- # try:
82
- # # Ensure models are loaded
83
- # if not self.load_models() or self.image_model is None:
84
- # return image, "Error: Models not loaded properly.", None
85
-
86
- # # Save uploaded image to a temporary file
87
- # temp_dir = tempfile.mkdtemp()
88
- # temp_path = os.path.join(temp_dir, "upload.png")
89
-
90
- # if isinstance(image, str):
91
- # # Copy the file if it's a path
92
- # from shutil import copyfile
93
-
94
- # copyfile(image, temp_path)
95
- # else:
96
- # # Save if it's a Gradio UploadButton image
97
- # image.save(temp_path)
98
-
99
- # # Run image analysis
100
- # self.logger.info(f"Analyzing image: {temp_path}")
101
- # results = self.image_model.analyze(temp_path)
102
-
103
- # # Create visualization
104
- # fig = plot_image_prediction(
105
- # image,
106
- # results.get("predictions", []),
107
- # f"Primary Finding: {results.get('primary_finding', 'Unknown')}",
108
- # )
109
-
110
- # # Convert to HTML for display
111
- # plot_html = self.fig_to_html(fig)
112
-
113
- # # Format results as HTML
114
- # html_result = f"""
115
- # <h2>X-ray Analysis Results</h2>
116
- # <p><strong>Primary Finding:</strong> {results.get("primary_finding", "Unknown")}</p>
117
- # <p><strong>Confidence:</strong> {results.get("confidence", 0):.1%}</p>
118
- # <p><strong>Abnormality Detected:</strong> {"Yes" if results.get("has_abnormality", False) else "No"}</p>
119
-
120
- # <h3>Top Predictions:</h3>
121
- # <ul>
122
- # """
123
-
124
- # # Add top 5 predictions
125
- # for label, prob in results.get("predictions", [])[:5]:
126
- # html_result += f"<li>{label}: {prob:.1%}</li>"
127
-
128
- # html_result += "</ul>"
129
-
130
- # # Add explanation
131
- # explanation = self.image_model.get_explanation(results)
132
- # html_result += f"<h3>Analysis Explanation:</h3><p>{explanation}</p>"
133
-
134
- # return image, html_result, plot_html
135
-
136
- # except Exception as e:
137
- # self.logger.error(f"Error in image analysis: {e}")
138
- # return image, f"Error analyzing image: {str(e)}", None
139
-
140
- # def analyze_text(self, text):
141
- # """
142
- # Analyze a medical report text.
143
-
144
- # Args:
145
- # text: Report text input through Gradio
146
-
147
- # Returns:
148
- # tuple: (text, text_results_html, entities_plot_html)
149
- # """
150
- # try:
151
- # # Ensure models are loaded
152
- # if not self.load_models() or self.text_model is None:
153
- # return text, "Error: Models not loaded properly.", None
154
-
155
- # # Check for empty text
156
- # if not text or len(text.strip()) < 10:
157
- # return (
158
- # text,
159
- # "Error: Please enter a valid medical report text (at least 10 characters).",
160
- # None,
161
- # )
162
-
163
- # # Normalize text
164
- # normalized_text = normalize_report_text(text)
165
-
166
- # # Run text analysis
167
- # self.logger.info("Analyzing medical report text")
168
- # results = self.text_model.analyze(normalized_text)
169
-
170
- # # Get entities and create visualization
171
- # entities = results.get("entities", {})
172
- # fig = plot_report_entities(normalized_text, entities)
173
-
174
- # # Convert to HTML for display
175
- # entities_plot_html = self.fig_to_html(fig)
176
-
177
- # # Format results as HTML
178
- # html_result = f"""
179
- # <h2>Medical Report Analysis Results</h2>
180
- # <p><strong>Severity Level:</strong> {results.get("severity", {}).get("level", "Unknown")}</p>
181
- # <p><strong>Severity Score:</strong> {results.get("severity", {}).get("score", 0)}/4</p>
182
- # <p><strong>Confidence:</strong> {results.get("severity", {}).get("confidence", 0):.1%}</p>
183
-
184
- # <h3>Key Findings:</h3>
185
- # <ul>
186
- # """
187
-
188
- # # Add findings
189
- # findings = results.get("findings", [])
190
- # if findings:
191
- # for finding in findings:
192
- # html_result += f"<li>{finding}</li>"
193
- # else:
194
- # html_result += "<li>No specific findings detailed.</li>"
195
-
196
- # html_result += "</ul>"
197
-
198
- # # Add entities
199
- # html_result += "<h3>Extracted Medical Entities:</h3>"
200
-
201
- # for category, items in entities.items():
202
- # if items:
203
- # html_result += f"<p><strong>{category.capitalize()}:</strong> {', '.join(items)}</p>"
204
-
205
- # # Add follow-up recommendations
206
- # html_result += "<h3>Follow-up Recommendations:</h3><ul>"
207
- # followups = results.get("followup_recommendations", [])
208
-
209
- # if followups:
210
- # for rec in followups:
211
- # html_result += f"<li>{rec}</li>"
212
- # else:
213
- # html_result += "<li>No specific follow-up recommendations.</li>"
214
-
215
- # html_result += "</ul>"
216
-
217
- # return text, html_result, entities_plot_html
218
-
219
- # except Exception as e:
220
- # self.logger.error(f"Error in text analysis: {e}")
221
- # return text, f"Error analyzing text: {str(e)}", None
222
-
223
- # def analyze_multimodal(self, image, text):
224
- # """
225
- # Perform multimodal analysis of image and text.
226
-
227
- # Args:
228
- # image: Image file uploaded through Gradio
229
- # text: Report text input through Gradio
230
-
231
- # Returns:
232
- # tuple: (results_html, multimodal_plot_html)
233
- # """
234
- # try:
235
- # # Ensure models are loaded
236
- # if not self.load_models() or self.fusion_model is None:
237
- # return "Error: Models not loaded properly.", None
238
-
239
- # # Check for empty inputs
240
- # if image is None:
241
- # return "Error: Please upload an X-ray image for analysis.", None
242
-
243
- # if not text or len(text.strip()) < 10:
244
- # return (
245
- # "Error: Please enter a valid medical report text (at least 10 characters).",
246
- # None,
247
- # )
248
-
249
- # # Save uploaded image to a temporary file
250
- # temp_dir = tempfile.mkdtemp()
251
- # temp_path = os.path.join(temp_dir, "upload.png")
252
-
253
- # if isinstance(image, str):
254
- # # Copy the file if it's a path
255
- # from shutil import copyfile
256
-
257
- # copyfile(image, temp_path)
258
- # else:
259
- # # Save if it's a Gradio UploadButton image
260
- # image.save(temp_path)
261
-
262
- # # Normalize text
263
- # normalized_text = normalize_report_text(text)
264
-
265
- # # Run multimodal analysis
266
- # self.logger.info("Performing multimodal analysis")
267
- # results = self.fusion_model.analyze(temp_path, normalized_text)
268
-
269
- # # Create visualization
270
- # fig = plot_multimodal_results(results, image, text)
271
-
272
- # # Convert to HTML for display
273
- # plot_html = self.fig_to_html(fig)
274
-
275
- # # Generate explanation
276
- # explanation = self.fusion_model.get_explanation(results)
277
-
278
- # # Format results as HTML
279
- # html_result = f"""
280
- # <h2>Multimodal Medical Analysis Results</h2>
281
-
282
- # <h3>Overview</h3>
283
- # <p><strong>Primary Finding:</strong> {results.get("primary_finding", "Unknown")}</p>
284
- # <p><strong>Severity Level:</strong> {results.get("severity", {}).get("level", "Unknown")}</p>
285
- # <p><strong>Severity Score:</strong> {results.get("severity", {}).get("score", 0)}/4</p>
286
- # <p><strong>Agreement Score:</strong> {results.get("agreement_score", 0):.0%}</p>
287
-
288
- # <h3>Detailed Findings</h3>
289
- # <ul>
290
- # """
291
-
292
- # # Add findings
293
- # findings = results.get("findings", [])
294
- # if findings:
295
- # for finding in findings:
296
- # html_result += f"<li>{finding}</li>"
297
- # else:
298
- # html_result += "<li>No specific findings detailed.</li>"
299
-
300
- # html_result += "</ul>"
301
-
302
- # # Add follow-up recommendations
303
- # html_result += "<h3>Recommended Follow-up</h3><ul>"
304
- # followups = results.get("followup_recommendations", [])
305
-
306
- # if followups:
307
- # for rec in followups:
308
- # html_result += f"<li>{rec}</li>"
309
- # else:
310
- # html_result += (
311
- # "<li>No specific follow-up recommendations provided.</li>"
312
- # )
313
-
314
- # html_result += "</ul>"
315
-
316
- # # Add confidence note
317
- # confidence = results.get("severity", {}).get("confidence", 0)
318
- # html_result += f"""
319
- # <p><em>Note: This analysis has a confidence level of {confidence:.0%}.
320
- # Please consult with healthcare professionals for official diagnosis.</em></p>
321
- # """
322
-
323
- # return html_result, plot_html
324
-
325
- # except Exception as e:
326
- # self.logger.error(f"Error in multimodal analysis: {e}")
327
- # return f"Error in multimodal analysis: {str(e)}", None
328
-
329
- # def enhance_image(self, image):
330
- # """
331
- # Enhance X-ray image contrast.
332
-
333
- # Args:
334
- # image: Image file uploaded through Gradio
335
-
336
- # Returns:
337
- # PIL.Image: Enhanced image
338
- # """
339
- # try:
340
- # if image is None:
341
- # return None
342
-
343
- # # Save uploaded image to a temporary file
344
- # temp_dir = tempfile.mkdtemp()
345
- # temp_path = os.path.join(temp_dir, "upload.png")
346
-
347
- # if isinstance(image, str):
348
- # # Copy the file if it's a path
349
- # from shutil import copyfile
350
-
351
- # copyfile(image, temp_path)
352
- # else:
353
- # # Save if it's a Gradio UploadButton image
354
- # image.save(temp_path)
355
-
356
- # # Enhance image
357
- # self.logger.info(f"Enhancing image: {temp_path}")
358
- # output_path = os.path.join(temp_dir, "enhanced.png")
359
- # enhance_xray_image(temp_path, output_path)
360
-
361
- # # Load enhanced image
362
- # enhanced = Image.open(output_path)
363
- # return enhanced
364
-
365
- # except Exception as e:
366
- # self.logger.error(f"Error enhancing image: {e}")
367
- # return image # Return original image on error
368
-
369
- # def fig_to_html(self, fig):
370
- # """Convert matplotlib figure to HTML for display in Gradio."""
371
- # try:
372
- # import base64
373
- # import io
374
-
375
- # buf = io.BytesIO()
376
- # fig.savefig(buf, format="png", bbox_inches="tight")
377
- # buf.seek(0)
378
- # img_str = base64.b64encode(buf.read()).decode("utf-8")
379
- # plt.close(fig)
380
-
381
- # return f'<img src="data:image/png;base64,{img_str}" alt="Analysis Plot">'
382
-
383
- # except Exception as e:
384
- # self.logger.error(f"Error converting figure to HTML: {e}")
385
- # return "<p>Error displaying visualization.</p>"
386
- import logging
387
- import os
388
- import sys
389
- import tempfile
390
- from pathlib import Path
391
  import requests
392
  import gradio as gr
393
  import matplotlib.pyplot as plt
@@ -503,7 +118,10 @@ class MediSyncApp:
503
 
504
  html_result = f"""
505
  <div class="medisync-card medisync-card-bg medisync-force-text">
506
- <h2 class="medisync-title medisync-blue">X-ray Analysis Results</h2>
 
 
 
507
  <p><strong>Primary Finding:</strong> {results.get("primary_finding", "Unknown")}</p>
508
  <p><strong>Confidence:</strong> {results.get("confidence", 0):.1%}</p>
509
  <p><strong>Abnormality Detected:</strong> {"Yes" if results.get("has_abnormality", False) else "No"}</p>
@@ -550,7 +168,10 @@ class MediSyncApp:
550
  entities_plot_html = self.fig_to_html(fig)
551
  html_result = f"""
552
  <div class="medisync-card medisync-card-bg medisync-force-text">
553
- <h2 class="medisync-title medisync-green">Text Analysis Results</h2>
 
 
 
554
  <p><strong>Severity Level:</strong> {results.get("severity", {}).get("level", "Unknown")}</p>
555
  <p><strong>Severity Score:</strong> {results.get("severity", {}).get("score", 0)}/4</p>
556
  <p><strong>Confidence:</strong> {results.get("severity", {}).get("confidence", 0):.1%}</p>
@@ -617,7 +238,10 @@ class MediSyncApp:
617
  explanation = self.fusion_model.get_explanation(results)
618
  html_result = f"""
619
  <div class="medisync-card medisync-card-bg medisync-force-text">
620
- <h2 class="medisync-title medisync-purple">Multimodal Analysis Results</h2>
 
 
 
621
  <h3>Overview</h3>
622
  <p><strong>Primary Finding:</strong> {results.get("primary_finding", "Unknown")}</p>
623
  <p><strong>Severity Level:</strong> {results.get("severity", {}).get("level", "Unknown")}</p>
@@ -772,8 +396,14 @@ def create_interface():
772
  color: var(--body-text-color, #222);
773
  }
774
  .medisync-title {
775
- font-weight: 700;
 
776
  margin-bottom: 0.7em;
 
 
 
 
 
777
  }
778
  .medisync-blue { color: #00bfae; }
779
  .medisync-green { color: #28a745; }
@@ -810,6 +440,7 @@ def create_interface():
810
  /* Responsive tweaks */
811
  @media (max-width: 900px) {
812
  .medisync-card { padding: 16px 8px 12px 8px; }
 
813
  }
814
  /* Ensure text is visible in dark mode */
815
  html[data-theme="dark"] .medisync-card-bg,
@@ -819,6 +450,7 @@ def create_interface():
819
  }
820
  html[data-theme="dark"] .medisync-title {
821
  color: #00bfae !important;
 
822
  }
823
  html[data-theme="dark"] .medisync-blue { color: #00bfae !important; }
824
  html[data-theme="dark"] .medisync-green { color: #00e676 !important; }
@@ -837,17 +469,19 @@ def create_interface():
837
  html[data-theme="dark"] .medisync-force-text, html[data-theme="dark"] .medisync-force-text * {
838
  color: #f8fafc !important;
839
  }
840
- /* End consultation status output force text color */
841
  #end_consultation_status, #end_consultation_status * {
842
  color: var(--body-text-color, #222) !important;
 
843
  }
844
  html[data-theme="dark"] #end_consultation_status, html[data-theme="dark"] #end_consultation_status * {
845
  color: #f8fafc !important;
 
846
  }
847
  /* Style for the popup/status after end consultation for visibility */
848
  #end_consultation_status, #end_consultation_status * {
849
- font-size: 1.08rem !important;
850
- font-weight: 500 !important;
851
  }
852
  html[data-theme="dark"] #end_consultation_status, html[data-theme="dark"] #end_consultation_status * {
853
  color: #f8fafc !important;
@@ -871,18 +505,22 @@ def create_interface():
871
  ) as interface:
872
  gr.Markdown(
873
  """
874
- <div style="display: flex; align-items: center; gap: 16px; margin-bottom: 0.5em;">
875
- <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/medivance_logo.png" alt="Medivance Logo" style="height: 38px; border-radius: 8px; background: #fff; box-shadow: 0 2px 8px 0 rgba(26,115,232,0.10);">
876
- <span style="font-size: 2.1rem; font-weight: 700; color: #00bfae;">MediSync</span>
 
 
 
 
877
  </div>
878
- <div style="font-size: 1.18rem; margin-bottom: 1.2em;">
879
  <span style="color: var(--body-text-color, #222);">AI-powered Multi-Modal Medical Analysis System</span>
880
  </div>
881
- <div style="font-size: 1.05rem; margin-bottom: 1.2em;">
882
  <span style="color: var(--body-text-color, #222);">Seamlessly analyze X-ray images and medical reports for comprehensive healthcare insights.</span>
883
  </div>
884
  <div style="margin-bottom: 1.2em;">
885
- <ul style="font-size: 1.01rem; color: var(--body-text-color, #222);">
886
  <li>Upload a chest X-ray image</li>
887
  <li>Enter the corresponding medical report text</li>
888
  <li>Choose the analysis type: <b>Image</b>, <b>Text</b>, or <b>Multimodal</b></li>
@@ -988,7 +626,10 @@ def create_interface():
988
  gr.Markdown(
989
  """
990
  <div class="medisync-card medisync-card-bg medisync-force-text">
991
- <h2 class="medisync-title medisync-blue">About MediSync</h2>
 
 
 
992
  <p>
993
  <b>MediSync</b> is an AI-powered healthcare solution that uses multi-modal analysis to provide comprehensive insights from medical images and reports.
994
  </p>
@@ -1033,15 +674,16 @@ def create_interface():
1033
  )
1034
 
1035
  def handle_end_consultation(appointment_id):
 
1036
  if not appointment_id or appointment_id.strip() == "":
1037
- return "<div class='medisync-force-text' style='color: #dc3545; padding: 10px; background-color: #ffe6e6; border-radius: 5px;'>Please enter your appointment ID first.</div>"
1038
  result = complete_appointment(appointment_id.strip())
1039
  if result["status"] == "success":
1040
  doctors_urls = get_doctors_page_urls()
1041
  html_response = f"""
1042
- <div class='medisync-force-text' style='color: #28a745; padding: 15px; background-color: #e6ffe6; border-radius: 5px; margin: 10px 0;">
1043
  <h3 style="color: #28a745;">✅ Consultation Completed Successfully!</h3>
1044
- <p style="color: var(--body-text-color, #222);">{result['message']}</p>
1045
  <p style="color: var(--body-text-color, #222);">Your appointment has been marked as completed.</p>
1046
  <button onclick="window.open('{doctors_urls['local']}', '_blank')"
1047
  style="background-color: #00bfae; color: white; padding: 8px 18px; border: none; border-radius: 6px; cursor: pointer; margin-top: 10px;">
@@ -1056,7 +698,7 @@ def create_interface():
1056
  else:
1057
  if "Cannot connect to Flask app" in result['message']:
1058
  html_response = f"""
1059
- <div class='medisync-force-text' style='color: #ff9800; padding: 15px; background-color: #fff3cd; border-radius: 5px; margin: 10px 0;">
1060
  <h3 style="color: #ff9800;">⚠️ Consultation Ready to Complete</h3>
1061
  <p style="color: var(--body-text-color, #222);">Your consultation analysis is complete! However, we cannot automatically mark your appointment as completed because the Flask app is not accessible from this environment.</p>
1062
  <p style="color: var(--body-text-color, #222);"><strong>Appointment ID:</strong> {appointment_id.strip()}</p>
@@ -1084,7 +726,7 @@ def create_interface():
1084
  """
1085
  else:
1086
  html_response = f"""
1087
- <div class='medisync-force-text' style='color: #dc3545; padding: 15px; background-color: #ffe6e6; border-radius: 5px; margin: 10px 0;">
1088
  <h3 style="color: #dc3545;">❌ Error Completing Consultation</h3>
1089
  <p style="color: var(--body-text-color, #222);">{result['message']}</p>
1090
  <p style="color: var(--body-text-color, #222);">Please try again or contact support if the problem persists.</p>
 
3
  import sys
4
  import tempfile
5
  from pathlib import Path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  import requests
7
  import gradio as gr
8
  import matplotlib.pyplot as plt
 
118
 
119
  html_result = f"""
120
  <div class="medisync-card medisync-card-bg medisync-force-text">
121
+ <h2 class="medisync-title medisync-blue">
122
+ <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/xray_icon.png" alt="X-ray" style="height:32px;vertical-align:middle;margin-right:10px;">
123
+ <span style="font-size:1.45em; font-weight:900; letter-spacing:1px; text-shadow:0 2px 8px #00bfae33;">X-ray Analysis Results</span>
124
+ </h2>
125
  <p><strong>Primary Finding:</strong> {results.get("primary_finding", "Unknown")}</p>
126
  <p><strong>Confidence:</strong> {results.get("confidence", 0):.1%}</p>
127
  <p><strong>Abnormality Detected:</strong> {"Yes" if results.get("has_abnormality", False) else "No"}</p>
 
168
  entities_plot_html = self.fig_to_html(fig)
169
  html_result = f"""
170
  <div class="medisync-card medisync-card-bg medisync-force-text">
171
+ <h2 class="medisync-title medisync-green">
172
+ <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/report_icon.png" alt="Report" style="height:32px;vertical-align:middle;margin-right:10px;">
173
+ <span style="font-size:1.45em; font-weight:900; letter-spacing:1px; text-shadow:0 2px 8px #28a74533;">Text Analysis Results</span>
174
+ </h2>
175
  <p><strong>Severity Level:</strong> {results.get("severity", {}).get("level", "Unknown")}</p>
176
  <p><strong>Severity Score:</strong> {results.get("severity", {}).get("score", 0)}/4</p>
177
  <p><strong>Confidence:</strong> {results.get("severity", {}).get("confidence", 0):.1%}</p>
 
238
  explanation = self.fusion_model.get_explanation(results)
239
  html_result = f"""
240
  <div class="medisync-card medisync-card-bg medisync-force-text">
241
+ <h2 class="medisync-title medisync-purple">
242
+ <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/multimodal_icon.png" alt="Multimodal" style="height:32px;vertical-align:middle;margin-right:10px;">
243
+ <span style="font-size:1.45em; font-weight:900; letter-spacing:1px; text-shadow:0 2px 8px #6c63ff33;">Multimodal Analysis Results</span>
244
+ </h2>
245
  <h3>Overview</h3>
246
  <p><strong>Primary Finding:</strong> {results.get("primary_finding", "Unknown")}</p>
247
  <p><strong>Severity Level:</strong> {results.get("severity", {}).get("level", "Unknown")}</p>
 
396
  color: var(--body-text-color, #222);
397
  }
398
  .medisync-title {
399
+ font-weight: 900;
400
+ font-size: 1.45em;
401
  margin-bottom: 0.7em;
402
+ letter-spacing: 1px;
403
+ text-shadow: 0 2px 8px #00bfae33, 0 1px 0 #fff;
404
+ display: flex;
405
+ align-items: center;
406
+ gap: 10px;
407
  }
408
  .medisync-blue { color: #00bfae; }
409
  .medisync-green { color: #28a745; }
 
440
  /* Responsive tweaks */
441
  @media (max-width: 900px) {
442
  .medisync-card { padding: 16px 8px 12px 8px; }
443
+ .medisync-title { font-size: 1.1em; }
444
  }
445
  /* Ensure text is visible in dark mode */
446
  html[data-theme="dark"] .medisync-card-bg,
 
450
  }
451
  html[data-theme="dark"] .medisync-title {
452
  color: #00bfae !important;
453
+ text-shadow: 0 2px 8px #00bfae33, 0 1px 0 #23272f;
454
  }
455
  html[data-theme="dark"] .medisync-blue { color: #00bfae !important; }
456
  html[data-theme="dark"] .medisync-green { color: #00e676 !important; }
 
469
  html[data-theme="dark"] .medisync-force-text, html[data-theme="dark"] .medisync-force-text * {
470
  color: #f8fafc !important;
471
  }
472
+ /* End consultation status output force text color and background for visibility */
473
  #end_consultation_status, #end_consultation_status * {
474
  color: var(--body-text-color, #222) !important;
475
+ background: #fff !important;
476
  }
477
  html[data-theme="dark"] #end_consultation_status, html[data-theme="dark"] #end_consultation_status * {
478
  color: #f8fafc !important;
479
+ background: #23272f !important;
480
  }
481
  /* Style for the popup/status after end consultation for visibility */
482
  #end_consultation_status, #end_consultation_status * {
483
+ font-size: 1.12rem !important;
484
+ font-weight: 600 !important;
485
  }
486
  html[data-theme="dark"] #end_consultation_status, html[data-theme="dark"] #end_consultation_status * {
487
  color: #f8fafc !important;
 
505
  ) as interface:
506
  gr.Markdown(
507
  """
508
+ <div style="display: flex; align-items: center; gap: 18px; margin-bottom: 0.5em;">
509
+ <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/medivance_logo.png" alt="Medivance Logo" style="height: 48px; border-radius: 10px; background: #fff; box-shadow: 0 2px 8px 0 rgba(26,115,232,0.10);">
510
+ <span style="font-size: 2.4rem; font-weight: 900; color: #00bfae; letter-spacing: 1.5px; text-shadow: 0 2px 8px #00bfae33, 0 1px 0 #fff;">
511
+ MediSync
512
+ <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/ai_heartbeat.png" alt="AI Heartbeat" style="height: 32px; vertical-align: middle; margin-left: 8px;">
513
+ </span>
514
+ <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/doctor_icon.png" alt="Doctor" style="height: 38px; border-radius: 8px; background: #fff; box-shadow: 0 2px 8px 0 rgba(26,115,232,0.10); margin-left: 8px;">
515
  </div>
516
+ <div style="font-size: 1.22rem; margin-bottom: 1.2em; font-weight: 600; color: #23272f;">
517
  <span style="color: var(--body-text-color, #222);">AI-powered Multi-Modal Medical Analysis System</span>
518
  </div>
519
+ <div style="font-size: 1.09rem; margin-bottom: 1.2em;">
520
  <span style="color: var(--body-text-color, #222);">Seamlessly analyze X-ray images and medical reports for comprehensive healthcare insights.</span>
521
  </div>
522
  <div style="margin-bottom: 1.2em;">
523
+ <ul style="font-size: 1.04rem; color: var(--body-text-color, #222);">
524
  <li>Upload a chest X-ray image</li>
525
  <li>Enter the corresponding medical report text</li>
526
  <li>Choose the analysis type: <b>Image</b>, <b>Text</b>, or <b>Multimodal</b></li>
 
626
  gr.Markdown(
627
  """
628
  <div class="medisync-card medisync-card-bg medisync-force-text">
629
+ <h2 class="medisync-title medisync-blue">
630
+ <img src="https://cdn.jsdelivr.net/gh/saqib-ali-buriro/medivance-assets/info_icon.png" alt="Info" style="height:32px;vertical-align:middle;margin-right:10px;">
631
+ <span style="font-size:1.45em; font-weight:900; letter-spacing:1px; text-shadow:0 2px 8px #00bfae33;">About MediSync</span>
632
+ </h2>
633
  <p>
634
  <b>MediSync</b> is an AI-powered healthcare solution that uses multi-modal analysis to provide comprehensive insights from medical images and reports.
635
  </p>
 
674
  )
675
 
676
  def handle_end_consultation(appointment_id):
677
+ # Always force text color and background for visibility
678
  if not appointment_id or appointment_id.strip() == "":
679
+ return "<div class='medisync-force-text' style='color: #dc3545; background: #fff; padding: 10px; background-color: #ffe6e6; border-radius: 5px;'>Please enter your appointment ID first.</div>"
680
  result = complete_appointment(appointment_id.strip())
681
  if result["status"] == "success":
682
  doctors_urls = get_doctors_page_urls()
683
  html_response = f"""
684
+ <div class='medisync-force-text' style='color: #28a745; background: #fff; padding: 15px; background-color: #e6ffe6; border-radius: 5px; margin: 10px 0;">
685
  <h3 style="color: #28a745;">✅ Consultation Completed Successfully!</h3>
686
+ <p style="color: var(--body-text-color, #222);">✔️ {result['message']}</p>
687
  <p style="color: var(--body-text-color, #222);">Your appointment has been marked as completed.</p>
688
  <button onclick="window.open('{doctors_urls['local']}', '_blank')"
689
  style="background-color: #00bfae; color: white; padding: 8px 18px; border: none; border-radius: 6px; cursor: pointer; margin-top: 10px;">
 
698
  else:
699
  if "Cannot connect to Flask app" in result['message']:
700
  html_response = f"""
701
+ <div class='medisync-force-text' style='color: #ff9800; background: #fff; padding: 15px; background-color: #fff3cd; border-radius: 5px; margin: 10px 0;">
702
  <h3 style="color: #ff9800;">⚠️ Consultation Ready to Complete</h3>
703
  <p style="color: var(--body-text-color, #222);">Your consultation analysis is complete! However, we cannot automatically mark your appointment as completed because the Flask app is not accessible from this environment.</p>
704
  <p style="color: var(--body-text-color, #222);"><strong>Appointment ID:</strong> {appointment_id.strip()}</p>
 
726
  """
727
  else:
728
  html_response = f"""
729
+ <div class='medisync-force-text' style='color: #dc3545; background: #fff; padding: 15px; background-color: #ffe6e6; border-radius: 5px; margin: 10px 0;">
730
  <h3 style="color: #dc3545;">❌ Error Completing Consultation</h3>
731
  <p style="color: var(--body-text-color, #222);">{result['message']}</p>
732
  <p style="color: var(--body-text-color, #222);">Please try again or contact support if the problem persists.</p>