Feri007 commited on
Commit
69927d9
·
verified ·
1 Parent(s): de22e0f

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +271 -0
app.py ADDED
@@ -0,0 +1,271 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ from collections import defaultdict
4
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
5
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
6
+ from reportlab.lib import colors
7
+ from reportlab.lib.enums import TA_RIGHT
8
+ from reportlab.pdfbase import pdfmetrics
9
+ from reportlab.pdfbase.ttfonts import TTFont
10
+ import difflib
11
+
12
+ # -------------------------------------------------------
13
+ # بارگذاری داده‌ها
14
+ # -------------------------------------------------------
15
+ def load_guidelines(json_file_path):
16
+ try:
17
+ with open(json_file_path, 'r', encoding='utf-8') as file:
18
+ data = json.load(file)
19
+ return data['guidelines']
20
+ except Exception as e:
21
+ print(f"Error loading JSON file: {e}")
22
+ return []
23
+
24
+ guidelines = load_guidelines("enriched_guidelines_with_lab_findings_completed.json")
25
+
26
+ # -------------------------------------------------------
27
+ # تحلیل علائم
28
+ # -------------------------------------------------------
29
+ def analyze_symptoms(symptoms_input, guidelines):
30
+ symptoms_input = [s.lower().strip() for s in symptoms_input.split(',') if s.strip()]
31
+ matched_diseases = defaultdict(lambda: {'score': 0, 'matched_symptoms': [], 'alarm_matched': False, 'full_guideline_data': None})
32
+
33
+ key_symptoms_weights = {
34
+ 'signs of liver decompensation': 2.0,
35
+ 'bloody diarrhea': 1.5,
36
+ 'fever (≥38°c)': 1.3,
37
+ 'abdominal pain (sudden or progressive)': 1.2,
38
+ 'abdominal distension (ascites)': 1.2,
39
+ 'back pain': 1.1,
40
+ 'dyspepsia': 1.0,
41
+ 'asymptomatic (incidental finding)': 0.8
42
+ }
43
+
44
+ for guideline in guidelines:
45
+ disease_name = guideline.get('condition_name', 'Unknown')
46
+ icd_code = guideline.get('icd_code', 'N/A')
47
+ guideline_symptoms = [s.lower().strip() for s in guideline.get('symptoms', [])]
48
+ alarm_features = guideline.get('alarm_features', {})
49
+
50
+ matched_symptoms = [s for s in symptoms_input if s in guideline_symptoms]
51
+ if matched_symptoms:
52
+ score = sum([key_symptoms_weights.get(symptom, 1.0) for symptom in matched_symptoms])
53
+ is_alarm_matched = any(
54
+ symptom.lower() in str(alarm_features.values()).lower()
55
+ for symptom in matched_symptoms
56
+ )
57
+ matched_diseases[disease_name] = {
58
+ 'score': score,
59
+ 'icd_code': icd_code,
60
+ 'matched_symptoms': matched_symptoms,
61
+ 'alarm_matched': is_alarm_matched,
62
+ 'full_guideline_data': guideline
63
+ }
64
+
65
+ results = []
66
+ total_score = sum(d['score'] for d in matched_diseases.values())
67
+
68
+ if total_score == 0:
69
+ return []
70
+
71
+ for disease_name, data in matched_diseases.items():
72
+ probability = (data['score'] / total_score) * 100
73
+ if data['alarm_matched']:
74
+ probability *= 1.5
75
+ probability = max(min(probability, 100), 5)
76
+
77
+ results.append({
78
+ 'disease_name': disease_name,
79
+ 'icd_code': data['icd_code'],
80
+ 'probability': round(probability, 2),
81
+ 'matched_symptoms': ', '.join(data['matched_symptoms']),
82
+ 'full_data': data['full_guideline_data']
83
+ })
84
+
85
+ results.sort(key=lambda x: x['probability'], reverse=True)
86
+ return results
87
+
88
+ # -------------------------------------------------------
89
+ # تحلیل آزمایش‌ها
90
+ # -------------------------------------------------------
91
+ synonyms = {
92
+ "ast": ["ast", "sgot", "aspartate aminotransferase"],
93
+ "alt": ["alt", "sgpt", "alanine aminotransferase"],
94
+ "serum glucose": ["serum glucose", "glucose", "blood sugar"],
95
+ "bilirubin": ["bilirubin", "total bilirubin"],
96
+ "alkaline phosphatase": ["alkaline phosphatase", "alp"],
97
+ "albumin": ["albumin", "serum albumin"],
98
+ "prothrombin time": ["prothrombin time", "pt", "protime"],
99
+ "creatinine": ["creatinine", "serum creatinine"],
100
+ "platelets": ["platelets", "plts"],
101
+ "hemoglobin": ["hemoglobin", "hgb"],
102
+ "wbc": ["wbc", "white blood cell count"]
103
+ }
104
+
105
+ def normalize_test_name(name):
106
+ name = name.lower().strip()
107
+ for key, syns in synonyms.items():
108
+ if name in syns:
109
+ return key
110
+ for key in synonyms.keys():
111
+ if difflib.get_close_matches(name, synonyms[key], cutoff=0.7):
112
+ return key
113
+ return name
114
+
115
+ def check_condition(user_value, expected):
116
+ try:
117
+ user_val = float(user_value)
118
+ if expected.startswith("<="):
119
+ return user_val <= float(expected[2:])
120
+ elif expected.startswith(">="):
121
+ return user_val >= float(expected[2:])
122
+ elif expected.startswith("<"):
123
+ return user_val < float(expected[1:])
124
+ elif expected.startswith(">"):
125
+ return user_val > float(expected[1:])
126
+ else:
127
+ return str(user_val) == expected
128
+ except:
129
+ return expected.lower() in user_value.lower() or user_value.lower() in expected.lower()
130
+
131
+ def analyze_lab_results(lab_results_text, guidelines):
132
+ lab_results_input = {}
133
+ for line in lab_results_text.split('\n'):
134
+ if ':' in line:
135
+ key, value = line.split(':', 1)
136
+ norm_key = normalize_test_name(key)
137
+ lab_results_input[norm_key] = value.strip()
138
+
139
+ matched_diseases = []
140
+ for guideline in guidelines:
141
+ disease_name = guideline.get('condition_name', 'Unknown')
142
+ icd_code = guideline.get('icd_code', 'N/A')
143
+ lab_findings = guideline.get('lab_findings', {})
144
+
145
+ matches = []
146
+ for lab_test, criteria in lab_findings.items():
147
+ norm_test = normalize_test_name(lab_test)
148
+ if norm_test in lab_results_input:
149
+ user_value = lab_results_input[norm_test]
150
+ expected = str(criteria.get('expected', '')).strip()
151
+ meaning = criteria.get('meaning', '')
152
+ if check_condition(user_value, expected):
153
+ matches.append({
154
+ 'test': lab_test,
155
+ 'user_value': user_value,
156
+ 'expected': expected,
157
+ 'meaning': meaning
158
+ })
159
+
160
+ if matches:
161
+ matched_diseases.append({
162
+ 'disease_name': disease_name,
163
+ 'icd_code': icd_code,
164
+ 'lab_matches': matches,
165
+ 'full_data': guideline
166
+ })
167
+
168
+ return matched_diseases
169
+
170
+ # -------------------------------------------------------
171
+ # ترکیب نتایج برای UI
172
+ # -------------------------------------------------------
173
+ def combined_analysis_for_ui(symptoms, lab_results_text):
174
+ symptom_results = analyze_symptoms(symptoms, guidelines)
175
+ lab_results = analyze_lab_results(lab_results_text, guidelines)
176
+
177
+ if not symptom_results and not lab_results:
178
+ return [], "❌ هیچ بیماری مرتبطی یافت نشد.", [], []
179
+
180
+ symptom_table_data = []
181
+ for r in symptom_results:
182
+ symptom_table_data.append([r['disease_name'], r['icd_code'], f"{r['probability']}%", r['matched_symptoms']])
183
+
184
+ lab_results_html = ""
185
+ if lab_results:
186
+ lab_results_html += "<h4>🧪 تحلیل بر اساس آزمایش‌ها:</h4>"
187
+ for lab in lab_results:
188
+ lab_results_html += f"<b>{lab['disease_name']}</b> (ICD: {lab['icd_code']})<br>"
189
+ for match in lab['lab_matches']:
190
+ lab_results_html += f" - <b>{match['test']}</b>: {match['user_value']} (انتظار: {match['expected']}) → {match['meaning']}<br>"
191
+ lab_results_html += "<br>"
192
+
193
+ return symptom_table_data, lab_results_html, symptom_results, lab_results
194
+
195
+ # -------------------------------------------------------
196
+ # نمایش جزئیات هنگام کلیک روی بیماری
197
+ # -------------------------------------------------------
198
+ def show_details(evt: gr.SelectData, symptom_results):
199
+ if evt is None or evt.index is None:
200
+ return "هیچ بیماری انتخاب نشده است."
201
+
202
+ selected_row = evt.index[0] if isinstance(evt.index, (list, tuple)) else evt.index
203
+ if selected_row < 0 or selected_row >= len(symptom_results):
204
+ return "بیماری انتخاب شده معتبر نیست."
205
+
206
+ disease = symptom_results[selected_row]["full_data"]
207
+ html = f"<h4 style='color:#2E86C1;'>{disease.get('condition_name','Unknown')}</h4>"
208
+
209
+ if disease.get('diagnosis_criteria'):
210
+ html += "<b>معیارهای تشخیصی:</b><ul>"
211
+ for item in disease['diagnosis_criteria']:
212
+ html += f"<li>{item}</li>"
213
+ html += "</ul>"
214
+
215
+ if disease.get('alarm_features'):
216
+ html += "<b>علائم هشدار:</b><ul>"
217
+ for k, v in disease['alarm_features'].items():
218
+ html += f"<li><b>{k}</b>: {v}</li>"
219
+ html += "</ul>"
220
+
221
+ if disease.get('first_line_treatment'):
222
+ html += "<b>درمان خط اول:</b><ul>"
223
+ for t in disease['first_line_treatment']:
224
+ html += f"<li>{t}</li>"
225
+ html += "</ul>"
226
+
227
+ if disease.get('second_line_treatment'):
228
+ html += "<b>درمان خط دوم:</b><ul>"
229
+ for t in disease['second_line_treatment']:
230
+ html += f"<li>{t}</li>"
231
+ html += "</ul>"
232
+
233
+ return html
234
+
235
+ # -------------------------------------------------------
236
+ # رابط Gradio
237
+ # -------------------------------------------------------
238
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
239
+ gr.Markdown("<h2 style='text-align:center;color:#2E86C1;'>💡 سیستم هوشمند تحلیل علائم و آزمایش‌ها</h2>")
240
+
241
+ with gr.Row():
242
+ symptoms_input = gr.Textbox(label="✅ علائم (با کاما جدا کنید)")
243
+ lab_results_input = gr.Textbox(label="🧪 نتایج آزمایش (هر خط: نام: مقدار)")
244
+
245
+ analyze_button = gr.Button("🔍 تحلیل کن")
246
+
247
+ with gr.Row():
248
+ with gr.Column(scale=2):
249
+ symptom_table_output = gr.Dataframe(headers=["بیماری", "ICD", "احتمال", "علائم منطبق"], interactive=False)
250
+ lab_results_output = gr.HTML()
251
+
252
+ with gr.Column(scale=3):
253
+ detailed_output = gr.HTML()
254
+
255
+ symptom_results_state = gr.State()
256
+ lab_results_state = gr.State()
257
+
258
+ analyze_button.click(
259
+ fn=combined_analysis_for_ui,
260
+ inputs=[symptoms_input, lab_results_input],
261
+ outputs=[symptom_table_output, lab_results_output, symptom_results_state, lab_results_state]
262
+ )
263
+
264
+ symptom_table_output.select(
265
+ fn=show_details,
266
+ inputs=[symptom_results_state],
267
+ outputs=detailed_output
268
+ )
269
+
270
+ if __name__ == "__main__":
271
+ demo.launch()