leilaghomashchi/cgm-data-analyzer
0
1import gradio as gr2import pandas as pd3import numpy as np4import plotly.express as px5import plotly.graph_objects as go6from plotly.subplots import make_subplots7import warnings8 9warnings.filterwarnings('ignore')10 11class CGMAnalyzer:12 def __init__(self):13 self.data = None14 self.columns = []15 16 # دادههای نمونه CGM17 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 col53 return None54 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 # خواندن فایل CSV69 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 None92 93 # پیدا کردن ستون قند خون94 glucose_col = None95 for col in self.columns:96 if 'قند' in col or 'glucose' in col.lower():97 glucose_col = col98 break99 100 if glucose_col is None:101 return None102 103 glucose_values = self.data[glucose_col].dropna()104 if len(glucose_values) == 0:105 return None106 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)) * 100110 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 0117 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 None131 132 # پیدا کردن ستونهای مورد نیاز133 glucose_col = None134 time_col = None135 136 for col in self.columns:137 if 'قند' in col or 'glucose' in col.lower():138 glucose_col = col139 if 'زمان' in col or 'time' in col.lower():140 time_col = col141 142 if glucose_col is None:143 return None144 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 fig181 182 def create_daily_pattern_chart(self):183 """نمودار الگوی روزانه قند خون"""184 if self.data is None:185 return None186 187 glucose_col = None188 time_col = None189 190 for col in self.columns:191 if 'قند' in col or 'glucose' in col.lower():192 glucose_col = col193 if 'زمان' in col or 'time' in col.lower():194 time_col = col195 196 if glucose_col is None or time_col is None:197 return None198 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 fig219 220 def create_meal_impact_chart(self):221 """نمودار تاثیر وعدههای غذایی"""222 if self.data is None:223 return None224 225 glucose_col = None226 meal_col = None227 228 for col in self.columns:229 if 'قند' in col or 'glucose' in col.lower():230 glucose_col = col231 if 'وعده' in col or 'meal' in col.lower():232 meal_col = col233 234 if glucose_col is None or meal_col is None:235 return None236 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 fig252 253 def create_weight_trend_chart(self):254 """نمودار روند وزن"""255 if self.data is None:256 return None257 258 weight_col = None259 date_col = None260 261 for col in self.columns:262 if 'وزن' in col:263 weight_col = col264 if 'تاریخ' in col:265 date_col = col266 267 if weight_col is None or date_col is None:268 return None269 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 fig291 292 def create_activity_chart(self):293 """نمودار فعالیت فیزیکی"""294 if self.data is None:295 return None296 297 steps_col = None298 date_col = None299 300 for col in self.columns:301 if 'قدم' in col:302 steps_col = col303 if 'تاریخ' in col:304 date_col = col305 306 if steps_col is None or date_col is None:307 return None308 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 fig332 333 def create_stress_correlation_chart(self):334 """نمودار همبستگی استرس و قند"""335 if self.data is None:336 return None337 338 glucose_col = None339 stress_col = None340 341 for col in self.columns:342 if 'قند' in col:343 glucose_col = col344 if 'استرس' in col:345 stress_col = col346 347 if glucose_col is None or stress_col is None:348 return None349 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 fig380 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 = None419 time_col = None420 421 for col in self.columns:422 if 'قند' in col:423 glucose_col = col424 if 'زمان' in col:425 time_col = col426 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 result436 else:437 return "عالی! قند شما در هیچ ساعتی بالای 140 نرفته است. 🎉"438 439 elif query == 'چه ساعاتی قندم نرمال است؟':440 glucose_col = None441 time_col = None442 443 for col in self.columns:444 if 'قند' in col:445 glucose_col = col446 if 'زمان' in col:447 time_col = col448 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 0458 result += f"ساعت {hour}: {count} بار ({percentage:.0f}%) 🟢\n"459 return result460 else:461 return "متأسفانه در هیچ ساعتی قند شما نرمال نبوده است. با پزشک مشورت کنید. ⚠️"462 463 elif query == 'کدام غذاها قندم را بالا میبرند؟':464 glucose_col = None465 meal_col = None466 467 for col in self.columns:468 if 'قند' in col:469 glucose_col = col470 if 'وعده' in col:471 meal_col = col472 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 result480 481 elif query == 'ورزش چه تاثیری روی قندم دارد؟':482 glucose_col = None483 activity_col = None484 485 for col in self.columns:486 if 'قند' in col:487 glucose_col = col488 if 'فعالیت' in col:489 activity_col = col490 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_exercise498 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 = None507 insulin_col = None508 509 for col in self.columns:510 if 'قند' in col:511 glucose_col = col512 if 'انسولین' in col:513 insulin_col = col514 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 0529 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 result542 else:543 return "داده کافی برای تحلیل تاثیر انسولین موجود نیست."544 545 elif query == 'استرس چقدر قندم را بالا میبرد؟':546 glucose_col = None547 stress_col = None548 549 for col in self.columns:550 if 'قند' in col:551 glucose_col = col552 if 'استرس' in col:553 stress_col = col554 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 result587 else:588 return "داده کافی برای تحلیل تاثیر استرس موجود نیست."589 590 elif query == 'آبوهوا چطور روی قندم تاثیر میگذارد؟':591 glucose_col = None592 weather_col = None593 594 for col in self.columns:595 if 'قند' in col:596 glucose_col = col597 if 'آب_وهوا' in col or 'آبوهوا' in col:598 weather_col = col599 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 result619 else:620 return "داده آبوهوا در فایل شما موجود نیست."621 622 elif query == 'کیفیت خوابم چه تاثیری روی قند دارد؟':623 glucose_col = None624 sleep_col = None625 626 for col in self.columns:627 if 'قند' in col:628 glucose_col = col629 if 'کیفیت_خواب' in col:630 sleep_col = col631 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 result660 else:661 return "داده کیفیت خواب در فایل شما موجود نیست."662 663 elif query == 'چقدر ورزش کردهام؟':664 steps_col = None665 activity_col = None666 667 for col in self.columns:668 if 'قدم' in col:669 steps_col = col670 if 'فعالیت' in col:671 activity_col = col672 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 0677 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 result691 else:692 return "داده قدمها در فایل شما موجود نیست."693 694 elif query == 'فشار خونم چطوره؟':695 bp_col = None696 697 for col in self.columns:698 if 'فشار' in col:699 bp_col = col700 break701 702 if bp_col:703 bp_values = self.data[bp_col].dropna()704 if not bp_values.empty:705 # تحلیل فشار خون706 high_count = 0707 normal_count = 0708 low_count = 0709 710 for bp in bp_values:711 try:712 systolic = int(bp.split('/')[0])713 if systolic >= 140:714 high_count += 1715 elif systolic >= 120:716 normal_count += 1717 else:718 low_count += 1719 except:720 continue721 722 total = high_count + normal_count + low_count723 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 result737 else:738 return "داده فشار خون کافی نیست."739 else:740 return "داده فشار خون در فایل شما موجود نیست."741 742 elif query == 'وزنم چطور تغییر کرده؟':743 weight_col = None744 745 for col in self.columns:746 if 'وزن' in col:747 weight_col = col748 break749 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_weight756 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 result772 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 1790 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_dates809 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 summary831 832# ساخت اپلیکیشن Gradio833def 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تاریخ,زمان,قند_خون,روند,وضعیت,فعالیت,وعده_غذایی,انسولین,استرس,خواب,کیفیت_خواب,آب_وهوا,فشار_خون,دارو,وزن,ضربان_قلب,مایعات_مصرفی,قدم_ها,کالری_مصرفی,یادداشت10482024-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 handlers1057 def upload_and_preview(file):1058 data, status = analyzer.upload_file(file)1059 summary = analyzer.get_data_summary()1060 return data, status, summary1061 1062 def load_sample_and_preview():1063 data, status = analyzer.load_sample_data()1064 summary = analyzer.get_data_summary()1065 return data, status, summary1066 1067 def show_more_data():1068 """نمایش دادههای بیشتر"""1069 if analyzer.data is not None:1070 # نمایش 50 رکورد اول1071 return analyzer.data.head(50)1072 return None1073 1074 def show_all_data():1075 """نمایش همه دادهها"""1076 if analyzer.data is not None:1077 return analyzer.data1078 return None1079 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_result1093 )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 app1108 1109# برای Hugging Face Spaces1110if __name__ == "__main__":1111 app = create_app()1112 app.launch()