Arko007 commited on
Commit
d4dd4ef
Β·
verified Β·
1 Parent(s): 2ba37d0

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +1436 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,1438 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
1
+ import os
 
 
2
  import streamlit as st
3
+ import pandas as pd
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ from plotly.subplots import make_subplots
7
+ import numpy as np
8
+ import datetime
9
+ from typing import Dict, List, Optional, Tuple
10
+ import json
11
+ from dataclasses import dataclass, asdict
12
+ import google.generativeai as genai
13
+ from PIL import Image
14
+ import pytesseract
15
+ import keras
16
+ from huggingface_hub import hf_hub_download
17
+ import warnings
18
+ warnings.filterwarnings("ignore")
19
+
20
+ # =============================================================================
21
+ # CONFIGURATION FOR HUGGING FACE SPACES
22
+ # =============================================================================
23
+
24
+ # Configure Streamlit page
25
+ st.set_page_config(
26
+ page_title="πŸ₯ MedAI Suite - AI-Powered Medical Platform",
27
+ page_icon="πŸ₯",
28
+ layout="wide",
29
+ initial_sidebar_state="expanded"
30
+ )
31
+
32
+ # Get API key from HF Secrets
33
+ try:
34
+ GEMINI_API_KEY = st.secrets["GEMINI_API_KEY"]
35
+ genai.configure(api_key=GEMINI_API_KEY)
36
+ except:
37
+ st.error("πŸ”‘ Gemini API key not found in secrets. Please configure it in HF Space settings.")
38
+ st.stop()
39
+
40
+ # Custom CSS for professional medical UI
41
+ def load_custom_css():
42
+ st.markdown("""
43
+ <style>
44
+ /* Main theme colors */
45
+ :root {
46
+ --primary-color: #667eea;
47
+ --secondary-color: #764ba2;
48
+ --success-color: #28a745;
49
+ --warning-color: #ffc107;
50
+ --danger-color: #dc3545;
51
+ --info-color: #17a2b8;
52
+ }
53
+
54
+ /* Header styling */
55
+ .main-header {
56
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
57
+ padding: 2rem;
58
+ border-radius: 12px;
59
+ color: white;
60
+ text-align: center;
61
+ margin-bottom: 2rem;
62
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
63
+ }
64
+
65
+ .main-header h1 {
66
+ margin: 0;
67
+ font-size: 2.5rem;
68
+ font-weight: 700;
69
+ }
70
+
71
+ .main-header p {
72
+ margin: 0.5rem 0 0 0;
73
+ font-size: 1.1rem;
74
+ opacity: 0.9;
75
+ }
76
+
77
+ /* Feature cards */
78
+ .feature-card {
79
+ background: #f8f9fa;
80
+ padding: 1.5rem;
81
+ border-radius: 12px;
82
+ border-left: 4px solid var(--primary-color);
83
+ margin: 1rem 0;
84
+ box-shadow: 0 2px 10px rgba(0,0,0,0.05);
85
+ transition: transform 0.2s ease;
86
+ }
87
+
88
+ .feature-card:hover {
89
+ transform: translateY(-2px);
90
+ box-shadow: 0 4px 20px rgba(0,0,0,0.1);
91
+ }
92
+
93
+ /* Metric cards */
94
+ .metric-card {
95
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
96
+ padding: 1.5rem;
97
+ border-radius: 12px;
98
+ color: white;
99
+ text-align: center;
100
+ box-shadow: 0 4px 15px rgba(0,0,0,0.1);
101
+ margin-bottom: 1rem;
102
+ }
103
+
104
+ .metric-card h3 {
105
+ margin: 0 0 0.5rem 0;
106
+ font-size: 1rem;
107
+ opacity: 0.9;
108
+ }
109
+
110
+ .metric-card h2 {
111
+ margin: 0;
112
+ font-size: 2rem;
113
+ font-weight: 700;
114
+ }
115
+
116
+ .metric-card small {
117
+ opacity: 0.8;
118
+ font-size: 0.9rem;
119
+ }
120
+
121
+ /* Button styling */
122
+ .stButton > button {
123
+ background: linear-gradient(90deg, var(--primary-color) 0%, var(--secondary-color) 100%);
124
+ color: white;
125
+ border: none;
126
+ border-radius: 8px;
127
+ padding: 0.7rem 1.5rem;
128
+ font-weight: 600;
129
+ transition: all 0.2s ease;
130
+ }
131
+
132
+ .stButton > button:hover {
133
+ transform: translateY(-1px);
134
+ box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
135
+ }
136
+
137
+ /* Alert styling */
138
+ .success-alert {
139
+ background: linear-gradient(90deg, #d4edda, #c3e6cb);
140
+ border-left: 4px solid var(--success-color);
141
+ padding: 1rem;
142
+ border-radius: 8px;
143
+ margin: 1rem 0;
144
+ }
145
+
146
+ .warning-alert {
147
+ background: linear-gradient(90deg, #fff3cd, #ffeaa7);
148
+ border-left: 4px solid var(--warning-color);
149
+ padding: 1rem;
150
+ border-radius: 8px;
151
+ margin: 1rem 0;
152
+ }
153
+
154
+ .error-alert {
155
+ background: linear-gradient(90deg, #f8d7da, #f5c6cb);
156
+ border-left: 4px solid var(--danger-color);
157
+ padding: 1rem;
158
+ border-radius: 8px;
159
+ margin: 1rem 0;
160
+ }
161
+
162
+ /* Chat styling */
163
+ .chat-message {
164
+ padding: 1rem;
165
+ border-radius: 12px;
166
+ margin: 1rem 0;
167
+ }
168
+
169
+ .user-message {
170
+ background: linear-gradient(135deg, #e3f2fd, #bbdefb);
171
+ border-left: 4px solid #2196f3;
172
+ }
173
+
174
+ .assistant-message {
175
+ background: linear-gradient(135deg, #f3e5f5, #e1bee7);
176
+ border-left: 4px solid #9c27b0;
177
+ }
178
+
179
+ /* Hide Streamlit default elements */
180
+ #MainMenu {visibility: hidden;}
181
+ footer {visibility: hidden;}
182
+ header {visibility: hidden;}
183
+
184
+ /* Professional medical disclaimer */
185
+ .medical-disclaimer {
186
+ background: linear-gradient(135deg, #fff3e0, #ffe0b2);
187
+ border: 2px solid #ff9800;
188
+ border-radius: 12px;
189
+ padding: 1.5rem;
190
+ margin: 2rem 0;
191
+ text-align: center;
192
+ }
193
+
194
+ .medical-disclaimer h4 {
195
+ color: #e65100;
196
+ margin-bottom: 1rem;
197
+ }
198
+ </style>
199
+ """, unsafe_allow_html=True)
200
+
201
+ # =============================================================================
202
+ # DATA CLASSES
203
+ # =============================================================================
204
+
205
+ @dataclass
206
+ class UserProfile:
207
+ """Enhanced user medical profile"""
208
+ user_id: str
209
+ name: str
210
+ age: int
211
+ height: float # cm
212
+ weight: float # kg
213
+ sex: str
214
+ blood_sugar: float # mg/dL
215
+ blood_pressure: str # systolic/diastolic
216
+ past_medications: List[str]
217
+ current_conditions: List[str]
218
+ allergies: List[str]
219
+ created_at: str
220
+ bmi: float = 0.0
221
+
222
+ def __post_init__(self):
223
+ if self.height > 0:
224
+ height_m = self.height / 100
225
+ self.bmi = round(self.weight / (height_m ** 2), 2)
226
+
227
+ # =============================================================================
228
+ # MEDICAL AI BACKEND
229
+ # =============================================================================
230
+
231
+ class MedicalAI:
232
+ """Complete Medical AI System"""
233
+
234
+ def __init__(self):
235
+ self.user_profiles = {}
236
+ self.conversation_history = {}
237
+ self.gemini_model = None
238
+ self.dr_model = None
239
+ self.dr_model_loaded = False
240
+
241
+ # Initialize Gemini
242
+ self._init_gemini()
243
+
244
+ # Initialize DR model
245
+ self._init_dr_model()
246
+
247
+ def _init_gemini(self):
248
+ """Initialize Gemini model"""
249
+ try:
250
+ self.gemini_model = genai.GenerativeModel("gemini-2.0-flash")
251
+ st.success("βœ… Gemini AI connected successfully")
252
+ except Exception as e:
253
+ st.error(f"❌ Gemini connection failed: {str(e)}")
254
+
255
+ def _init_dr_model(self):
256
+ """Initialize diabetic retinopathy model"""
257
+ try:
258
+ with st.spinner("🧠 Loading Diabetic Retinopathy AI model..."):
259
+ repo_id = "Arko007/diabetic-retinopathy-v1"
260
+ weights_filename = "best_model.h5"
261
+ local_weights_path = hf_hub_download(repo_id=repo_id, filename=weights_filename)
262
+ self.dr_model = keras.saving.load_model(local_weights_path)
263
+ self.dr_model_loaded = True
264
+ st.success("βœ… Eye screening AI model loaded successfully")
265
+ except Exception as e:
266
+ st.warning(f"⚠️ Eye screening model unavailable: {str(e)}")
267
+ self.dr_model_loaded = False
268
+
269
+ def validate_user_input(self, user_data: Dict) -> Tuple[bool, List[str]]:
270
+ """Validate user profile data"""
271
+ errors = []
272
+
273
+ required_fields = ['name', 'age', 'height', 'weight', 'sex']
274
+ for field in required_fields:
275
+ if not user_data.get(field):
276
+ errors.append(f"❌ {field.title()} is required")
277
+
278
+ # Age validation
279
+ try:
280
+ age = int(user_data.get('age', 0))
281
+ if not 1 <= age <= 150:
282
+ errors.append("❌ Age must be between 1-150 years")
283
+ except:
284
+ errors.append("❌ Age must be a valid number")
285
+
286
+ # Height validation
287
+ try:
288
+ height = float(user_data.get('height', 0))
289
+ if not 50 <= height <= 300:
290
+ errors.append("❌ Height must be between 50-300 cm")
291
+ except:
292
+ errors.append("❌ Height must be a valid number")
293
+
294
+ # Weight validation
295
+ try:
296
+ weight = float(user_data.get('weight', 0))
297
+ if not 10 <= weight <= 500:
298
+ errors.append("❌ Weight must be between 10-500 kg")
299
+ except:
300
+ errors.append("❌ Weight must be a valid number")
301
+
302
+ return len(errors) == 0, errors
303
+
304
+ def create_user_profile(self, user_data: Dict) -> Tuple[Optional[UserProfile], List[str]]:
305
+ """Create new user profile"""
306
+ is_valid, errors = self.validate_user_input(user_data)
307
+ if not is_valid:
308
+ return None, errors
309
+
310
+ timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
311
+ user_id = f"medai_user_{timestamp}"
312
+
313
+ try:
314
+ profile = UserProfile(
315
+ user_id=user_id,
316
+ name=user_data.get('name', '').strip().title(),
317
+ age=int(user_data.get('age', 0)),
318
+ height=float(user_data.get('height', 0)),
319
+ weight=float(user_data.get('weight', 0)),
320
+ sex=user_data.get('sex', '').lower().strip(),
321
+ blood_sugar=float(user_data.get('blood_sugar') or 0),
322
+ blood_pressure=user_data.get('blood_pressure', '').strip(),
323
+ past_medications=self._clean_list(user_data.get('past_medications', [])),
324
+ current_conditions=self._clean_list(user_data.get('current_conditions', [])),
325
+ allergies=self._clean_list(user_data.get('allergies', [])),
326
+ created_at=datetime.datetime.now().isoformat()
327
+ )
328
+
329
+ self.user_profiles[user_id] = profile
330
+ self.conversation_history[user_id] = []
331
+
332
+ return profile, []
333
+
334
+ except Exception as e:
335
+ return None, [f"❌ Profile creation error: {str(e)}"]
336
+
337
+ def _clean_list(self, input_list) -> List[str]:
338
+ """Clean list inputs"""
339
+ if isinstance(input_list, str):
340
+ return [item.strip() for item in input_list.split(',') if item.strip()]
341
+ elif isinstance(input_list, list):
342
+ return [str(item).strip() for item in input_list if str(item).strip()]
343
+ return []
344
+
345
+ def get_bmi_category(self, bmi: float) -> str:
346
+ """Get BMI category"""
347
+ if bmi < 18.5:
348
+ return "Underweight"
349
+ elif bmi < 23:
350
+ return "Normal weight"
351
+ elif bmi < 25:
352
+ return "Overweight"
353
+ elif bmi < 30:
354
+ return "Obese Class I"
355
+ else:
356
+ return "Obese Class II+"
357
+
358
+ def generate_medical_context(self, user_id: str) -> str:
359
+ """Generate medical context for consultation"""
360
+ if user_id not in self.user_profiles:
361
+ return ""
362
+
363
+ profile = self.user_profiles[user_id]
364
+ return f"""
365
+ Patient: {profile.name}, {profile.age} years old, {profile.sex.title()}
366
+ Physical: Height {profile.height}cm, Weight {profile.weight}kg, BMI {profile.bmi}
367
+ Vitals: Blood Sugar {profile.blood_sugar} mg/dL, BP {profile.blood_pressure}
368
+ Medical History: {', '.join(profile.current_conditions) if profile.current_conditions else 'None'}
369
+ Medications: {', '.join(profile.past_medications) if profile.past_medications else 'None'}
370
+ Allergies: {', '.join(profile.allergies) if profile.allergies else 'None'}
371
+ """
372
+
373
+ def ask_medical_question(self, user_id: str, question: str) -> Dict:
374
+ """Medical consultation using Gemini"""
375
+ if not self.gemini_model:
376
+ return {'success': False, 'error': "AI consultation unavailable"}
377
+
378
+ if user_id not in self.user_profiles:
379
+ return {'success': False, 'error': "Please create a profile first"}
380
+
381
+ medical_context = self.generate_medical_context(user_id)
382
+
383
+ prompt = f"""You are MedAI, a professional medical AI assistant for healthcare in India.
384
+
385
+ PATIENT CONTEXT:
386
+ {medical_context}
387
+
388
+ PATIENT QUESTION: {question}
389
+
390
+ INSTRUCTIONS:
391
+ 1. Provide helpful, evidence-based medical guidance
392
+ 2. Consider the patient's profile and Indian healthcare context
393
+ 3. Use clear, supportive language
394
+ 4. Always emphasize consulting healthcare professionals
395
+ 5. If urgent symptoms, immediately advise emergency care
396
+ 6. Keep response comprehensive but accessible (300-400 words)
397
+
398
+ Provide a detailed, caring response that helps the patient understand their health."""
399
+
400
+ try:
401
+ response = self.gemini_model.generate_content(prompt)
402
+ answer = response.text
403
+
404
+ # Store conversation
405
+ conversation = {
406
+ 'question': question,
407
+ 'answer': answer,
408
+ 'timestamp': datetime.datetime.now().isoformat()
409
+ }
410
+ self.conversation_history[user_id].append(conversation)
411
+
412
+ return {'success': True, 'answer': answer, 'timestamp': conversation['timestamp']}
413
+
414
+ except Exception as e:
415
+ return {'success': False, 'error': f"Consultation error: {str(e)}"}
416
+
417
+ def analyze_medical_report(self, image: Image.Image) -> Dict:
418
+ """Analyze medical reports using OCR + Gemini"""
419
+ if not self.gemini_model:
420
+ return {'success': False, 'error': "Report analysis unavailable"}
421
+
422
+ try:
423
+ # OCR extraction
424
+ text = pytesseract.image_to_string(image)
425
+ if not text.strip():
426
+ return {'success': False, 'error': "No text found in image"}
427
+
428
+ prompt = f"""You are a medical AI analyzing a healthcare report for Indian patients.
429
+
430
+ EXTRACTED REPORT TEXT:
431
+ {text}
432
+
433
+ ANALYSIS INSTRUCTIONS:
434
+ 1. Identify the type of medical report
435
+ 2. Highlight values outside normal ranges
436
+ 3. Explain abnormal findings in simple terms with analogies
437
+ 4. Provide lifestyle recommendations for concerning values
438
+ 5. Use markdown formatting for clear structure
439
+ 6. Always end with medical disclaimer
440
+
441
+ Provide a comprehensive, patient-friendly analysis."""
442
+
443
+ response = self.gemini_model.generate_content(prompt)
444
+
445
+ return {
446
+ 'success': True,
447
+ 'analysis': response.text,
448
+ 'extracted_text': text[:500] + "..." if len(text) > 500 else text,
449
+ 'timestamp': datetime.datetime.now().isoformat()
450
+ }
451
+
452
+ except Exception as e:
453
+ return {'success': False, 'error': f"Analysis error: {str(e)}"}
454
+
455
+ def analyze_diabetic_retinopathy(self, image: Image.Image) -> Dict:
456
+ """Diabetic retinopathy screening using custom model + Gemini explanation"""
457
+ if not self.dr_model_loaded:
458
+ return {'success': False, 'error': "Eye screening model unavailable"}
459
+
460
+ try:
461
+ # Preprocess image
462
+ img_resized = image.resize((384, 384))
463
+ image_array = np.array(img_resized).astype(np.float32) / 255.0
464
+ image_array = np.expand_dims(image_array, axis=0)
465
+
466
+ # Get prediction
467
+ predictions = self.dr_model.predict(image_array, verbose=0)
468
+ predicted_class_index = np.argmax(predictions, axis=1)[0]
469
+ confidence = float(np.max(predictions))
470
+
471
+ class_labels = ["No DR", "Mild DR", "Moderate DR", "Severe DR", "Proliferative DR"]
472
+ predicted_label = class_labels[predicted_class_index]
473
+
474
+ # Generate detailed analysis
475
+ if self.gemini_model:
476
+ prompt = f"""You are an ophthalmology AI providing educational analysis for Indian healthcare.
477
+
478
+ SCREENING RESULT:
479
+ - AI Classification: {predicted_label}
480
+ - Model Confidence: {confidence:.2%}
481
+ - Custom Model: Arko007/diabetic-retinopathy-v1
482
+
483
+ ANALYSIS INSTRUCTIONS:
484
+ 1. Explain what this classification means
485
+ 2. Describe typical changes for this stage
486
+ 3. Provide follow-up recommendations
487
+ 4. Include lifestyle guidance
488
+ 5. Use supportive, clear language
489
+ 6. Always emphasize this is screening, not diagnosis
490
+
491
+ Provide comprehensive analysis with clear sections."""
492
+
493
+ try:
494
+ gemini_response = self.gemini_model.generate_content(prompt)
495
+ detailed_analysis = gemini_response.text
496
+ except:
497
+ detailed_analysis = f"**Classification:** {predicted_label}\n**Confidence:** {confidence:.2%}\n\nPlease consult an eye specialist for detailed evaluation."
498
+ else:
499
+ detailed_analysis = f"**Classification:** {predicted_label}\n**Confidence:** {confidence:.2%}"
500
+
501
+ return {
502
+ 'success': True,
503
+ 'classification': predicted_label,
504
+ 'confidence': confidence,
505
+ 'analysis': detailed_analysis,
506
+ 'timestamp': datetime.datetime.now().isoformat()
507
+ }
508
+
509
+ except Exception as e:
510
+ return {'success': False, 'error': f"Screening error: {str(e)}"}
511
+
512
+ def get_conversation_history(self, user_id: str, limit: int = 10) -> List[Dict]:
513
+ """Get conversation history"""
514
+ history = self.conversation_history.get(user_id, [])
515
+ return history[-limit:] if limit else history
516
+
517
+ # =============================================================================
518
+ # SESSION STATE INITIALIZATION
519
+ # =============================================================================
520
+
521
+ def initialize_session_state():
522
+ """Initialize all session state variables"""
523
+ if 'medical_ai' not in st.session_state:
524
+ st.session_state.medical_ai = MedicalAI()
525
+
526
+ if 'current_user' not in st.session_state:
527
+ st.session_state.current_user = None
528
+
529
+ if 'chat_history' not in st.session_state:
530
+ st.session_state.chat_history = []
531
+
532
+ if 'page' not in st.session_state:
533
+ st.session_state.page = "πŸ₯ Dashboard"
534
+
535
+ # =============================================================================
536
+ # UI COMPONENTS
537
+ # =============================================================================
538
+
539
+ def display_main_header():
540
+ """Display main application header"""
541
+ st.markdown("""
542
+ <div class="main-header">
543
+ <h1>πŸ₯ MedAI Suite</h1>
544
+ <p>AI-Powered Medical Platform | Consultation β€’ Report Analysis β€’ Eye Screening β€’ Health Analytics</p>
545
+ </div>
546
+ """, unsafe_allow_html=True)
547
+
548
+ def create_sidebar():
549
+ """Enhanced sidebar navigation"""
550
+ with st.sidebar:
551
+ # App branding
552
+ st.markdown("""
553
+ <div style="text-align: center; padding: 1rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 12px; color: white; margin-bottom: 1rem;">
554
+ <h2>πŸ₯ MedAI Suite</h2>
555
+ <p>Your AI Health Assistant</p>
556
+ </div>
557
+ """, unsafe_allow_html=True)
558
+
559
+ # User info
560
+ if st.session_state.current_user:
561
+ user = st.session_state.current_user
562
+ st.markdown(f"""
563
+ <div style="background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%); padding: 1rem; border-radius: 12px; margin-bottom: 1rem;">
564
+ <h4>πŸ‘€ Current Patient</h4>
565
+ <p><strong>{user.name}</strong><br>
566
+ Age: {user.age} | BMI: {user.bmi}</p>
567
+ </div>
568
+ """, unsafe_allow_html=True)
569
+
570
+ if st.button("πŸ”„ New Patient", use_container_width=True):
571
+ st.session_state.current_user = None
572
+ st.session_state.chat_history = []
573
+ st.rerun()
574
+ else:
575
+ st.info("πŸ‘€ No patient profile selected")
576
+
577
+ # Navigation
578
+ st.markdown("### 🧭 Navigation")
579
+
580
+ page_options = [
581
+ "πŸ₯ Dashboard",
582
+ "πŸ‘€ Patient Profile",
583
+ "πŸ€– Medical Consultation",
584
+ "πŸ“‹ Report Analysis",
585
+ "πŸ‘οΈ Eye Screening",
586
+ "πŸ“Š Health Analytics"
587
+ ]
588
+
589
+ selected_page = st.selectbox(
590
+ "Go to:",
591
+ page_options,
592
+ index=page_options.index(st.session_state.page) if st.session_state.page in page_options else 0,
593
+ key="navigation_selectbox"
594
+ )
595
+
596
+ if selected_page != st.session_state.page:
597
+ st.session_state.page = selected_page
598
+ st.rerun()
599
+
600
+ # Quick actions
601
+ st.markdown("### ⚑ Quick Actions")
602
+
603
+ if st.session_state.current_user:
604
+ if st.button("🚨 Emergency Consultation", use_container_width=True, type="primary"):
605
+ st.session_state.page = "πŸ€– Medical Consultation"
606
+ st.rerun()
607
+
608
+ if st.button("πŸ“Š Health Dashboard", use_container_width=True):
609
+ st.session_state.page = "πŸ“Š Health Analytics"
610
+ st.rerun()
611
+
612
+ # Footer
613
+ st.markdown("---")
614
+ st.markdown("""
615
+ <div style="text-align: center; font-size: 0.8em; color: #666;">
616
+ <p>πŸ₯ MedAI Suite<br>
617
+ AI-Powered Healthcare Assistant<br>
618
+ Made with ❀️ for Better Health</p>
619
+ </div>
620
+ """, unsafe_allow_html=True)
621
+
622
+ def create_patient_profile_form():
623
+ """Patient profile creation"""
624
+ st.markdown("## πŸ‘€ Create Patient Profile")
625
+
626
+ with st.form("patient_profile_form", clear_on_submit=False):
627
+ st.markdown("### Basic Information")
628
+
629
+ col1, col2 = st.columns(2)
630
+
631
+ with col1:
632
+ name = st.text_input("πŸ‘€ Full Name*", placeholder="Enter patient name")
633
+ age = st.number_input("πŸŽ‚ Age*", min_value=1, max_value=150, value=30, step=1)
634
+ height = st.number_input("πŸ“ Height (cm)*", min_value=50, max_value=250, value=170, step=1)
635
+ weight = st.number_input("βš–οΈ Weight (kg)*", min_value=10, max_value=300, value=70.0, step=0.1)
636
+
637
+ with col2:
638
+ sex = st.selectbox("⚧ Sex*", ["Male", "Female", "Other"], key="sex_selectbox")
639
+ blood_sugar = st.number_input("🍬 Blood Sugar (mg/dL)", min_value=0, value=95, step=1)
640
+
641
+ # Blood pressure
642
+ st.markdown("🩺 **Blood Pressure**")
643
+ bp_col1, bp_col2 = st.columns(2)
644
+ with bp_col1:
645
+ bp_sys = st.number_input("Systolic", min_value=0, value=120, step=1, key="bp_sys")
646
+ with bp_col2:
647
+ bp_dia = st.number_input("Diastolic", min_value=0, value=80, step=1, key="bp_dia")
648
+
649
+ st.markdown("### Medical History")
650
+
651
+ col3, col4 = st.columns(2)
652
+
653
+ with col3:
654
+ conditions = st.text_area("πŸ₯ Current Conditions",
655
+ placeholder="e.g., Diabetes, Hypertension (comma-separated)")
656
+ medications = st.text_area("πŸ’Š Past Medications",
657
+ placeholder="e.g., Metformin, Aspirin (comma-separated)")
658
+
659
+ with col4:
660
+ allergies = st.text_area("⚠️ Known Allergies",
661
+ placeholder="e.g., Penicillin, Shellfish (comma-separated)")
662
+ notes = st.text_area("πŸ“ Additional Notes",
663
+ placeholder="Any other relevant information")
664
+
665
+ # Submit button
666
+ submitted = st.form_submit_button("βœ… Create Profile", type="primary", use_container_width=True)
667
+
668
+ if submitted:
669
+ user_data = {
670
+ 'name': name,
671
+ 'age': age,
672
+ 'height': height,
673
+ 'weight': weight,
674
+ 'sex': sex.lower(),
675
+ 'blood_sugar': blood_sugar,
676
+ 'blood_pressure': f"{bp_sys}/{bp_dia}",
677
+ 'current_conditions': conditions,
678
+ 'past_medications': medications,
679
+ 'allergies': allergies
680
+ }
681
+
682
+ profile, errors = st.session_state.medical_ai.create_user_profile(user_data)
683
+
684
+ if profile:
685
+ st.session_state.current_user = profile
686
+ st.markdown(f"""
687
+ <div class="success-alert">
688
+ <h4>βœ… Profile Created Successfully!</h4>
689
+ <p>Welcome <strong>{name}</strong>! Your medical profile is ready.</p>
690
+ </div>
691
+ """, unsafe_allow_html=True)
692
+ st.balloons()
693
+ else:
694
+ for error in errors:
695
+ st.error(error)
696
+
697
+ def display_patient_profile():
698
+ """Display patient profile dashboard"""
699
+ if not st.session_state.current_user:
700
+ return
701
+
702
+ user = st.session_state.current_user
703
+
704
+ # Profile header
705
+ st.markdown(f"""
706
+ <div class="main-header">
707
+ <h2>πŸ‘€ {user.name}</h2>
708
+ <p>Patient ID: {user.user_id} | Created: {user.created_at[:10]}</p>
709
+ </div>
710
+ """, unsafe_allow_html=True)
711
+
712
+ # Metrics
713
+ col1, col2, col3, col4, col5, col6 = st.columns(6)
714
+
715
+ metrics = [
716
+ (col1, "Age", f"{user.age}", "years"),
717
+ (col2, "Height", f"{user.height}", "cm"),
718
+ (col3, "Weight", f"{user.weight}", "kg"),
719
+ (col4, "BMI", f"{user.bmi}", st.session_state.medical_ai.get_bmi_category(user.bmi)),
720
+ (col5, "Blood Sugar", f"{user.blood_sugar}", "mg/dL"),
721
+ (col6, "Blood Pressure", user.blood_pressure, "mmHg")
722
+ ]
723
+
724
+ for col, title, value, unit in metrics:
725
+ with col:
726
+ st.markdown(f"""
727
+ <div class="metric-card">
728
+ <h3>{title}</h3>
729
+ <h2>{value}</h2>
730
+ <small>{unit}</small>
731
+ </div>
732
+ """, unsafe_allow_html=True)
733
+
734
+ # Medical history
735
+ if any([user.current_conditions, user.past_medications, user.allergies]):
736
+ st.markdown("### πŸ“‹ Medical Summary")
737
+
738
+ col1, col2, col3 = st.columns(3)
739
+
740
+ with col1:
741
+ st.markdown("**πŸ₯ Current Conditions**")
742
+ if user.current_conditions:
743
+ for condition in user.current_conditions:
744
+ st.markdown(f"β€’ {condition}")
745
+ else:
746
+ st.markdown("β€’ None reported")
747
+
748
+ with col2:
749
+ st.markdown("**πŸ’Š Past Medications**")
750
+ if user.past_medications:
751
+ for medication in user.past_medications:
752
+ st.markdown(f"β€’ {medication}")
753
+ else:
754
+ st.markdown("β€’ None reported")
755
+
756
+ with col3:
757
+ st.markdown("**⚠️ Known Allergies**")
758
+ if user.allergies:
759
+ for allergy in user.allergies:
760
+ st.markdown(f"β€’ {allergy}")
761
+ else:
762
+ st.markdown("β€’ None reported")
763
+
764
+ def create_medical_consultation():
765
+ """AI Medical Consultation Interface"""
766
+ st.markdown("## πŸ€– AI Medical Consultation")
767
+
768
+ if not st.session_state.current_user:
769
+ st.markdown("""
770
+ <div class="warning-alert">
771
+ <h4>⚠️ Patient Profile Required</h4>
772
+ <p>Please create a patient profile first to receive personalized medical consultation.</p>
773
+ </div>
774
+ """, unsafe_allow_html=True)
775
+ return
776
+
777
+ user = st.session_state.current_user
778
+
779
+ # Patient context
780
+ with st.expander("πŸ‘€ Current Patient Context", expanded=False):
781
+ col1, col2 = st.columns(2)
782
+ with col1:
783
+ st.write(f"**Name:** {user.name}")
784
+ st.write(f"**Age:** {user.age} years")
785
+ st.write(f"**BMI:** {user.bmi} ({st.session_state.medical_ai.get_bmi_category(user.bmi)})")
786
+ with col2:
787
+ st.write(f"**Blood Sugar:** {user.blood_sugar} mg/dL")
788
+ st.write(f"**Blood Pressure:** {user.blood_pressure}")
789
+ if user.current_conditions:
790
+ st.write(f"**Conditions:** {', '.join(user.current_conditions)}")
791
+
792
+ # Quick consultation topics
793
+ st.markdown("#### πŸ” Quick Consultation Topics")
794
+
795
+ col1, col2, col3, col4 = st.columns(4)
796
+
797
+ quick_topics = [
798
+ ("πŸ“Š Health Review", "Please review my current health metrics and provide insights."),
799
+ ("🩺 Blood Pressure", "What should I know about managing my blood pressure?"),
800
+ ("🍎 Lifestyle Tips", "What lifestyle changes would you recommend for me?"),
801
+ ("⚠️ Risk Assessment", "Are there any health risks I should be aware of?")
802
+ ]
803
+
804
+ selected_topic = None
805
+ for i, (col, (title, question)) in enumerate(zip([col1, col2, col3, col4], quick_topics)):
806
+ with col:
807
+ if st.button(title, use_container_width=True, key=f"topic_{i}"):
808
+ selected_topic = question
809
+
810
+ # Chat interface
811
+ st.markdown("### πŸ’¬ Ask Your Medical Questions")
812
+
813
+ # Display chat history
814
+ for msg in st.session_state.chat_history[-5:]: # Show last 5 messages
815
+ if msg["role"] == "user":
816
+ st.markdown(f"""
817
+ <div class="chat-message user-message">
818
+ <strong>πŸ‘€ You:</strong> {msg["content"]}
819
+ </div>
820
+ """, unsafe_allow_html=True)
821
+ else:
822
+ st.markdown(f"""
823
+ <div class="chat-message assistant-message">
824
+ <strong>πŸ€– MedAI:</strong> {msg["content"]}
825
+ </div>
826
+ """, unsafe_allow_html=True)
827
+
828
+ # Input form
829
+ with st.form("medical_consultation_form", clear_on_submit=True):
830
+ question = st.text_area(
831
+ "✍️ Your Medical Question:",
832
+ value=selected_topic if selected_topic else "",
833
+ placeholder="Describe your symptoms or ask about your health...",
834
+ height=100
835
+ )
836
+
837
+ col1, col2 = st.columns([3, 1])
838
+ with col1:
839
+ priority = st.selectbox("🚨 Priority Level", ["Normal", "Urgent", "Emergency"], key="priority_selectbox")
840
+
841
+ submitted = st.form_submit_button("πŸ€– Get AI Consultation", type="primary", use_container_width=True)
842
+
843
+ if submitted and question.strip():
844
+ # Add user message
845
+ st.session_state.chat_history.append({"role": "user", "content": question})
846
+
847
+ # Emergency check
848
+ if priority == "Emergency" or any(word in question.lower() for word in ['chest pain', "can't breathe", 'severe pain', 'bleeding']):
849
+ st.markdown("""
850
+ <div class="error-alert">
851
+ <h4>🚨 MEDICAL EMERGENCY ALERT</h4>
852
+ <p><strong>If this is a medical emergency, please call emergency services immediately (102/108) or visit the nearest hospital!</strong></p>
853
+ </div>
854
+ """, unsafe_allow_html=True)
855
+
856
+ # Get AI response
857
+ with st.spinner("🧠 MedAI is analyzing your question..."):
858
+ response = st.session_state.medical_ai.ask_medical_question(user.user_id, question)
859
+
860
+ if response['success']:
861
+ # Add AI response
862
+ st.session_state.chat_history.append({"role": "assistant", "content": response['answer']})
863
+
864
+ # Display response
865
+ st.markdown(f"""
866
+ <div class="chat-message assistant-message">
867
+ <strong>πŸ€– MedAI:</strong> {response['answer']}
868
+ </div>
869
+ """, unsafe_allow_html=True)
870
+
871
+ st.rerun()
872
+ else:
873
+ st.error(f"❌ Consultation error: {response['error']}")
874
+
875
+ # Medical disclaimer
876
+ st.markdown("""
877
+ <div class="medical-disclaimer">
878
+ <h4>⚠️ IMPORTANT MEDICAL DISCLAIMER</h4>
879
+ <p>This AI assistant provides general health information for educational purposes only.
880
+ It is not a substitute for professional medical advice, diagnosis, or treatment.
881
+ Always consult qualified healthcare professionals for medical concerns.</p>
882
+ </div>
883
+ """, unsafe_allow_html=True)
884
+
885
+ def create_report_analysis():
886
+ """Medical Report Analysis Interface"""
887
+ st.markdown("## πŸ“‹ Medical Report Analysis")
888
+
889
+ st.markdown("""
890
+ <div class="feature-card">
891
+ <h4>πŸ”¬ AI-Powered Report Analysis</h4>
892
+ <p>Upload images of your medical reports for AI analysis. Supports blood tests, urine tests,
893
+ lipid profiles, liver function tests, kidney function tests, and more.</p>
894
+ <p><strong>Supported formats:</strong> PNG, JPG, JPEG</p>
895
+ </div>
896
+ """, unsafe_allow_html=True)
897
+
898
+ # File upload
899
+ uploaded_file = st.file_uploader(
900
+ "πŸ“ Choose Medical Report Image",
901
+ type=['png', 'jpg', 'jpeg'],
902
+ help="Upload a clear image of your medical report"
903
+ )
904
+
905
+ if uploaded_file:
906
+ image = Image.open(uploaded_file)
907
+
908
+ col1, col2 = st.columns([1, 1])
909
+
910
+ with col1:
911
+ st.markdown("### πŸ“· Uploaded Report")
912
+ st.image(image, caption="Your medical report", use_column_width=True)
913
+
914
+ # Image quality check
915
+ width, height = image.size
916
+ if width < 800 or height < 600:
917
+ st.warning("⚠️ Low resolution detected. Higher resolution images provide better analysis.")
918
+
919
+ with col2:
920
+ if st.button("πŸ” Analyze Report", type="primary", use_container_width=True):
921
+ with st.spinner("🧠 Analyzing your medical report..."):
922
+ result = st.session_state.medical_ai.analyze_medical_report(image)
923
+
924
+ if result['success']:
925
+ st.markdown("### πŸ“Š AI Analysis Results")
926
+ st.markdown(result['analysis'])
927
+
928
+ # Show extracted text
929
+ with st.expander("πŸ“ Extracted Text Preview", expanded=False):
930
+ st.text(result.get('extracted_text', 'Text extraction unavailable'))
931
+
932
+ if st.session_state.current_user:
933
+ st.success("βœ… Analysis complete! Results ready for consultation.")
934
+
935
+ else:
936
+ st.error(f"❌ Analysis failed: {result['error']}")
937
+
938
+ # Tips for better results
939
+ with st.expander("πŸ’‘ Tips for Better Analysis", expanded=False):
940
+ st.markdown("""
941
+ **For optimal results:**
942
+
943
+ 1. **πŸ“Έ Clear Image:** Ensure good lighting and sharp text
944
+ 2. **πŸ“ Straight Orientation:** Keep the report upright
945
+ 3. **πŸ” High Resolution:** Use at least 800x600 pixels
946
+ 4. **πŸ“‹ Complete Report:** Include all sections and reference ranges
947
+ 5. **πŸ₯ Official Reports:** Use certified laboratory reports
948
+
949
+ **Supported Report Types:**
950
+ - Complete Blood Count (CBC)
951
+ - Blood Chemistry Panels
952
+ - Lipid Profiles
953
+ - Liver & Kidney Function Tests
954
+ - Thyroid Function Tests
955
+ - Diabetes Monitoring (HbA1c, Glucose)
956
+ """)
957
+
958
+ def create_diabetic_retinopathy_screening():
959
+ """Diabetic Retinopathy Screening Interface"""
960
+ st.markdown("## πŸ‘οΈ AI Eye Screening")
961
+
962
+ if not st.session_state.medical_ai.dr_model_loaded:
963
+ st.markdown("""
964
+ <div class="error-alert">
965
+ <h4>❌ Eye Screening Unavailable</h4>
966
+ <p>The diabetic retinopathy screening model could not be loaded. Please try refreshing the page.</p>
967
+ </div>
968
+ """, unsafe_allow_html=True)
969
+ return
970
+
971
+ st.markdown("""
972
+ <div class="feature-card">
973
+ <h4>πŸ”¬ AI-Powered Diabetic Retinopathy Screening</h4>
974
+ <p>Upload retinal fundus images for AI screening of diabetic retinopathy.
975
+ Our custom deep learning model can detect signs of eye complications in diabetic patients.</p>
976
+ <p><strong>Model:</strong> Arko007/diabetic-retinopathy-v1 (Custom trained for Indian population)</p>
977
+ </div>
978
+ """, unsafe_allow_html=True)
979
+
980
+ # Upload interface
981
+ uploaded_image = st.file_uploader(
982
+ "πŸ“ Upload Retinal Fundus Image",
983
+ type=['png', 'jpg', 'jpeg'],
984
+ help="Upload a clear retinal photograph",
985
+ key="dr_image_upload"
986
+ )
987
+
988
+ if uploaded_image:
989
+ image = Image.open(uploaded_image)
990
+
991
+ col1, col2 = st.columns([1, 1])
992
+
993
+ with col1:
994
+ st.markdown("### πŸ‘οΈ Retinal Image")
995
+ st.image(image, caption="Retinal fundus image", use_column_width=True)
996
+
997
+ # Image info
998
+ width, height = image.size
999
+ st.info(f"πŸ“ Image dimensions: {width}Γ—{height} pixels")
1000
+
1001
+ if width < 384 or height < 384:
1002
+ st.warning("⚠️ Minimum recommended resolution: 384Γ—384 pixels")
1003
+
1004
+ with col2:
1005
+ if st.button("πŸ” Screen for Diabetic Retinopathy", type="primary", use_container_width=True):
1006
+ with st.spinner("🧠 AI is analyzing the retinal image..."):
1007
+ result = st.session_state.medical_ai.analyze_diabetic_retinopathy(image)
1008
+
1009
+ if result['success']:
1010
+ classification = result['classification']
1011
+ confidence = result['confidence']
1012
+
1013
+ # Severity color coding
1014
+ severity_colors = {
1015
+ "No DR": "🟒",
1016
+ "Mild DR": "🟑",
1017
+ "Moderate DR": "🟠",
1018
+ "Severe DR": "πŸ”΄",
1019
+ "Proliferative DR": "πŸ”΄"
1020
+ }
1021
+
1022
+ color = severity_colors.get(classification, "βšͺ")
1023
+
1024
+ st.markdown(f"""
1025
+ <div class="success-alert">
1026
+ <h3>{color} AI Screening Result: {classification}</h3>
1027
+ <p><strong>Model Confidence:</strong> {confidence:.1%}</p>
1028
+ </div>
1029
+ """, unsafe_allow_html=True)
1030
+
1031
+ # Confidence bar
1032
+ st.progress(confidence)
1033
+
1034
+ # Detailed analysis
1035
+ st.markdown("### πŸ“Š Detailed Analysis")
1036
+ st.markdown(result['analysis'])
1037
+
1038
+ # Recommendations
1039
+ st.markdown("### πŸ’‘ Recommendations")
1040
+ if classification == "No DR":
1041
+ st.success("βœ… No diabetic retinopathy detected. Continue regular eye checkups.")
1042
+ elif classification == "Mild DR":
1043
+ st.warning("⚠️ Mild diabetic retinopathy detected. Schedule follow-up in 6-12 months.")
1044
+ elif classification in ["Moderate DR", "Severe DR"]:
1045
+ st.error("πŸ”΄ Significant diabetic retinopathy detected. Consult an ophthalmologist promptly.")
1046
+ elif classification == "Proliferative DR":
1047
+ st.error("🚨 Advanced diabetic retinopathy detected. URGENT ophthalmologist consultation required!")
1048
+
1049
+ if st.session_state.current_user:
1050
+ st.info("πŸ’Ύ Screening results saved to your profile.")
1051
+
1052
+ else:
1053
+ st.error(f"❌ Screening failed: {result['error']}")
1054
+
1055
+ # Educational information
1056
+ st.markdown("### πŸ“š Understanding Diabetic Retinopathy")
1057
+
1058
+ with st.expander("ℹ️ About Diabetic Retinopathy", expanded=False):
1059
+ st.markdown("""
1060
+ **What is Diabetic Retinopathy?**
1061
+
1062
+ A diabetes complication affecting the eyes, caused by damage to retinal blood vessels.
1063
+
1064
+ **Screening Stages:**
1065
+
1066
+ 1. **🟒 No DR:** No signs detected
1067
+ 2. **🟑 Mild DR:** Early changes (microaneurysms)
1068
+ 3. **🟠 Moderate DR:** Blood vessels become blocked
1069
+ 4. **πŸ”΄ Severe DR:** Significant blood vessel blockage
1070
+ 5. **πŸ”΄ Proliferative DR:** Advanced stage with new vessel growth
1071
+
1072
+ **Risk Factors:**
1073
+ - Duration of diabetes
1074
+ - Poor blood sugar control
1075
+ - High blood pressure
1076
+ - Pregnancy in diabetic women
1077
+
1078
+ **Prevention:**
1079
+ - Maintain good blood sugar control
1080
+ - Regular eye examinations
1081
+ - Control blood pressure and cholesterol
1082
+ - Healthy lifestyle choices
1083
+ """)
1084
+
1085
+ # Screening disclaimer
1086
+ st.markdown("""
1087
+ <div class="medical-disclaimer">
1088
+ <h4>⚠️ SCREENING DISCLAIMER</h4>
1089
+ <p>This AI screening tool is for educational purposes only. It is not a medical device
1090
+ and cannot replace professional eye examination. Always consult qualified ophthalmologists
1091
+ for proper diagnosis and treatment of eye conditions.</p>
1092
+ </div>
1093
+ """, unsafe_allow_html=True)
1094
+
1095
+ def generate_health_metrics(profile_data=None, days=30):
1096
+ """Generate sample health data for analytics"""
1097
+ dates = pd.date_range(start=datetime.date.today() - datetime.timedelta(days=days),
1098
+ periods=days, freq='D')
1099
+
1100
+ # Base values from profile
1101
+ if profile_data:
1102
+ base_weight = profile_data.weight
1103
+ base_sugar = profile_data.blood_sugar if profile_data.blood_sugar > 0 else 95
1104
+ bp_parts = profile_data.blood_pressure.split('/')
1105
+ base_bp_sys = float(bp_parts[0]) if len(bp_parts) == 2 else 120
1106
+ base_bp_dia = float(bp_parts[1]) if len(bp_parts) == 2 else 80
1107
+ else:
1108
+ base_weight, base_sugar, base_bp_sys, base_bp_dia = 70, 95, 120, 80
1109
+
1110
+ # Generate realistic variations
1111
+ np.random.seed(42)
1112
+ weight = np.random.normal(base_weight, 0.5, days)
1113
+ blood_sugar = np.clip(np.random.normal(base_sugar, 10, days), 70, 300)
1114
+ bp_systolic = np.clip(np.random.normal(base_bp_sys, 8, days), 90, 180)
1115
+ bp_diastolic = np.clip(np.random.normal(base_bp_dia, 5, days), 60, 120)
1116
+ steps = np.maximum(2000, np.random.normal(8000, 1500, days)).astype(int)
1117
+ sleep_hours = np.clip(np.random.normal(7.5, 1, days), 5, 10)
1118
+
1119
+ return pd.DataFrame({
1120
+ 'date': dates,
1121
+ 'weight': weight.round(1),
1122
+ 'blood_sugar': blood_sugar.round(0),
1123
+ 'bp_systolic': bp_systolic.round(0),
1124
+ 'bp_diastolic': bp_diastolic.round(0),
1125
+ 'steps': steps,
1126
+ 'sleep_hours': sleep_hours.round(1)
1127
+ })
1128
+
1129
+ def create_health_analytics():
1130
+ """Health Analytics Dashboard"""
1131
+ st.markdown("## πŸ“Š Health Analytics Dashboard")
1132
+
1133
+ if not st.session_state.current_user:
1134
+ st.markdown("""
1135
+ <div class="warning-alert">
1136
+ <h4>⚠️ Patient Profile Required</h4>
1137
+ <p>Create a patient profile to view personalized health analytics.</p>
1138
+ </div>
1139
+ """, unsafe_allow_html=True)
1140
+ return
1141
+
1142
+ user = st.session_state.current_user
1143
+ health_data = generate_health_metrics(user)
1144
+
1145
+ # Health score calculation
1146
+ bmi_score = 25 if 18.5 <= user.bmi <= 25 else 15
1147
+ sugar_score = 25 if user.blood_sugar <= 100 else 15
1148
+ bp_parts = user.blood_pressure.split('/')
1149
+ bp_score = 25 if len(bp_parts) == 2 and int(bp_parts[0]) <= 120 and int(bp_parts[1]) <= 80 else 15
1150
+ activity_score = 25 # Assume good activity
1151
+
1152
+ total_score = bmi_score + sugar_score + bp_score + activity_score
1153
+
1154
+ # Dashboard tabs
1155
+ tab1, tab2, tab3 = st.tabs(["πŸ“ˆ Overview", "πŸ“Š Detailed Metrics", "🎯 Health Score"])
1156
+
1157
+ with tab1:
1158
+ st.subheader("πŸ“Š Health Overview")
1159
+
1160
+ # Key metrics
1161
+ col1, col2, col3, col4 = st.columns(4)
1162
+
1163
+ latest = health_data.iloc[-1]
1164
+
1165
+ with col1:
1166
+ st.metric("Current Weight", f"{latest['weight']:.1f} kg",
1167
+ delta=f"{latest['weight'] - health_data['weight'].mean():+.1f}")
1168
+ with col2:
1169
+ st.metric("Blood Sugar", f"{latest['blood_sugar']:.0f} mg/dL",
1170
+ delta=f"{latest['blood_sugar'] - health_data['blood_sugar'].mean():+.0f}")
1171
+ with col3:
1172
+ st.metric("Blood Pressure", f"{latest['bp_systolic']:.0f}/{latest['bp_diastolic']:.0f}",
1173
+ help="Systolic/Diastolic pressure in mmHg")
1174
+ with col4:
1175
+ st.metric("Daily Steps", f"{latest['steps']:,}",
1176
+ delta=f"{latest['steps'] - health_data['steps'].mean():+,.0f}")
1177
+
1178
+ # Trends chart
1179
+ fig = make_subplots(
1180
+ rows=2, cols=2,
1181
+ subplot_titles=('Weight Trend', 'Blood Sugar', 'Blood Pressure', 'Activity'),
1182
+ specs=[[{"secondary_y": False}, {"secondary_y": False}],
1183
+ [{"secondary_y": False}, {"secondary_y": False}]]
1184
+ )
1185
+
1186
+ fig.add_trace(go.Scatter(x=health_data['date'], y=health_data['weight'],
1187
+ name='Weight', line=dict(color='blue')), row=1, col=1)
1188
+ fig.add_trace(go.Scatter(x=health_data['date'], y=health_data['blood_sugar'],
1189
+ name='Blood Sugar', line=dict(color='red')), row=1, col=2)
1190
+ fig.add_trace(go.Scatter(x=health_data['date'], y=health_data['bp_systolic'],
1191
+ name='Systolic', line=dict(color='orange')), row=2, col=1)
1192
+ fig.add_trace(go.Scatter(x=health_data['date'], y=health_data['steps'],
1193
+ name='Steps', line=dict(color='green')), row=2, col=2)
1194
+
1195
+ fig.update_layout(height=600, showlegend=False, title_text="30-Day Health Trends")
1196
+ st.plotly_chart(fig, use_container_width=True)
1197
+
1198
+ with tab2:
1199
+ st.subheader("πŸ“ˆ Detailed Health Metrics")
1200
+
1201
+ # Data table
1202
+ st.markdown("#### Recent Health Records")
1203
+ display_data = health_data.tail(7).copy()
1204
+ display_data['date'] = display_data['date'].dt.strftime('%Y-%m-%d')
1205
+ st.dataframe(display_data, use_container_width=True)
1206
+
1207
+ # Correlation analysis
1208
+ st.markdown("#### Health Metrics Correlation")
1209
+ corr_data = health_data[['weight', 'blood_sugar', 'bp_systolic', 'steps', 'sleep_hours']].corr()
1210
+ fig_corr = px.imshow(corr_data, title="Health Metrics Correlation Matrix",
1211
+ color_continuous_scale='RdBu_r', aspect="auto")
1212
+ st.plotly_chart(fig_corr, use_container_width=True)
1213
+
1214
+ with tab3:
1215
+ st.subheader("🎯 Personal Health Score")
1216
+
1217
+ # Health score gauge
1218
+ fig_gauge = go.Figure(go.Indicator(
1219
+ mode="gauge+number",
1220
+ value=total_score,
1221
+ domain={'x': [0, 1], 'y': [0, 1]},
1222
+ title={'text': "Overall Health Score"},
1223
+ gauge={
1224
+ 'axis': {'range': [None, 100]},
1225
+ 'bar': {'color': "darkblue"},
1226
+ 'steps': [
1227
+ {'range': [0, 60], 'color': "lightgray"},
1228
+ {'range': [60, 80], 'color': "yellow"},
1229
+ {'range': [80, 100], 'color': "green"}
1230
+ ],
1231
+ 'threshold': {
1232
+ 'line': {'color': "red", 'width': 4},
1233
+ 'thickness': 0.75,
1234
+ 'value': 90
1235
+ }
1236
+ }
1237
+ ))
1238
+
1239
+ st.plotly_chart(fig_gauge, use_container_width=True)
1240
+
1241
+ # Score breakdown
1242
+ col1, col2, col3, col4 = st.columns(4)
1243
+ with col1:
1244
+ st.metric("BMI Score", f"{bmi_score}/25")
1245
+ with col2:
1246
+ st.metric("Blood Sugar Score", f"{sugar_score}/25")
1247
+ with col3:
1248
+ st.metric("Blood Pressure Score", f"{bp_score}/25")
1249
+ with col4:
1250
+ st.metric("Activity Score", f"{activity_score}/25")
1251
+
1252
+ # Recommendations
1253
+ st.markdown("### πŸ’‘ Personalized Health Recommendations")
1254
+
1255
+ recommendations = []
1256
+ if bmi_score < 25:
1257
+ recommendations.append("πŸ‹οΈ Focus on achieving a healthy BMI through balanced nutrition and exercise")
1258
+ if sugar_score < 25:
1259
+ recommendations.append("🍎 Monitor blood sugar levels and consider dietary adjustments")
1260
+ if bp_score < 25:
1261
+ recommendations.append("🩺 Keep track of blood pressure and practice stress management")
1262
+
1263
+ if not recommendations:
1264
+ recommendations.append("πŸŽ‰ Excellent health metrics! Continue your healthy lifestyle.")
1265
+
1266
+ for rec in recommendations:
1267
+ st.success(rec)
1268
+
1269
+ def create_dashboard_home():
1270
+ """Main dashboard home page"""
1271
+ display_main_header()
1272
+
1273
+ if not st.session_state.current_user:
1274
+ # Welcome screen
1275
+ st.markdown("## 🌟 Welcome to MedAI Suite")
1276
+
1277
+ col1, col2 = st.columns([2, 1])
1278
+
1279
+ with col1:
1280
+ st.markdown("""
1281
+ <div class="feature-card">
1282
+ <h3>πŸš€ Your AI-Powered Health Platform</h3>
1283
+ <p>Get started with comprehensive healthcare AI tools:</p>
1284
+ <ul>
1285
+ <li><strong>πŸ€– Medical Consultation:</strong> Personalized health guidance from AI</li>
1286
+ <li><strong>πŸ“‹ Report Analysis:</strong> AI analysis of blood tests and medical reports</li>
1287
+ <li><strong>πŸ‘οΈ Eye Screening:</strong> Diabetic retinopathy detection using custom AI</li>
1288
+ <li><strong>πŸ“Š Health Analytics:</strong> Track and visualize your health metrics</li>
1289
+ </ul>
1290
+ <h4>πŸ‘€ Create your patient profile to begin!</h4>
1291
+ </div>
1292
+ """, unsafe_allow_html=True)
1293
+
1294
+ with col2:
1295
+ st.markdown("### 🎯 Quick Start")
1296
+ if st.button("πŸ‘€ Create Patient Profile", use_container_width=True, type="primary"):
1297
+ st.session_state.page = "πŸ‘€ Patient Profile"
1298
+ st.rerun()
1299
+
1300
+ st.markdown("### πŸ”§ System Status")
1301
+ status_items = [
1302
+ ("πŸ€– AI Consultation", "Ready"),
1303
+ ("πŸ“‹ Report Analysis", "Ready"),
1304
+ ("πŸ‘οΈ Eye Screening", "Ready" if st.session_state.medical_ai.dr_model_loaded else "Loading"),
1305
+ ("πŸ“Š Health Analytics", "Ready")
1306
+ ]
1307
+
1308
+ for item, status in status_items:
1309
+ color = "🟒" if status == "Ready" else "🟑"
1310
+ st.markdown(f"{color} {item}: {status}")
1311
+
1312
+ # Feature showcase
1313
+ st.markdown("## πŸ₯ Platform Features")
1314
+
1315
+ col1, col2, col3, col4 = st.columns(4)
1316
+
1317
+ features = [
1318
+ ("πŸ€–", "AI Consultation", "Get personalized medical advice"),
1319
+ ("πŸ“‹", "Report Analysis", "Understand your medical reports"),
1320
+ ("πŸ‘οΈ", "Eye Screening", "Detect diabetic retinopathy"),
1321
+ ("πŸ“Š", "Health Analytics", "Track your health progress")
1322
+ ]
1323
+
1324
+ for col, (icon, title, desc) in zip([col1, col2, col3, col4], features):
1325
+ with col:
1326
+ st.markdown(f"""
1327
+ <div class="feature-card" style="text-align: center; height: 200px;">
1328
+ <h1>{icon}</h1>
1329
+ <h4>{title}</h4>
1330
+ <p>{desc}</p>
1331
+ </div>
1332
+ """, unsafe_allow_html=True)
1333
+
1334
+ else:
1335
+ # User dashboard
1336
+ user = st.session_state.current_user
1337
+
1338
+ st.markdown(f"## πŸ‘‹ Welcome back, {user.name}!")
1339
+
1340
+ # Quick stats
1341
+ col1, col2, col3, col4 = st.columns(4)
1342
+
1343
+ consultations = len(st.session_state.medical_ai.get_conversation_history(user.user_id))
1344
+ days_active = (datetime.datetime.now() - datetime.datetime.fromisoformat(user.created_at)).days
1345
+
1346
+ with col1:
1347
+ st.metric("πŸ’¬ Consultations", consultations)
1348
+ with col2:
1349
+ st.metric("πŸ“… Days Active", days_active)
1350
+ with col3:
1351
+ st.metric("🎯 Health Score", "85/100")
1352
+ with col4:
1353
+ st.metric("βš–οΈ BMI Status", st.session_state.medical_ai.get_bmi_category(user.bmi))
1354
+
1355
+ # Quick actions
1356
+ st.markdown("### ⚑ Quick Actions")
1357
+
1358
+ col1, col2, col3, col4 = st.columns(4)
1359
+
1360
+ action_buttons = [
1361
+ ("πŸ€– AI Consultation", "πŸ€– Medical Consultation"),
1362
+ ("πŸ“‹ Analyze Report", "πŸ“‹ Report Analysis"),
1363
+ ("πŸ‘οΈ Eye Screening", "πŸ‘οΈ Eye Screening"),
1364
+ ("πŸ“Š Health Dashboard", "πŸ“Š Health Analytics")
1365
+ ]
1366
+
1367
+ for col, (title, page) in zip([col1, col2, col3, col4], action_buttons):
1368
+ with col:
1369
+ if st.button(title, use_container_width=True):
1370
+ st.session_state.page = page
1371
+ st.rerun()
1372
+
1373
+ # Recent activity
1374
+ st.markdown("### πŸ“‹ Recent Activity")
1375
+
1376
+ recent_history = st.session_state.medical_ai.get_conversation_history(user.user_id, limit=3)
1377
+
1378
+ if recent_history:
1379
+ for i, conv in enumerate(recent_history[::-1], 1):
1380
+ with st.expander(f"πŸ’¬ Consultation {i} - {conv['timestamp'][:16]}"):
1381
+ st.markdown(f"**Question:** {conv['question'][:150]}...")
1382
+ st.markdown(f"**Response:** {conv['answer'][:200]}...")
1383
+ else:
1384
+ st.info("πŸ” No consultations yet. Start your first AI consultation!")
1385
+
1386
+ # =============================================================================
1387
+ # MAIN APPLICATION LOGIC
1388
+ # =============================================================================
1389
+
1390
+ def main():
1391
+ """Main application entry point"""
1392
+ # Load custom CSS
1393
+ load_custom_css()
1394
+
1395
+ # Initialize session state
1396
+ initialize_session_state()
1397
+
1398
+ # Create sidebar
1399
+ create_sidebar()
1400
+
1401
+ # Route to appropriate page
1402
+ page = st.session_state.page
1403
+
1404
+ if page == "πŸ₯ Dashboard":
1405
+ create_dashboard_home()
1406
+
1407
+ elif page == "πŸ‘€ Patient Profile":
1408
+ if st.session_state.current_user:
1409
+ display_patient_profile()
1410
+ st.markdown("---")
1411
+ if st.button("✏️ Create New Profile", type="secondary"):
1412
+ st.session_state.current_user = None
1413
+ st.session_state.chat_history = []
1414
+ st.rerun()
1415
+ else:
1416
+ create_patient_profile_form()
1417
+
1418
+ elif page == "πŸ€– Medical Consultation":
1419
+ create_medical_consultation()
1420
+
1421
+ elif page == "πŸ“‹ Report Analysis":
1422
+ create_report_analysis()
1423
+
1424
+ elif page == "πŸ‘οΈ Eye Screening":
1425
+ create_diabetic_retinopathy_screening()
1426
+
1427
+ elif page == "πŸ“Š Health Analytics":
1428
+ create_health_analytics()
1429
+
1430
+ else:
1431
+ create_dashboard_home()
1432
+
1433
+ # =============================================================================
1434
+ # APPLICATION ENTRY POINT
1435
+ # =============================================================================
1436
 
1437
+ if __name__ == "__main__":
1438
+ main()