Umranz commited on
Commit
3d98fdb
Β·
1 Parent(s): 8136e91

Update MediScan AI app with improved UI and fixed models loading

Browse files
Files changed (2) hide show
  1. app.py +230 -0
  2. requirements.txt +0 -0
app.py ADDED
@@ -0,0 +1,230 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from huggingface_hub import hf_hub_download
3
+ import pickle
4
+ import numpy as np
5
+ import os
6
+
7
+ REPO_ID = "Umranz/mediscan-symptom-classifier"
8
+
9
+ def load_models():
10
+ files = ["svm.pkl", "logistic.pkl", "random_forest.pkl", "naive_bayes.pkl", "voting_ensemble.pkl", "label_encoder.pkl", "tfidf.pkl"]
11
+ loaded = {}
12
+ for f in files:
13
+ path = hf_hub_download(repo_id=REPO_ID, filename=f)
14
+ with open(path, "rb") as file:
15
+ loaded[f.replace(".pkl", "")] = pickle.load(file)
16
+ return loaded
17
+
18
+ print("Loading models...")
19
+ M = load_models()
20
+ tfidf = M["tfidf"]
21
+ le = M["label_encoder"]
22
+ ensemble = M["voting_ensemble"]
23
+ models = {
24
+ "SVM" : M["svm"],
25
+ "Logistic Reg" : M["logistic"],
26
+ "Random Forest" : M["random_forest"],
27
+ "Naive Bayes" : M["naive_bayes"],
28
+ }
29
+ print("βœ… Models loaded!")
30
+
31
+ SEVERITY = {
32
+ "Fungal infection" : ("🟑", "Mild"),
33
+ "Allergy" : ("🟑", "Mild"),
34
+ "GERD" : ("🟑", "Mild"),
35
+ "Chronic cholestasis" : ("🟠", "Moderate"),
36
+ "Drug Reaction" : ("🟠", "Moderate"),
37
+ "Peptic ulcer disease" : ("🟠", "Moderate"),
38
+ "AIDS" : ("πŸ”΄", "Severe"),
39
+ "Diabetes" : ("🟠", "Moderate"),
40
+ "Gastroenteritis" : ("🟑", "Mild"),
41
+ "Bronchial Asthma" : ("🟠", "Moderate"),
42
+ "Hypertension" : ("πŸ”΄", "Severe"),
43
+ "Migraine" : ("🟑", "Mild"),
44
+ "Cervical spondylosis" : ("🟑", "Mild"),
45
+ "Paralysis (brain hemorrhage)": ("πŸ”΄", "Severe"),
46
+ "Jaundice" : ("🟠", "Moderate"),
47
+ "Malaria" : ("πŸ”΄", "Severe"),
48
+ "Chicken pox" : ("🟑", "Mild"),
49
+ "Dengue" : ("πŸ”΄", "Severe"),
50
+ "Typhoid" : ("🟠", "Moderate"),
51
+ "hepatitis A" : ("🟠", "Moderate"),
52
+ "Hepatitis B" : ("πŸ”΄", "Severe"),
53
+ "Hepatitis C" : ("πŸ”΄", "Severe"),
54
+ "Hepatitis D" : ("πŸ”΄", "Severe"),
55
+ "Hepatitis E" : ("🟠", "Moderate"),
56
+ "Alcoholic hepatitis" : ("🟠", "Moderate"),
57
+ "Tuberculosis" : ("πŸ”΄", "Severe"),
58
+ "Common Cold" : ("🟒", "Low"),
59
+ "Pneumonia" : ("πŸ”΄", "Severe"),
60
+ "Dimorphic hemmorhoids(piles)": ("🟑", "Mild"),
61
+ "Heart attack" : ("πŸ”΄", "Critical"),
62
+ "Varicose veins" : ("🟑", "Mild"),
63
+ "Hypothyroidism" : ("🟠", "Moderate"),
64
+ "Hyperthyroidism" : ("🟠", "Moderate"),
65
+ "Hypoglycemia" : ("πŸ”΄", "Severe"),
66
+ "Osteoarthristis" : ("🟑", "Mild"),
67
+ "Arthritis" : ("🟑", "Mild"),
68
+ "Vertigo" : ("🟑", "Mild"),
69
+ "Acne" : ("🟒", "Low"),
70
+ "Urinary tract infection" : ("🟑", "Mild"),
71
+ "Psoriasis" : ("🟑", "Mild"),
72
+ "Impetigo" : ("🟑", "Mild"),
73
+ }
74
+
75
+ def predict(symptoms, threshold):
76
+ if not symptoms.strip():
77
+ return (
78
+ "⚠️ Please enter your symptoms.",
79
+ "",
80
+ "",
81
+ ""
82
+ )
83
+
84
+ vec = tfidf.transform([symptoms])
85
+ proba = ensemble.predict_proba(vec)[0]
86
+ top3 = np.argsort(proba)[::-1][:3]
87
+
88
+ top_idx = top3[0]
89
+ top_label = le.classes_[top_idx]
90
+ top_conf = proba[top_idx] * 100
91
+ sev_emoji, sev_label = SEVERITY.get(top_label, ("βšͺ", "Unknown"))
92
+
93
+ if top_conf < threshold:
94
+ main_result = (
95
+ f"⚠️ **Low Confidence ({top_conf:.1f}%)** β€” Please provide more specific symptoms.\n\n"
96
+ f"Best guess: **{top_label}** but confidence is below your threshold of {threshold}%."
97
+ )
98
+ return main_result, "", "", ""
99
+ else:
100
+ main_result = (
101
+ f"## {sev_emoji} {top_label}\n"
102
+ f"**Confidence:** {top_conf:.1f}%\n\n"
103
+ f"**Severity:** {sev_emoji} {sev_label}\n\n"
104
+ f"{'β–ˆ' * int(top_conf // 5)}{'β–‘' * (20 - int(top_conf // 5))} {top_conf:.1f}%"
105
+ )
106
+
107
+ top3_result = "## πŸ† Top 3 Predictions\n\n"
108
+ for rank, idx in enumerate(top3):
109
+ label = le.classes_[idx]
110
+ conf = proba[idx] * 100
111
+ s_emoji, s_label = SEVERITY.get(label, ("βšͺ", "Unknown"))
112
+ bar = "β–ˆ" * int(conf // 5) + "β–‘" * (20 - int(conf // 5))
113
+ top3_result += (
114
+ f"**{rank+1}. {label}** {s_emoji} {s_label}\n"
115
+ f"{bar} {conf:.1f}%\n\n"
116
+ )
117
+
118
+ agreement = "## πŸ€– Model Votes\n\n"
119
+ votes = {}
120
+ for name, model in models.items():
121
+ pred = le.classes_[model.predict(vec)[0]]
122
+ votes[name] = pred
123
+ match = "βœ…" if pred == top_label else "πŸ”„"
124
+ agreement += f"{match} **{name}** β†’ {pred}\n\n"
125
+
126
+ all_agree = len(set(votes.values())) == 1
127
+ agreement += (
128
+ "\n🟒 **All models agree!**" if all_agree
129
+ else "\n🟑 **Models have different opinions β€” consider consulting a doctor.**"
130
+ )
131
+
132
+ disclaimer = (
133
+ "## ⚠️ Medical Disclaimer\n\n"
134
+ "This tool is for **educational purposes only** and does **NOT** replace "
135
+ "professional medical advice. Always consult a qualified healthcare provider "
136
+ "for diagnosis and treatment.\n\n"
137
+ "**If you have a medical emergency, call your local emergency number immediately.**"
138
+ )
139
+
140
+ return main_result, top3_result, agreement, disclaimer
141
+
142
+ EXAMPLES = [
143
+ ["fever, chills, headache, muscle pain, sweating", 50],
144
+ ["itching, skin rash, nodal skin eruptions, dischromic patches", 50],
145
+ ["chest pain, shortness of breath, fatigue, sweating", 50],
146
+ ["sneezing, runny nose, cough, sore throat, congestion", 50],
147
+ ["fatigue, weight loss, high fever, night sweats, cough", 50],
148
+ ]
149
+
150
+ with gr.Blocks(title="MediScan AI") as demo:
151
+
152
+ gr.Markdown("""
153
+ # 🩺 MediScan AI β€” Medical Symptom Classifier
154
+ **4 ML Models + Voting Ensemble** | DistilBERT-level accuracy with traditional ML
155
+ > Enter your symptoms separated by commas for instant multi-model analysis.
156
+ """)
157
+
158
+ with gr.Row():
159
+ with gr.Column(scale=2):
160
+ symptoms_input = gr.Textbox(
161
+ lines=4,
162
+ placeholder="e.g. fever, chills, headache, muscle pain, fatigue...",
163
+ label="πŸ” Describe Your Symptoms",
164
+ max_lines=8
165
+ )
166
+ threshold_slider = gr.Slider(
167
+ minimum=10,
168
+ maximum=90,
169
+ value=50,
170
+ step=5,
171
+ label="βš™οΈ Confidence Threshold (%)",
172
+ info="Predictions below this % will show a low-confidence warning"
173
+ )
174
+ analyze_btn = gr.Button(
175
+ "πŸ” Analyze Symptoms",
176
+ variant="primary",
177
+ size="lg"
178
+ )
179
+
180
+ with gr.Column(scale=3):
181
+ main_output = gr.Markdown(label="Primary Diagnosis")
182
+
183
+ with gr.Row():
184
+ top3_output = gr.Markdown(label="Top 3 Predictions")
185
+ agreement_output = gr.Markdown(label="Model Agreement")
186
+
187
+ disclaimer_output = gr.Markdown()
188
+
189
+ gr.Examples(
190
+ examples=EXAMPLES,
191
+ inputs=[symptoms_input, threshold_slider],
192
+ label="πŸ’‘ Try These Examples"
193
+ )
194
+
195
+ with gr.Accordion("ℹ️ About MediScan AI", open=False):
196
+ gr.Markdown("""
197
+ ## 🧠 How It Works
198
+ MediScan AI runs your symptoms through **4 independent ML models simultaneously:**
199
+
200
+ | Model | Strength |
201
+ |---|---|
202
+ | **SVM** | Best accuracy on text classification |
203
+ | **Logistic Regression** | Fast, reliable baseline |
204
+ | **Random Forest** | Handles noisy input well |
205
+ | **Naive Bayes** | Great for keyword-based symptoms |
206
+
207
+ A **Soft Voting Ensemble** combines all 4 predictions for the final result.
208
+
209
+ ## πŸ“Š Dataset
210
+ - **Source:** Gretel AI Symptom to Diagnosis dataset
211
+ - **Diseases:** 24 unique conditions
212
+ - **Features:** TF-IDF with bigrams (5000 features)
213
+
214
+ ## πŸ‘¨β€πŸ’» Built By
215
+ Umranz β€” [HuggingFace Profile](https://huggingface.co/Umranz)
216
+ """)
217
+
218
+ analyze_btn.click(
219
+ fn=predict,
220
+ inputs=[symptoms_input, threshold_slider],
221
+ outputs=[main_output, top3_output, agreement_output, disclaimer_output]
222
+ )
223
+
224
+ symptoms_input.submit(
225
+ fn=predict,
226
+ inputs=[symptoms_input, threshold_slider],
227
+ outputs=[main_output, top3_output, agreement_output, disclaimer_output]
228
+ )
229
+
230
+ demo.launch()
requirements.txt ADDED
File without changes