leilaghomashchi commited on
Commit
8470ba0
·
verified ·
1 Parent(s): 19c5ce5
Files changed (1) hide show
  1. app.py +1112 -0
app.py ADDED
@@ -0,0 +1,1112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import numpy as np
4
+ import plotly.express as px
5
+ import plotly.graph_objects as go
6
+ from plotly.subplots import make_subplots
7
+ import warnings
8
+
9
+ warnings.filterwarnings('ignore')
10
+
11
+ class CGMAnalyzer:
12
+ def __init__(self):
13
+ self.data = None
14
+ self.columns = []
15
+
16
+ # داده‌های نمونه CGM
17
+ self.sample_data = [
18
+ {'تاریخ': '2024-01-15', 'زمان': '07:30', 'قند_خون': 125, 'روند': 'افزایش_تند', 'وضعیت': 'نرمال', 'فعالیت': 'صبحانه', 'وعده_غذایی': 'صبحانه', 'انسولین': 5, 'استرس': 'کم', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '120/80', 'دارو': 'متفورمین', 'وزن': 75.2, 'ضربان_قلب': 72, 'مایعات_مصرفی': 250, 'قدم_ها': 320, 'کالری_مصرفی': 280, 'یادداشت': ''},
19
+ {'تاریخ': '2024-01-15', 'زمان': '08:00', 'قند_خون': 175, 'روند': 'افزایش_آرام', 'وضعیت': 'بالا', 'فعالیت': 'نشسته', 'وعده_غذایی': 'نداشته', 'انسولین': 0, 'استرس': 'متوسط', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '125/85', 'دارو': 'هیچ', 'وزن': 75.1, 'ضربان_قلب': 78, 'مایعات_مصرفی': 180, 'قدم_ها': 150, 'کالری_مصرفی': 0, 'یادداشت': 'کمی گرسنه'},
20
+ {'تاریخ': '2024-01-15', 'زمان': '09:00', 'قند_خون': 152, 'روند': 'کاهش_آرام', 'وضعیت': 'بالا', 'فعالیت': 'کار', 'وعده_غذایی': 'نداشته', 'انسولین': 0, 'استرس': 'زیاد', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '130/90', 'دارو': 'هیچ', 'وزن': 75.0, 'ضربان_قلب': 85, 'مایعات_مصرفی': 200, 'قدم_ها': 450, 'کالری_مصرفی': 0, 'یادداشت': ''},
21
+ {'تاریخ': '2024-01-15', 'زمان': '10:00', 'قند_خون': 108, 'روند': 'کاهش_آرام', 'وضعیت': 'نرمال', 'فعالیت': 'کار', 'وعده_غذایی': 'نداشته', 'انسولین': 0, 'استرس': 'کم', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '118/78', 'دارو': 'هیچ', 'وزن': 74.9, 'ضربان_قلب': 70, 'مایعات_مصرفی': 220, 'قدم_ها': 680, 'کالری_مصرفی': 0, 'یادداشت': ''},
22
+ {'تاریخ': '2024-01-15', 'زمان': '12:30', 'قند_خون': 135, 'روند': 'افزایش_تند', 'وضعیت': 'نرمال', 'فعالیت': 'ناهار', 'وعده_غذایی': 'ناهار', 'انسولین': 3, 'استرس': 'کم', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '115/75', 'دارو': 'هیچ', 'وزن': 74.8, 'ضربان_قلب': 68, 'مایعات_مصرفی': 320, 'قدم_ها': 1250, 'کالری_مصرفی': 450, 'یادداشت': ''},
23
+ {'تاریخ': '2024-01-15', 'زمان': '13:00', 'قند_خون': 185, 'روند': 'افزایش_آرام', 'وضعیت': 'بالا', 'فعالیت': 'نشسته', 'وعده_غذایی': 'نداشته', 'انسولین': 0, 'استرس': 'کم', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '122/82', 'دارو': 'هیچ', 'وزن': 74.7, 'ضربان_قلب': 75, 'مایعات_مصرفی': 180, 'قدم_ها': 80, 'کالری_مصرفی': 0, 'یادداشت': ''},
24
+ {'تاریخ': '2024-01-15', 'زمان': '17:00', 'قند_خون': 95, 'روند': 'پایدار', 'وضعیت': 'نرمال', 'فعالیت': 'ورزش', 'وعده_غذایی': 'نداشته', 'انسولین': 0, 'استرس': 'کم', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '110/70', 'دارو': 'هیچ', 'وزن': 74.5, 'ضربان_قلب': 95, 'مایعات_مصرفی': 400, 'قدم_ها': 5200, 'کالری_مصرفی': 0, 'یادداشت': 'احساس خوب'},
25
+ {'تاریخ': '2024-01-15', 'زمان': '19:30', 'قند_خون': 145, 'روند': 'افزایش_تند', 'وضعیت': 'نرمال', 'فعالیت': 'شام', 'وعده_غذایی': 'شام', 'انسولین': 4, 'استرس': 'کم', 'خواب': 'خیر', 'کیفیت_خواب': 'خوب', 'آب_وهوا': 'آفتابی', 'فشار_خون': '125/85', 'دارو': 'هیچ', 'وزن': 74.4, 'ضربان_قلب': 72, 'مایعات_مصرفی': 250, 'قدم_ها': 420, 'کالری_مصرفی': 380, 'یادداشت': ''}
26
+ ]
27
+
28
+ # سوالات آماده
29
+ self.diabetic_queries = [
30
+ 'قند من معمولاً چقدر است؟',
31
+ 'چقدر وقت قندم نرمال بوده؟',
32
+ 'قندم چه ساعاتی بالا می‌رود؟',
33
+ 'چه ساعاتی قندم نرمال است؟',
34
+ 'چند بار قندم خیلی پایین شده؟',
35
+ 'چند بار قندم خیلی بالا رفته؟',
36
+ 'کدام غذاها قندم را بالا می‌برند؟',
37
+ 'ورزش چه تاثیری روی قندم دارد؟',
38
+ 'انسولین چقدر قندم را پایین می‌آورد؟',
39
+ 'استرس چقدر قندم را بالا می‌برد؟',
40
+ 'آب‌وهوا چطور روی قندم تاثیر می‌گذارد؟',
41
+ 'کیفیت خوابم چه تاثیری روی قند دارد؟',
42
+ 'چقدر ورزش کرده‌ام؟',
43
+ 'فشار خونم چطوره؟',
44
+ 'وزنم چطور تغییر کرده؟'
45
+ ]
46
+
47
+ def get_column_safely(self, column_keywords):
48
+ """پیدا کردن ستون به صورت ایمن"""
49
+ for keyword in column_keywords:
50
+ for col in self.columns:
51
+ if keyword in col:
52
+ return col
53
+ return None
54
+
55
+ def load_sample_data(self):
56
+ """بارگذاری داده‌های نمونه"""
57
+ self.data = pd.DataFrame(self.sample_data)
58
+ self.columns = list(self.data.columns)
59
+ # نمایش همه داده‌های نمونه (8 رکورد)
60
+ return self.data, "✅ داده‌های نمونه CGM بارگذاری شد"
61
+
62
+ def upload_file(self, file):
63
+ """بارگذاری فایل CSV"""
64
+ if file is None:
65
+ return None, "❌ لطفاً فایل CSV انتخاب کنید"
66
+
67
+ try:
68
+ # خواندن فایل CSV
69
+ self.data = pd.read_csv(file.name, encoding='utf-8')
70
+
71
+ # اگر UTF-8 کار نکرد، encoding های دیگر را امتحان کن
72
+ if self.data.empty:
73
+ self.data = pd.read_csv(file.name, encoding='cp1256')
74
+
75
+ self.columns = list(self.data.columns)
76
+
77
+ # تبدیل ستون‌های عددی
78
+ for col in self.columns:
79
+ if col in ['قند_خون', 'انسولین'] or 'قند' in col:
80
+ self.data[col] = pd.to_numeric(self.data[col], errors='coerce')
81
+
82
+ # نمایش تعداد بیشتری از رکوردها (25 به جای 10)
83
+ return self.data.head(25), f"✅ {len(self.data)} رکورد CGM با موفقیت بارگذاری شد"
84
+
85
+ except Exception as e:
86
+ return None, f"❌ خطا در خواندن فایل: {str(e)}"
87
+
88
+ def calculate_diabetic_stats(self):
89
+ """محاسبه آمار دیابت"""
90
+ if self.data is None or self.data.empty:
91
+ return None
92
+
93
+ # پیدا کردن ستون قند خون
94
+ glucose_col = None
95
+ for col in self.columns:
96
+ if 'قند' in col or 'glucose' in col.lower():
97
+ glucose_col = col
98
+ break
99
+
100
+ if glucose_col is None:
101
+ return None
102
+
103
+ glucose_values = self.data[glucose_col].dropna()
104
+ if len(glucose_values) == 0:
105
+ return None
106
+
107
+ # محاسبه آمار
108
+ time_in_range = len(glucose_values[(glucose_values >= 70) & (glucose_values <= 140)])
109
+ time_in_range_percent = (time_in_range / len(glucose_values)) * 100
110
+
111
+ hypo_count = len(glucose_values[glucose_values < 70])
112
+ hyper_count = len(glucose_values[glucose_values > 180])
113
+
114
+ mean_glucose = glucose_values.mean()
115
+ std_glucose = glucose_values.std()
116
+ cv = (std_glucose / mean_glucose) * 100 if mean_glucose > 0 else 0
117
+
118
+ return {
119
+ 'mean': mean_glucose,
120
+ 'time_in_range': time_in_range_percent,
121
+ 'hypo_count': hypo_count,
122
+ 'hyper_count': hyper_count,
123
+ 'variability': cv,
124
+ 'total_readings': len(glucose_values)
125
+ }
126
+
127
+ def create_glucose_trend_chart(self):
128
+ """نمودار روند قند خون"""
129
+ if self.data is None:
130
+ return None
131
+
132
+ # پیدا کردن ستون‌های مورد نیاز
133
+ glucose_col = None
134
+ time_col = None
135
+
136
+ for col in self.columns:
137
+ if 'قند' in col or 'glucose' in col.lower():
138
+ glucose_col = col
139
+ if 'زمان' in col or 'time' in col.lower():
140
+ time_col = col
141
+
142
+ if glucose_col is None:
143
+ return None
144
+
145
+ # ساخت نمودار
146
+ fig = go.Figure()
147
+
148
+ if time_col:
149
+ x_data = self.data[time_col]
150
+ else:
151
+ x_data = range(len(self.data))
152
+
153
+ # اضافه کردن خط قند خون
154
+ fig.add_trace(go.Scatter(
155
+ x=x_data,
156
+ y=self.data[glucose_col],
157
+ mode='lines+markers',
158
+ name='قند خون',
159
+ line=dict(color='blue', width=2),
160
+ marker=dict(size=6)
161
+ ))
162
+
163
+ # اضافه کردن خطوط مرجع
164
+ fig.add_hline(y=70, line_dash="dash", line_color="red",
165
+ annotation_text="حد پایین (70)")
166
+ fig.add_hline(y=140, line_dash="dash", line_color="green",
167
+ annotation_text="حد بالا (140)")
168
+ fig.add_hline(y=180, line_dash="dash", line_color="orange",
169
+ annotation_text="خطرناک (180)")
170
+
171
+ # تنظیمات نمودار
172
+ fig.update_layout(
173
+ title="روند قند خون در طول زمان",
174
+ xaxis_title="زمان",
175
+ yaxis_title="قند خون (mg/dL)",
176
+ hovermode='x',
177
+ template="plotly_white"
178
+ )
179
+
180
+ return fig
181
+
182
+ def create_daily_pattern_chart(self):
183
+ """نمودار الگوی روزانه قند خون"""
184
+ if self.data is None:
185
+ return None
186
+
187
+ glucose_col = None
188
+ time_col = None
189
+
190
+ for col in self.columns:
191
+ if 'قند' in col or 'glucose' in col.lower():
192
+ glucose_col = col
193
+ if 'زمان' in col or 'time' in col.lower():
194
+ time_col = col
195
+
196
+ if glucose_col is None or time_col is None:
197
+ return None
198
+
199
+ # گروه‌بندی بر اساس ساعت
200
+ self.data['hour'] = self.data[time_col].str.split(':').str[0]
201
+ hourly_avg = self.data.groupby('hour')[glucose_col].mean().reset_index()
202
+
203
+ fig = go.Figure()
204
+ fig.add_trace(go.Bar(
205
+ x=hourly_avg['hour'],
206
+ y=hourly_avg[glucose_col],
207
+ name='متوسط قند در هر ساعت',
208
+ marker_color='lightblue'
209
+ ))
210
+
211
+ fig.update_layout(
212
+ title="الگوی روزانه قند خون",
213
+ xaxis_title="ساعت",
214
+ yaxis_title="متوسط قند خون (mg/dL)",
215
+ template="plotly_white"
216
+ )
217
+
218
+ return fig
219
+
220
+ def create_meal_impact_chart(self):
221
+ """نمودار تاثیر وعده‌های غذایی"""
222
+ if self.data is None:
223
+ return None
224
+
225
+ glucose_col = None
226
+ meal_col = None
227
+
228
+ for col in self.columns:
229
+ if 'قند' in col or 'glucose' in col.lower():
230
+ glucose_col = col
231
+ if 'وعده' in col or 'meal' in col.lower():
232
+ meal_col = col
233
+
234
+ if glucose_col is None or meal_col is None:
235
+ return None
236
+
237
+ meal_avg = self.data.groupby(meal_col)[glucose_col].mean().reset_index()
238
+
239
+ fig = go.Figure()
240
+ fig.add_trace(go.Pie(
241
+ labels=meal_avg[meal_col],
242
+ values=meal_avg[glucose_col],
243
+ name="تاثیر وعده‌های غذایی"
244
+ ))
245
+
246
+ fig.update_layout(
247
+ title="متوسط قند خون در وعده‌های مختلف",
248
+ template="plotly_white"
249
+ )
250
+
251
+ return fig
252
+
253
+ def create_weight_trend_chart(self):
254
+ """نمودار روند وزن"""
255
+ if self.data is None:
256
+ return None
257
+
258
+ weight_col = None
259
+ date_col = None
260
+
261
+ for col in self.columns:
262
+ if 'وزن' in col:
263
+ weight_col = col
264
+ if 'تاریخ' in col:
265
+ date_col = col
266
+
267
+ if weight_col is None or date_col is None:
268
+ return None
269
+
270
+ # گروه‌بندی بر اساس تاریخ و میانگین‌گیری
271
+ daily_weight = self.data.groupby(date_col)[weight_col].mean().reset_index()
272
+
273
+ fig = go.Figure()
274
+ fig.add_trace(go.Scatter(
275
+ x=daily_weight[date_col],
276
+ y=daily_weight[weight_col],
277
+ mode='lines+markers',
278
+ name='وزن روزانه',
279
+ line=dict(color='purple', width=3),
280
+ marker=dict(size=8)
281
+ ))
282
+
283
+ fig.update_layout(
284
+ title="روند تغییرات وزن",
285
+ xaxis_title="تاریخ",
286
+ yaxis_title="وزن (کیلوگرم)",
287
+ template="plotly_white"
288
+ )
289
+
290
+ return fig
291
+
292
+ def create_activity_chart(self):
293
+ """نمودار فعالیت فیزیکی"""
294
+ if self.data is None:
295
+ return None
296
+
297
+ steps_col = None
298
+ date_col = None
299
+
300
+ for col in self.columns:
301
+ if 'قدم' in col:
302
+ steps_col = col
303
+ if 'تاریخ' in col:
304
+ date_col = col
305
+
306
+ if steps_col is None or date_col is None:
307
+ return None
308
+
309
+ # گروه‌بندی بر اساس تاریخ
310
+ daily_steps = self.data.groupby(date_col)[steps_col].sum().reset_index()
311
+
312
+ fig = go.Figure()
313
+ fig.add_trace(go.Bar(
314
+ x=daily_steps[date_col],
315
+ y=daily_steps[steps_col],
316
+ name='قدم‌های روزانه',
317
+ marker_color='lightgreen'
318
+ ))
319
+
320
+ # اضافه کردن خط مرجع 10,000 قدم
321
+ fig.add_hline(y=10000, line_dash="dash", line_color="red",
322
+ annotation_text="هدف روزانه (10,000)")
323
+
324
+ fig.update_layout(
325
+ title="فعالیت فیزیکی روزانه",
326
+ xaxis_title="تاریخ",
327
+ yaxis_title="تعداد قدم",
328
+ template="plotly_white"
329
+ )
330
+
331
+ return fig
332
+
333
+ def create_stress_correlation_chart(self):
334
+ """نمودار همبستگی استرس و قند"""
335
+ if self.data is None:
336
+ return None
337
+
338
+ glucose_col = None
339
+ stress_col = None
340
+
341
+ for col in self.columns:
342
+ if 'قند' in col:
343
+ glucose_col = col
344
+ if 'استرس' in col:
345
+ stress_col = col
346
+
347
+ if glucose_col is None or stress_col is None:
348
+ return None
349
+
350
+ # تبدیل سطوح استرس به عدد برای نمودار
351
+ stress_mapping = {'خیلی_کم': 1, 'کم': 2, 'متوسط': 3, 'زیاد': 4, 'خیلی_زیاد': 5}
352
+ plot_data = self.data.copy()
353
+ plot_data['stress_numeric'] = plot_data[stress_col].map(stress_mapping)
354
+
355
+ fig = go.Figure()
356
+
357
+ for stress_level in plot_data[stress_col].unique():
358
+ stress_data = plot_data[plot_data[stress_col] == stress_level]
359
+ fig.add_trace(go.Scatter(
360
+ x=stress_data['stress_numeric'],
361
+ y=stress_data[glucose_col],
362
+ mode='markers',
363
+ name=f'استرس {stress_level}',
364
+ marker=dict(size=8, opacity=0.7)
365
+ ))
366
+
367
+ fig.update_layout(
368
+ title="رابطه بین سطح استرس و قند خون",
369
+ xaxis_title="سطح استرس",
370
+ yaxis_title="قند خون (mg/dL)",
371
+ xaxis=dict(
372
+ tickmode='array',
373
+ tickvals=[1, 2, 3, 4, 5],
374
+ ticktext=['خیلی کم', 'کم', 'متوسط', 'زیاد', 'خیلی زیاد']
375
+ ),
376
+ template="plotly_white"
377
+ )
378
+
379
+ return fig
380
+
381
+ def execute_query(self, query):
382
+ """اجرای سوالات کاربر"""
383
+ if self.data is None or self.data.empty:
384
+ return "❌ هیچ داده‌ای موجود نیست. لطفاً ابتدا فایل بارگذاری کنید یا داده نمونه را بارگذاری کنید."
385
+
386
+ query = query.strip()
387
+
388
+ try:
389
+ if query == 'قند من معمولاً چقدر است؟':
390
+ stats = self.calculate_diabetic_stats()
391
+ if stats:
392
+ return f"متوسط قند خون شما {stats['mean']:.0f} mg/dL است.\n" + \
393
+ ("این عدد خوب است! 🎉" if stats['mean'] < 140 else
394
+ "بهتر است با پزشک مشورت کنید. 👨‍⚕️" if stats['mean'] > 150 else "در حد قابل قبول است.")
395
+
396
+ elif query == 'چقدر وقت قندم نرمال بوده؟':
397
+ stats = self.calculate_diabetic_stats()
398
+ if stats:
399
+ return f"از {stats['total_readings']} بار اندازه‌گیری، {stats['time_in_range']:.1f}% وقت قند شما در حد نرمال (70-140) بوده است.\n" + \
400
+ ("عالی! 🎯" if stats['time_in_range'] > 70 else
401
+ "نیاز به بهبود دارد. 📈" if stats['time_in_range'] < 50 else "قابل قبول است. ✅")
402
+
403
+ elif query == 'چند بار قندم خیلی پایین شده؟':
404
+ stats = self.calculate_diabetic_stats()
405
+ if stats:
406
+ return f"{stats['hypo_count']} بار قند خون شما زیر 70 رفته است (هیپوگلایسمی).\n" + \
407
+ ("عالی! هیچ مورد هیپو نداشتید. 🎉" if stats['hypo_count'] == 0 else
408
+ "⚠️ مراقب باشید و با پزشک صحبت کنید.")
409
+
410
+ elif query == 'چند بار قندم خیلی بالا رفته؟':
411
+ stats = self.calculate_diabetic_stats()
412
+ if stats:
413
+ return f"{stats['hyper_count']} بار قند خون شما بالای 180 رفته است (هایپرگلایسمی).\n" + \
414
+ ("عالی! هیچ مورد هایپر شدید نداشتید. 🎉" if stats['hyper_count'] == 0 else
415
+ "⚠️ نیاز به کنترل بیشتر دارید.")
416
+
417
+ elif query == 'قندم چه ساعاتی بالا می‌رود؟':
418
+ glucose_col = None
419
+ time_col = None
420
+
421
+ for col in self.columns:
422
+ if 'قند' in col:
423
+ glucose_col = col
424
+ if 'زمان' in col:
425
+ time_col = col
426
+
427
+ if glucose_col and time_col:
428
+ high_glucose = self.data[self.data[glucose_col] > 140]
429
+ if not high_glucose.empty:
430
+ high_glucose['hour'] = high_glucose[time_col].str.split(':').str[0]
431
+ hour_counts = high_glucose['hour'].value_counts().head(3)
432
+ result = "قند شما بیشتر در این ساعات بالا می‌رود:\n"
433
+ for hour, count in hour_counts.items():
434
+ result += f"ساعت {hour}: {count} بار\n"
435
+ return result
436
+ else:
437
+ return "عالی! قند شما در هیچ ساعتی بالای 140 نرفته است. 🎉"
438
+
439
+ elif query == 'چه ساعاتی قندم نرمال است؟':
440
+ glucose_col = None
441
+ time_col = None
442
+
443
+ for col in self.columns:
444
+ if 'قند' in col:
445
+ glucose_col = col
446
+ if 'زمان' in col:
447
+ time_col = col
448
+
449
+ if glucose_col and time_col:
450
+ normal_glucose = self.data[(self.data[glucose_col] >= 70) & (self.data[glucose_col] <= 140)]
451
+ if not normal_glucose.empty:
452
+ normal_glucose['hour'] = normal_glucose[time_col].str.split(':').str[0]
453
+ hour_counts = normal_glucose['hour'].value_counts().head(5)
454
+ result = "قند شما بیشتر در این ساعات نرمال است:\n"
455
+ for hour, count in hour_counts.items():
456
+ total_in_hour = len(self.data[self.data[time_col].str.startswith(str(hour))])
457
+ percentage = (count / total_in_hour * 100) if total_in_hour > 0 else 0
458
+ result += f"ساعت {hour}: {count} بار ({percentage:.0f}%) 🟢\n"
459
+ return result
460
+ else:
461
+ return "متأسفانه در هیچ ساعتی قند شما نرمال نبوده است. با پزشک مشورت کنید. ⚠️"
462
+
463
+ elif query == 'کدام غذاها قندم را بالا می‌برند؟':
464
+ glucose_col = None
465
+ meal_col = None
466
+
467
+ for col in self.columns:
468
+ if 'قند' in col:
469
+ glucose_col = col
470
+ if 'وعده' in col:
471
+ meal_col = col
472
+
473
+ if glucose_col and meal_col:
474
+ meal_avg = self.data.groupby(meal_col)[glucose_col].mean().sort_values(ascending=False)
475
+ result = "متوسط قند خون بعد از وعده‌های مختلف:\n"
476
+ for meal, avg in meal_avg.items():
477
+ status = "🔴" if avg > 160 else "🟡" if avg > 140 else "🟢"
478
+ result += f"{status} {meal}: {avg:.0f} mg/dL\n"
479
+ return result
480
+
481
+ elif query == 'ورزش چه تاثیری روی قندم دارد؟':
482
+ glucose_col = None
483
+ activity_col = None
484
+
485
+ for col in self.columns:
486
+ if 'قند' in col:
487
+ glucose_col = col
488
+ if 'فعالیت' in col:
489
+ activity_col = col
490
+
491
+ if glucose_col and activity_col:
492
+ exercise_data = self.data[self.data[activity_col] == 'ورزش']
493
+ if not exercise_data.empty:
494
+ avg_exercise = exercise_data[glucose_col].mean()
495
+ non_exercise = self.data[self.data[activity_col] != 'ورزش']
496
+ avg_non_exercise = non_exercise[glucose_col].mean()
497
+ difference = avg_non_exercise - avg_exercise
498
+
499
+ return f"هنگام ورزش متوسط قند شما {avg_exercise:.0f} و در سایر اوقات {avg_non_exercise:.0f} است.\n" + \
500
+ f"ورزش {difference:.0f} واحد قند را کم می‌کند. 💪" if difference > 0 else \
501
+ "ورزش تاثیر منفی روی قند شما نداشته. 👍"
502
+ else:
503
+ return "در این دوره فعالیت ورزشی ثبت نشده است."
504
+
505
+ elif query == 'انسولین چقدر قندم را پایین می‌آورد؟':
506
+ glucose_col = None
507
+ insulin_col = None
508
+
509
+ for col in self.columns:
510
+ if 'قند' in col:
511
+ glucose_col = col
512
+ if 'انسولین' in col:
513
+ insulin_col = col
514
+
515
+ if glucose_col and insulin_col:
516
+ # مقایسه قند قبل و بعد از انسولین
517
+ insulin_data = self.data[self.data[insulin_col] > 0]
518
+ no_insulin_data = self.data[self.data[insulin_col] == 0]
519
+
520
+ if not insulin_data.empty and not no_insulin_data.empty:
521
+ avg_with_insulin = insulin_data[glucose_col].mean()
522
+ avg_without_insulin = no_insulin_data[glucose_col].mean()
523
+
524
+ # محاسبه متوسط انسولین مصرفی
525
+ avg_insulin_dose = insulin_data[insulin_col].mean()
526
+
527
+ # تاثیر هر واحد انسولین
528
+ effect_per_unit = (avg_without_insulin - avg_with_insulin) / avg_insulin_dose if avg_insulin_dose > 0 else 0
529
+
530
+ result = f"تحلیل تاثیر انسولین:\n"
531
+ result += f"• متوسط قند با انسولین: {avg_with_insulin:.0f} mg/dL\n"
532
+ result += f"• متوسط قند بدون انسولین: {avg_without_insulin:.0f} mg/dL\n"
533
+ result += f"• متوسط دوز انسولین: {avg_insulin_dose:.1f} واحد\n"
534
+ result += f"• هر واحد انسولین تقریباً {effect_per_unit:.0f} واحد قند را کم می‌کند 💉\n"
535
+
536
+ if effect_per_unit > 0:
537
+ result += "انسولین شما خوب کار می‌کند! ✅"
538
+ else:
539
+ result += "ممکن است نیاز به تنظیم دوز داشته باشید. با پزشک مشورت کنید. ⚠️"
540
+
541
+ return result
542
+ else:
543
+ return "داده کافی برای تحلیل تاثیر انسولین موجود نیست."
544
+
545
+ elif query == 'استرس چقدر قندم را بالا می‌برد؟':
546
+ glucose_col = None
547
+ stress_col = None
548
+
549
+ for col in self.columns:
550
+ if 'قند' in col:
551
+ glucose_col = col
552
+ if 'استرس' in col:
553
+ stress_col = col
554
+
555
+ if glucose_col and stress_col:
556
+ stress_levels = ['کم', 'متوسط', 'زیاد']
557
+ result = "تاثیر سطح استرس روی قند خون:\n"
558
+
559
+ stress_analysis = {}
560
+ for stress_level in stress_levels:
561
+ stress_data = self.data[self.data[stress_col] == stress_level]
562
+ if not stress_data.empty:
563
+ avg_glucose = stress_data[glucose_col].mean()
564
+ count = len(stress_data)
565
+ stress_analysis[stress_level] = {'avg': avg_glucose, 'count': count}
566
+
567
+ if stress_analysis:
568
+ for stress_level in stress_levels:
569
+ if stress_level in stress_analysis:
570
+ data = stress_analysis[stress_level]
571
+ emoji = "🟢" if data['avg'] < 140 else "🟡" if data['avg'] < 160 else "🔴"
572
+ result += f"{emoji} استرس {stress_level}: {data['avg']:.0f} mg/dL ({data['count']} بار)\n"
573
+
574
+ # محاسبه تفاوت بین کم‌ترین و بیشترین استرس
575
+ if 'کم' in stress_analysis and 'زیاد' in stress_analysis:
576
+ difference = stress_analysis['زیاد']['avg'] - stress_analysis['کم']['avg']
577
+ result += f"\n💡 استرس زیاد {difference:.0f} واحد قند را نسبت به استرس کم بالا می‌برد.\n"
578
+
579
+ if difference > 30:
580
+ result += "استرس تاثیر زیادی روی قند شما دارد. تکنیک‌های آرامش‌بخشی را امتحان کنید. 🧘‍♀️"
581
+ elif difference > 15:
582
+ result += "استرس تاثیر متوسطی روی قند شما دارد."
583
+ else:
584
+ result += "خوشبختانه استرس تاثیر کمی روی قند شما دارد. 👍"
585
+
586
+ return result
587
+ else:
588
+ return "داده کافی برای تحلیل تاثیر استرس موجود نیست."
589
+
590
+ elif query == 'آب‌وهوا چطور روی قندم تاثیر می‌گذارد؟':
591
+ glucose_col = None
592
+ weather_col = None
593
+
594
+ for col in self.columns:
595
+ if 'قند' in col:
596
+ glucose_col = col
597
+ if 'آب_وهوا' in col or 'آب‌وهوا' in col:
598
+ weather_col = col
599
+
600
+ if glucose_col and weather_col:
601
+ weather_analysis = self.data.groupby(weather_col)[glucose_col].agg(['mean', 'count']).reset_index()
602
+ result = "تاثیر آب‌وهوا روی قند خون:\n"
603
+
604
+ for _, row in weather_analysis.iterrows():
605
+ weather = row[weather_col]
606
+ avg_glucose = row['mean']
607
+ count = row['count']
608
+ emoji = "🟢" if avg_glucose < 140 else "🟡" if avg_glucose < 160 else "🔴"
609
+ result += f"{emoji} {weather}: {avg_glucose:.0f} mg/dL ({count} بار)\n"
610
+
611
+ # یافتن بهترین و بدترین آب‌وهوا
612
+ best_weather = weather_analysis.loc[weather_analysis['mean'].idxmin(), weather_col]
613
+ worst_weather = weather_analysis.loc[weather_analysis['mean'].idxmax(), weather_col]
614
+
615
+ result += f"\n🌟 بهترین آب‌وهوا برای قند شما: {best_weather}\n"
616
+ result += f"⚠️ بدترین آب‌وهوا برای قند شما: {worst_weather}"
617
+
618
+ return result
619
+ else:
620
+ return "داده آب‌وهوا در فایل شما موجود نیست."
621
+
622
+ elif query == 'کیفیت خوابم چه تاثیری روی قند دارد؟':
623
+ glucose_col = None
624
+ sleep_col = None
625
+
626
+ for col in self.columns:
627
+ if 'قند' in col:
628
+ glucose_col = col
629
+ if 'کیفیت_خواب' in col:
630
+ sleep_col = col
631
+
632
+ if glucose_col and sleep_col:
633
+ sleep_analysis = self.data.groupby(sleep_col)[glucose_col].agg(['mean', 'count']).reset_index()
634
+ result = "تاثیر کیفیت خواب روی قند خون:\n"
635
+
636
+ sleep_order = {'عالی': 1, 'خوب': 2, 'متوسط': 3, 'بد': 4, 'خیلی_بد': 5}
637
+ sleep_analysis['order'] = sleep_analysis[sleep_col].map(sleep_order)
638
+ sleep_analysis = sleep_analysis.sort_values('order')
639
+
640
+ for _, row in sleep_analysis.iterrows():
641
+ sleep_quality = row[sleep_col]
642
+ avg_glucose = row['mean']
643
+ count = row['count']
644
+ emoji = "🟢" if avg_glucose < 140 else "🟡" if avg_glucose < 160 else "🔴"
645
+ result += f"{emoji} خواب {sleep_quality}: {avg_glucose:.0f} mg/dL ({count} بار)\n"
646
+
647
+ # محاسبه تفاوت بین بهترین و بدترین خواب
648
+ best_sleep = sleep_analysis.iloc[0]
649
+ worst_sleep = sleep_analysis.iloc[-1]
650
+ difference = worst_sleep['mean'] - best_sleep['mean']
651
+
652
+ result += f"\n💤 خواب بد {difference:.0f} واحد قند را بالاتر از خواب خوب می‌برد.\n"
653
+
654
+ if difference > 20:
655
+ result += "کیفیت خواب تاثیر زیادی روی قند شما دارد. بهبود خواب اولویت باشد! 😴"
656
+ else:
657
+ result += "کیفیت خواب تاثیر قابل قبولی روی قند شما دارد. 👍"
658
+
659
+ return result
660
+ else:
661
+ return "داده کیفیت خواب در فایل شما موجود نیست."
662
+
663
+ elif query == 'چقدر ورزش کرده‌ام؟':
664
+ steps_col = None
665
+ activity_col = None
666
+
667
+ for col in self.columns:
668
+ if 'قدم' in col:
669
+ steps_col = col
670
+ if 'فعالیت' in col:
671
+ activity_col = col
672
+
673
+ if steps_col:
674
+ total_steps = self.data[steps_col].sum()
675
+ avg_daily_steps = total_steps / len(self.data.groupby('تاریخ'))
676
+ exercise_days = len(self.data[self.data[activity_col] == 'ورزش']) if activity_col else 0
677
+
678
+ result = f"آمار فعالیت فیزیکی شما:\n"
679
+ result += f"👟 کل قدم‌ها: {total_steps:,} قدم\n"
680
+ result += f"📊 متوسط روزانه: {avg_daily_steps:.0f} قدم\n"
681
+ result += f"💪 روزهای ورزش: {exercise_days} روز\n\n"
682
+
683
+ if avg_daily_steps >= 10000:
684
+ result += "عالی! شما به هدف 10,000 قدم روزانه رسیده‌اید! 🎯"
685
+ elif avg_daily_steps >= 7000:
686
+ result += "خوب است! کمی بیشتر قدم بزنید تا به 10,000 برسید. 📈"
687
+ else:
688
+ result += "نیاز به فعالیت بیشتر دارید. سعی کنید بیشتر قدم بزنید. 🚶‍♂️"
689
+
690
+ return result
691
+ else:
692
+ return "داده قدم‌ها در فایل شما موجود نیست."
693
+
694
+ elif query == 'فشار خونم چطوره؟':
695
+ bp_col = None
696
+
697
+ for col in self.columns:
698
+ if 'فشار' in col:
699
+ bp_col = col
700
+ break
701
+
702
+ if bp_col:
703
+ bp_values = self.data[bp_col].dropna()
704
+ if not bp_values.empty:
705
+ # تحلیل فشار خون
706
+ high_count = 0
707
+ normal_count = 0
708
+ low_count = 0
709
+
710
+ for bp in bp_values:
711
+ try:
712
+ systolic = int(bp.split('/')[0])
713
+ if systolic >= 140:
714
+ high_count += 1
715
+ elif systolic >= 120:
716
+ normal_count += 1
717
+ else:
718
+ low_count += 1
719
+ except:
720
+ continue
721
+
722
+ total = high_count + normal_count + low_count
723
+
724
+ result = f"آمار فشار خون شما:\n"
725
+ result += f"🔴 بالا (≥140): {high_count} بار ({high_count/total*100:.0f}%)\n"
726
+ result += f"🟡 نرمال (120-139): {normal_count} بار ({normal_count/total*100:.0f}%)\n"
727
+ result += f"🟢 ایده‌آل (<120): {low_count} بار ({low_count/total*100:.0f}%)\n\n"
728
+
729
+ if high_count/total > 0.3:
730
+ result += "⚠️ فشار خون شما اغلب بالا است. با پزشک مشورت کنید."
731
+ elif normal_count/total > 0.7:
732
+ result += "✅ فشار خون شما در حد قابل قبول است."
733
+ else:
734
+ result += "👍 فشار خون شما در حد ایده‌آل است."
735
+
736
+ return result
737
+ else:
738
+ return "داده فشار خون کافی نیست."
739
+ else:
740
+ return "داده فشار خون در فایل شما موجود نیست."
741
+
742
+ elif query == 'وزنم چطور تغییر کرده؟':
743
+ weight_col = None
744
+
745
+ for col in self.columns:
746
+ if 'وزن' in col:
747
+ weight_col = col
748
+ break
749
+
750
+ if weight_col:
751
+ weights = self.data[weight_col].dropna()
752
+ if len(weights) > 1:
753
+ first_weight = weights.iloc[0]
754
+ last_weight = weights.iloc[-1]
755
+ weight_change = last_weight - first_weight
756
+ avg_weight = weights.mean()
757
+
758
+ result = f"تغییرات وزن شما:\n"
759
+ result += f"⚖️ وزن اولیه: {first_weight} کیلو\n"
760
+ result += f"⚖️ وزن فعلی: {last_weight} کیلو\n"
761
+ result += f"📊 متوسط وزن: {avg_weight:.1f} کیلو\n"
762
+ result += f"📈 تغییر کلی: {weight_change:+.1f} کیلو\n\n"
763
+
764
+ if abs(weight_change) < 1:
765
+ result += "👍 وزن شما ثابت مانده است."
766
+ elif weight_change > 0:
767
+ result += f"📈 {weight_change:.1f} کیلو افزایش وزن داشته‌اید."
768
+ else:
769
+ result += f"📉 {abs(weight_change):.1f} کیلو کاهش وزن داشته‌اید."
770
+
771
+ return result
772
+ else:
773
+ return "داده وزن کافی برای تحلیل تغییرات نیست."
774
+ else:
775
+ return "داده وزن در فایل شما موجود نیست."
776
+
777
+ else:
778
+ return "متوجه سوال شما نشدم. لطفاً یکی از سوالات آماده را انتخاب کنید."
779
+
780
+ except Exception as e:
781
+ return f"❌ مشکلی پیش آمده: {str(e)}"
782
+
783
+ def get_data_summary(self):
784
+ """خلاصه داده‌ها"""
785
+ if self.data is None:
786
+ return "هیچ داده‌ای بارگذاری نشده است."
787
+
788
+ # محاسبه دوره زمانی
789
+ unique_dates = self.data['تاریخ'].nunique() if 'تاریخ' in self.columns else 1
790
+
791
+ summary = f"📊 تعداد رکوردها: {len(self.data)}\n"
792
+ summary += f"📅 دوره زمانی: {unique_dates} روز\n"
793
+ summary += f"🏷️ تعداد ستون‌ها: {len(self.columns)}\n"
794
+
795
+ # آمار قند خون
796
+ stats = self.calculate_diabetic_stats()
797
+ if stats:
798
+ summary += f"\n🩺 آمار قند خون:\n"
799
+ summary += f"• متوسط قند: {stats['mean']:.0f} mg/dL\n"
800
+ summary += f"• زمان در محدوده: {stats['time_in_range']:.1f}%\n"
801
+ summary += f"• تعداد هیپو: {stats['hypo_count']}\n"
802
+ summary += f"• تعداد هایپر: {stats['hyper_count']}\n"
803
+ summary += f"• تنوع گلایسمی: {stats['variability']:.1f}%\n"
804
+
805
+ # آمار فعالیت فیزیکی
806
+ if 'قدم_ها' in self.columns:
807
+ total_steps = self.data['قدم_ها'].sum()
808
+ avg_daily_steps = total_steps / unique_dates
809
+ summary += f"\n👟 فعالیت فیزیکی:\n"
810
+ summary += f"• کل قدم‌ها: {total_steps:,}\n"
811
+ summary += f"• متوسط روزانه: {avg_daily_steps:.0f} قدم\n"
812
+
813
+ # آمار انسولین
814
+ if 'انسولین' in self.columns:
815
+ insulin_doses = self.data[self.data['انسولین'] > 0]['انسولین']
816
+ if not insulin_doses.empty:
817
+ summary += f"\n💉 انسولین:\n"
818
+ summary += f"• تعداد دوزها: {len(insulin_doses)}\n"
819
+ summary += f"• متوسط دوز: {insulin_doses.mean():.1f} واحد\n"
820
+
821
+ # آمار وزن
822
+ if 'وزن' in self.columns:
823
+ weights = self.data['وزن'].dropna()
824
+ if len(weights) > 1:
825
+ weight_change = weights.iloc[-1] - weights.iloc[0]
826
+ summary += f"\n⚖️ وزن:\n"
827
+ summary += f"• وزن فعلی: {weights.iloc[-1]} کیلو\n"
828
+ summary += f"• تغییر: {weight_change:+.1f} کیلو\n"
829
+
830
+ return summary
831
+
832
+ # ساخت اپلیکیشن Gradio
833
+ def create_app():
834
+ analyzer = CGMAnalyzer()
835
+
836
+ # CSS برای RTL و استایل بهتر
837
+ custom_css = """
838
+ .rtl { direction: rtl; text-align: right; }
839
+ .main-title { text-align: center; color: #d63384; font-size: 28px; font-weight: bold; margin: 20px 0; }
840
+ .subtitle { text-align: center; color: #6c757d; margin-bottom: 30px; font-size: 16px; }
841
+ .section-title { color: #6f42c1; font-weight: bold; margin: 20px 0 10px 0; }
842
+ .gradio-container { font-family: 'Segoe UI', Tahoma, Arial, sans-serif; }
843
+
844
+ /* بهبود نمایش جدول */
845
+ .dataframe {
846
+ font-size: 12px !important;
847
+ width: 100% !important;
848
+ overflow-x: auto !important;
849
+ max-height: 500px !important;
850
+ overflow-y: auto !important;
851
+ }
852
+ .dataframe table {
853
+ table-layout: fixed !important;
854
+ width: 100% !important;
855
+ border-collapse: collapse !important;
856
+ }
857
+ .dataframe th {
858
+ background-color: #f8f9fa !important;
859
+ font-weight: bold !important;
860
+ padding: 8px 4px !important;
861
+ text-align: center !important;
862
+ border: 1px solid #dee2e6 !important;
863
+ position: sticky !important;
864
+ top: 0 !important;
865
+ z-index: 10 !important;
866
+ }
867
+ .dataframe td {
868
+ padding: 6px 4px !important;
869
+ text-align: center !important;
870
+ border: 1px solid #dee2e6 !important;
871
+ word-wrap: break-word !important;
872
+ overflow: hidden !important;
873
+ }
874
+
875
+ /* ستون‌های خاص با عرض ثابت */
876
+ .dataframe th:nth-child(1), .dataframe td:nth-child(1) { width: 100px !important; } /* تاریخ */
877
+ .dataframe th:nth-child(2), .dataframe td:nth-child(2) { width: 70px !important; } /* زمان */
878
+ .dataframe th:nth-child(3), .dataframe td:nth-child(3) { width: 80px !important; } /* قند_خون */
879
+ .dataframe th:nth-child(4), .dataframe td:nth-child(4) { width: 100px !important; } /* روند */
880
+ .dataframe th:nth-child(5), .dataframe td:nth-child(5) { width: 80px !important; } /* وضعیت */
881
+ .dataframe th:nth-child(6), .dataframe td:nth-child(6) { width: 90px !important; } /* فعالیت */
882
+ .dataframe th:nth-child(7), .dataframe td:nth-child(7) { width: 100px !important; } /* وعده_غذایی */
883
+ .dataframe th:nth-child(8), .dataframe td:nth-child(8) { width: 70px !important; } /* انسولین */
884
+ .dataframe th:nth-child(9), .dataframe td:nth-child(9) { width: 80px !important; } /* استرس */
885
+ .dataframe th:nth-child(10), .dataframe td:nth-child(10) { width: 60px !important; } /* خواب */
886
+ .dataframe th:nth-child(11), .dataframe td:nth-child(11) { width: 90px !important; } /* کیفیت_خواب */
887
+ .dataframe th:nth-child(12), .dataframe td:nth-child(12) { width: 80px !important; } /* آب_وهوا */
888
+ .dataframe th:nth-child(13), .dataframe td:nth-child(13) { width: 90px !important; } /* فشار_خون */
889
+ .dataframe th:nth-child(14), .dataframe td:nth-child(14) { width: 90px !important; } /* دارو */
890
+ .dataframe th:nth-child(15), .dataframe td:nth-child(15) { width: 60px !important; } /* وزن */
891
+ .dataframe th:nth-child(16), .dataframe td:nth-child(16) { width: 80px !important; } /* ضربان_قلب */
892
+ .dataframe th:nth-child(17), .dataframe td:nth-child(17) { width: 90px !important; } /* مایعات_مصرفی */
893
+ .dataframe th:nth-child(18), .dataframe td:nth-child(18) { width: 80px !important; } /* قدم_ها */
894
+ .dataframe th:nth-child(19), .dataframe td:nth-child(19) { width: 90px !important; } /* کالری_مصرفی */
895
+ .dataframe th:nth-child(20), .dataframe td:nth-child(20) { width: 120px !important; } /* یادداشت */
896
+
897
+ /* اسکرول بار بهتر */
898
+ .dataframe::-webkit-scrollbar {
899
+ width: 8px;
900
+ height: 8px;
901
+ }
902
+ .dataframe::-webkit-scrollbar-track {
903
+ background: #f1f1f1;
904
+ }
905
+ .dataframe::-webkit-scrollbar-thumb {
906
+ background: #888;
907
+ border-radius: 4px;
908
+ }
909
+ .dataframe::-webkit-scrollbar-thumb:hover {
910
+ background: #555;
911
+ }
912
+ """
913
+
914
+ with gr.Blocks(title="تحلیل‌گر داده‌های CGM", theme=gr.themes.Soft(), css=custom_css) as app:
915
+
916
+ gr.HTML('<div class="main-title">🩺 تحلیل‌گر داده‌های CGM</div>')
917
+ gr.HTML('<div class="subtitle">مانیتورینگ مداوم قند خون • ابزار تحلیل هوشمند برای بیماران دیابتی</div>')
918
+
919
+ with gr.Tab("📂 بارگذاری داده‌ها"):
920
+ with gr.Row():
921
+ with gr.Column():
922
+ file_input = gr.File(
923
+ label="انتخاب فایل CSV",
924
+ file_types=[".csv"],
925
+ elem_classes=["rtl"]
926
+ )
927
+ sample_btn = gr.Button("🔄 بارگذاری داده نمونه", variant="secondary")
928
+ upload_status = gr.Textbox(
929
+ label="وضعیت بارگذاری",
930
+ interactive=False,
931
+ elem_classes=["rtl"]
932
+ )
933
+
934
+ with gr.Column():
935
+ data_summary = gr.Textbox(
936
+ label="خلاصه داده‌ها",
937
+ lines=8,
938
+ interactive=False,
939
+ elem_classes=["rtl"]
940
+ )
941
+
942
+ # دکمه‌های کنترل نمایش داده‌ها
943
+ with gr.Row():
944
+ more_data_btn = gr.Button("📊 نمایش 50 رکورد اول", variant="secondary")
945
+ all_data_btn = gr.Button("📋 نمایش همه داده‌ها", variant="secondary")
946
+ gr.HTML('<div style="color: #6c757d; font-size: 14px; padding: 10px;">💡 نکته: برای مشاهده داده‌های بیشتر از دکمه‌های بالا استفاده کنید</div>')
947
+
948
+ data_preview = gr.Dataframe(
949
+ label="نمایش داده‌ها",
950
+ wrap=True,
951
+ elem_classes=["rtl"]
952
+ )
953
+
954
+ with gr.Tab("🤔 سوالات آماده"):
955
+ gr.HTML('<div class="section-title">سوالات رایج از قند خون - روی هر دکمه کلیک کنید:</div>')
956
+
957
+ with gr.Row():
958
+ with gr.Column():
959
+ query_buttons = []
960
+ for i, query in enumerate(analyzer.diabetic_queries):
961
+ btn = gr.Button(query, elem_classes=["rtl"])
962
+ query_buttons.append(btn)
963
+
964
+ query_result = gr.Textbox(
965
+ label="پاسخ سوال",
966
+ lines=5,
967
+ interactive=False,
968
+ elem_classes=["rtl"]
969
+ )
970
+
971
+ with gr.Tab("💬 سوال دلخواه"):
972
+ with gr.Row():
973
+ custom_query = gr.Textbox(
974
+ label="سوال خود را بنویسید",
975
+ placeholder="مثال: قند من معمولاً چقدر است؟",
976
+ elem_classes=["rtl"]
977
+ )
978
+ ask_btn = gr.Button("🔍 پرسش", variant="primary")
979
+
980
+ custom_result = gr.Textbox(
981
+ label="پاسخ",
982
+ lines=5,
983
+ interactive=False,
984
+ elem_classes=["rtl"]
985
+ )
986
+
987
+ with gr.Tab("📈 نمودارها"):
988
+ gr.HTML('<div class="section-title">نمودارهای تحلیل داده‌ها</div>')
989
+
990
+ with gr.Row():
991
+ trend_btn = gr.Button("📊 روند قند خون")
992
+ pattern_btn = gr.Button("🕐 الگوی روزانه")
993
+ meal_btn = gr.Button("🍽️ تاثیر وعده‌ها")
994
+
995
+ with gr.Row():
996
+ weight_btn = gr.Button("⚖️ روند وزن")
997
+ activity_btn = gr.Button("👟 فعالیت فیزیکی")
998
+ stress_btn = gr.Button("😰 استرس و قند")
999
+
1000
+ chart_output = gr.Plot(label="نمودار")
1001
+
1002
+ with gr.Tab("💡 راهنما"):
1003
+ gr.HTML("""
1004
+ <div class="rtl" style="padding: 20px; font-family: Tahoma;">
1005
+ <h3>💡 راهنمای استفاده:</h3>
1006
+ <ul style="line-height: 1.8;">
1007
+ <li><strong>بارگذاری داده‌ها:</strong> فایل CSV حاوی ستون‌های زیر:
1008
+ <br>• اجباری: تاریخ، زمان، قند_خون، وضعیت، فعالیت، وعده_غذایی، انسولین، استرس
1009
+ <br>• اختیاری: کیفیت_خواب، آب_وهوا، فشار_خون، دارو، وزن، ضربان_قلب، مایعات_مصرفی، قدم_ها، کالری_مصرفی، یادداشت
1010
+ </li>
1011
+ <li><strong>سوالات آماده:</strong> روی هر سوال کلیک کنید تا پاسخ را ببینید</li>
1012
+ <li><strong>سوال دلخواه:</strong> سوال خود را با کلمات ساده بنویسید</li>
1013
+ <li><strong>نمودارها:</strong> تحلیل بصری داده‌های شما شامل 6 نوع نمودار مختلف</li>
1014
+ </ul>
1015
+
1016
+ <h3>📊 محدوده‌های قند خون:</h3>
1017
+ <ul style="line-height: 1.8;">
1018
+ <li><span style="color: red; font-weight: bold;">🔴 خطرناک:</span> کمتر از 70 (فوری به پزشک مراجعه کنید)</li>
1019
+ <li><span style="color: green; font-weight: bold;">🟢 خوب:</span> 70 تا 140 (عالی است)</li>
1020
+ <li><span style="color: orange; font-weight: bold;">🟡 بالا:</span> بیشتر از 140 (بهتر است کنترل کنید)</li>
1021
+ <li><span style="color: red; font-weight: bold;">🔴 خیلی بالا:</span> بیشتر از 180 (حتماً با پزشک صحبت کنید)</li>
1022
+ </ul>
1023
+
1024
+ <h3>🆕 ویژگی‌های جدید:</h3>
1025
+ <ul style="line-height: 1.8;">
1026
+ <li><strong>تحلیل کیفیت خواب:</strong> بررسی تاثیر خواب روی قند خون</li>
1027
+ <li><strong>تاثیر آب‌وهوا:</strong> نحوه تاثیر شرایط جوی بر کنترل قند</li>
1028
+ <li><strong>ردیابی وزن:</strong> پیگیری تغییرات وزن در طول زمان</li>
1029
+ <li><strong>فعالیت فیزیکی:</strong> تحلیل میزان قدم‌زدن و ورزش</li>
1030
+ <li><strong>مانیتورینگ فشار خون:</strong> کنترل همزمان فشار خون</li>
1031
+ <li><strong>مدیریت دارو:</strong> پیگیری مصرف داروها</li>
1032
+ </ul>
1033
+
1034
+ <h3>🏥 نکات مهم:</h3>
1035
+ <ul style="line-height: 1.8;">
1036
+ <li><strong>هدف:</strong> بیش از 70% وقت قند در محدوده نرمال باشد</li>
1037
+ <li><strong>هدف روزانه:</strong> حداقل 10,000 قدم در روز</li>
1038
+ <li>اگر قند زیر 70 رفت، فوری شکر یا آبمیوه بخورید</li>
1039
+ <li>اگر قند بالای 300 رفت، فوری به بیمارستان بروید</li>
1040
+ <li><strong>کیفیت خواب:</strong> 7-8 ساعت خواب باکیفیت ضروری است</li>
1041
+ <li><strong>مدیریت استرس:</strong> تکنیک‌های آرامش‌بخشی یاد بگیرید</li>
1042
+ <li><strong style="color: red;">این برنامه جایگزین مشاوره پزشک نیست</strong></li>
1043
+ </ul>
1044
+
1045
+ <h3>📋 نمونه فرمت CSV:</h3>
1046
+ <pre style="background: #f8f9fa; padding: 10px; border-radius: 5px; font-size: 12px;">
1047
+ تاریخ,زمان,قند_خون,روند,وضعیت,فعالیت,وعده_غذایی,انسولین,استرس,خواب,کیفیت_خواب,آب_وهوا,فشار_خون,دارو,وزن,ضربان_قلب,مایعات_مصرفی,قدم_ها,کالری_مصرفی,یادداشت
1048
+ 2024-01-15,07:30,125,افزایش_تند,نرمال,صبحانه,صبحانه,5,کم,خیر,خوب,آفتابی,120/80,متفورمین,75.2,72,250,320,280,
1049
+ </pre>
1050
+
1051
+ <h3>🔒 حریم خصوصی:</h3>
1052
+ <p>داده‌های شما محلی پردازش می‌شوند و ذخیره نمی‌شوند.</p>
1053
+ </div>
1054
+ """)
1055
+
1056
+ # Event handlers
1057
+ def upload_and_preview(file):
1058
+ data, status = analyzer.upload_file(file)
1059
+ summary = analyzer.get_data_summary()
1060
+ return data, status, summary
1061
+
1062
+ def load_sample_and_preview():
1063
+ data, status = analyzer.load_sample_data()
1064
+ summary = analyzer.get_data_summary()
1065
+ return data, status, summary
1066
+
1067
+ def show_more_data():
1068
+ """نمایش داده‌های بیشتر"""
1069
+ if analyzer.data is not None:
1070
+ # نمایش 50 رکورد اول
1071
+ return analyzer.data.head(50)
1072
+ return None
1073
+
1074
+ def show_all_data():
1075
+ """نمایش همه داده‌ها"""
1076
+ if analyzer.data is not None:
1077
+ return analyzer.data
1078
+ return None
1079
+
1080
+ # اتصال رویدادها
1081
+ file_input.upload(upload_and_preview, inputs=file_input, outputs=[data_preview, upload_status, data_summary])
1082
+ sample_btn.click(load_sample_and_preview, outputs=[data_preview, upload_status, data_summary])
1083
+
1084
+ # دکمه‌های نمایش داده‌های بیشتر
1085
+ more_data_btn.click(show_more_data, outputs=data_preview)
1086
+ all_data_btn.click(show_all_data, outputs=data_preview)
1087
+
1088
+ # اتصال دکمه‌های سوالات آماده
1089
+ for i, btn in enumerate(query_buttons):
1090
+ btn.click(
1091
+ lambda q=analyzer.diabetic_queries[i]: analyzer.execute_query(q),
1092
+ outputs=query_result
1093
+ )
1094
+
1095
+ # سوال دلخواه
1096
+ ask_btn.click(analyzer.execute_query, inputs=custom_query, outputs=custom_result)
1097
+ custom_query.submit(analyzer.execute_query, inputs=custom_query, outputs=custom_result)
1098
+
1099
+ # نمودارها
1100
+ trend_btn.click(analyzer.create_glucose_trend_chart, outputs=chart_output)
1101
+ pattern_btn.click(analyzer.create_daily_pattern_chart, outputs=chart_output)
1102
+ meal_btn.click(analyzer.create_meal_impact_chart, outputs=chart_output)
1103
+ weight_btn.click(analyzer.create_weight_trend_chart, outputs=chart_output)
1104
+ activity_btn.click(analyzer.create_activity_chart, outputs=chart_output)
1105
+ stress_btn.click(analyzer.create_stress_correlation_chart, outputs=chart_output)
1106
+
1107
+ return app
1108
+
1109
+ # برای Hugging Face Spaces
1110
+ if __name__ == "__main__":
1111
+ app = create_app()
1112
+ app.launch()