Arghya Ghosh commited on
Commit
2ad835c
·
verified ·
1 Parent(s): f17e889

Upload 11 files

Browse files
Files changed (11) hide show
  1. api/alzheimers.py +54 -0
  2. api/disease.py +280 -0
  3. api/pneumonia.py +84 -0
  4. api/tumor.py +57 -0
  5. core/config.py +14 -0
  6. core/utils.py +58 -0
  7. main.py +63 -0
  8. pyproject.toml +21 -0
  9. requirements.txt +15 -2
  10. routes/router.py +21 -0
  11. uv.lock +0 -0
api/alzheimers.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/api/alzheimers.py
2
+ from fastapi import APIRouter, UploadFile, File, HTTPException
3
+ from core.utils import preprocess_image_tf, generate_gemini_insights
4
+ from functools import lru_cache
5
+ import numpy as np
6
+ import tensorflow as tf
7
+ import os
8
+
9
+ router = APIRouter()
10
+
11
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
12
+ MODEL_PATH = os.path.join(BASE_DIR, "models", "alzheimers.h5")
13
+
14
+ CLASS_LABELS = [
15
+ "Mild Dementia",
16
+ "Moderate Dementia",
17
+ "Non Demented",
18
+ "Very Mild Dementia",
19
+ ]
20
+
21
+
22
+ @lru_cache(maxsize=1)
23
+ def load_model():
24
+ return tf.keras.models.load_model(MODEL_PATH) # type: ignore
25
+
26
+
27
+ @router.post(
28
+ "/analyze", name="smritiyaan", description="Analyze Alzheimer's from MRI images"
29
+ )
30
+ async def analyze(file: UploadFile = File(...)):
31
+ contents = await file.read()
32
+ if file.content_type not in ["image/jpeg", "image/png"]:
33
+ raise HTTPException(status_code=400, detail="Only JPG/PNG supported.")
34
+
35
+ if len(contents) > 5 * 1024 * 1024:
36
+ raise HTTPException(status_code=413, detail="Image too large. Max size 5MB.")
37
+
38
+ input_tensor = preprocess_image_tf(contents)
39
+ model = load_model()
40
+ predictions = model.predict(input_tensor)
41
+ confidences = predictions[0].tolist()
42
+ predicted_class = CLASS_LABELS[np.argmax(confidences)]
43
+ confidence_dict = {
44
+ label: float(conf) for label, conf in zip(CLASS_LABELS, confidences)
45
+ }
46
+
47
+ insights = await generate_gemini_insights(
48
+ predicted_class, confidence_dict, mode="alzheimers"
49
+ )
50
+ return {
51
+ "predictedClass": predicted_class,
52
+ "confidences": confidence_dict,
53
+ "insights": insights,
54
+ }
api/disease.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/api/disease.py
2
+ from fastapi import APIRouter, HTTPException
3
+ from pydantic import BaseModel
4
+ import numpy as np
5
+ import pandas as pd
6
+ import pickle
7
+ import ast
8
+ import os
9
+
10
+ router = APIRouter()
11
+
12
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
13
+ model_path = os.path.join(BASE_DIR, "models", "svc2.pkl")
14
+
15
+ # Load models and data
16
+ with open(model_path, "rb") as f:
17
+ svc = pickle.load(f)
18
+
19
+ # Load data files
20
+ DATA_DIR = os.path.join(BASE_DIR, "data")
21
+
22
+ description = pd.read_csv(os.path.join(DATA_DIR, "description.csv"))
23
+ precautions = pd.read_csv(os.path.join(DATA_DIR, "precautions_df.csv"))
24
+ medications = pd.read_csv(os.path.join(DATA_DIR, "medications.csv"))
25
+ diets = pd.read_csv(os.path.join(DATA_DIR, "diets.csv"))
26
+ workout = pd.read_csv(os.path.join(DATA_DIR, "workout_df.csv"))
27
+
28
+ # Load symptoms dict and disease list
29
+ symptoms_dict = {
30
+ "itching": 0,
31
+ "skin_rash": 1,
32
+ "nodal_skin_eruptions": 2,
33
+ "continuous_sneezing": 3,
34
+ "shivering": 4,
35
+ "chills": 5,
36
+ "joint_pain": 6,
37
+ "stomach_pain": 7,
38
+ "acidity": 8,
39
+ "ulcers_on_tongue": 9,
40
+ "muscle_wasting": 10,
41
+ "vomiting": 11,
42
+ "burning_micturition": 12,
43
+ "spotting_ urination": 13,
44
+ "fatigue": 14,
45
+ "weight_gain": 15,
46
+ "anxiety": 16,
47
+ "cold_hands_and_feets": 17,
48
+ "mood_swings": 18,
49
+ "weight_loss": 19,
50
+ "restlessness": 20,
51
+ "lethargy": 21,
52
+ "patches_in_throat": 22,
53
+ "irregular_sugar_level": 23,
54
+ "cough": 24,
55
+ "high_fever": 25,
56
+ "sunken_eyes": 26,
57
+ "breathlessness": 27,
58
+ "sweating": 28,
59
+ "dehydration": 29,
60
+ "indigestion": 30,
61
+ "headache": 31,
62
+ "yellowish_skin": 32,
63
+ "dark_urine": 33,
64
+ "nausea": 34,
65
+ "loss_of_appetite": 35,
66
+ "pain_behind_the_eyes": 36,
67
+ "back_pain": 37,
68
+ "constipation": 38,
69
+ "abdominal_pain": 39,
70
+ "diarrhoea": 40,
71
+ "mild_fever": 41,
72
+ "yellow_urine": 42,
73
+ "yellowing_of_eyes": 43,
74
+ "acute_liver_failure": 44,
75
+ "fluid_overload": 45,
76
+ "swelling_of_stomach": 46,
77
+ "swelled_lymph_nodes": 47,
78
+ "malaise": 48,
79
+ "blurred_and_distorted_vision": 49,
80
+ "phlegm": 50,
81
+ "throat_irritation": 51,
82
+ "redness_of_eyes": 52,
83
+ "sinus_pressure": 53,
84
+ "runny_nose": 54,
85
+ "congestion": 55,
86
+ "chest_pain": 56,
87
+ "weakness_in_limbs": 57,
88
+ "fast_heart_rate": 58,
89
+ "pain_during_bowel_movements": 59,
90
+ "pain_in_anal_region": 60,
91
+ "bloody_stool": 61,
92
+ "irritation_in_anus": 62,
93
+ "neck_pain": 63,
94
+ "dizziness": 64,
95
+ "cramps": 65,
96
+ "bruising": 66,
97
+ "obesity": 67,
98
+ "swollen_legs": 68,
99
+ "swollen_blood_vessels": 69,
100
+ "puffy_face_and_eyes": 70,
101
+ "enlarged_thyroid": 71,
102
+ "brittle_nails": 72,
103
+ "swollen_extremeties": 73,
104
+ "excessive_hunger": 74,
105
+ "extra_marital_contacts": 75,
106
+ "drying_and_tingling_lips": 76,
107
+ "slurred_speech": 77,
108
+ "knee_pain": 78,
109
+ "hip_joint_pain": 79,
110
+ "muscle_weakness": 80,
111
+ "stiff_neck": 81,
112
+ "swelling_joints": 82,
113
+ "movement_stiffness": 83,
114
+ "spinning_movements": 84,
115
+ "loss_of_balance": 85,
116
+ "unsteadiness": 86,
117
+ "weakness_of_one_body_side": 87,
118
+ "loss_of_smell": 88,
119
+ "bladder_discomfort": 89,
120
+ "foul_smell_of urine": 90,
121
+ "continuous_feel_of_urine": 91,
122
+ "passage_of_gases": 92,
123
+ "internal_itching": 93,
124
+ "toxic_look_(typhos)": 94,
125
+ "depression": 95,
126
+ "irritability": 96,
127
+ "muscle_pain": 97,
128
+ "altered_sensorium": 98,
129
+ "red_spots_over_body": 99,
130
+ "belly_pain": 100,
131
+ "abnormal_menstruation": 101,
132
+ "dischromic _patches": 102,
133
+ "watering_from_eyes": 103,
134
+ "increased_appetite": 104,
135
+ "polyuria": 105,
136
+ "family_history": 106,
137
+ "mucoid_sputum": 107,
138
+ "rusty_sputum": 108,
139
+ "lack_of_concentration": 109,
140
+ "visual_disturbances": 110,
141
+ "receiving_blood_transfusion": 111,
142
+ "receiving_unsterile_injections": 112,
143
+ "coma": 113,
144
+ "stomach_bleeding": 114,
145
+ "distention_of_abdomen": 115,
146
+ "history_of_alcohol_consumption": 116,
147
+ "fluid_overload.1": 117,
148
+ "blood_in_sputum": 118,
149
+ "prominent_veins_on_calf": 119,
150
+ "palpitations": 120,
151
+ "painful_walking": 121,
152
+ "pus_filled_pimples": 122,
153
+ "blackheads": 123,
154
+ "scurring": 124,
155
+ "skin_peeling": 125,
156
+ "silver_like_dusting": 126,
157
+ "small_dents_in_nails": 127,
158
+ "inflammatory_nails": 128,
159
+ "blister": 129,
160
+ "red_sore_around_nose": 130,
161
+ "yellow_crust_ooze": 131,
162
+ } # Keep your full symptoms_dict here
163
+
164
+ diseases_list = {
165
+ 15: "Fungal infection",
166
+ 4: "Allergy",
167
+ 16: "GERD",
168
+ 9: "Chronic cholestasis",
169
+ 14: "Drug Reaction",
170
+ 33: "Peptic ulcer diseae",
171
+ 1: "AIDS",
172
+ 12: "Diabetes ",
173
+ 17: "Gastroenteritis",
174
+ 6: "Bronchial Asthma",
175
+ 23: "Hypertension ",
176
+ 30: "Migraine",
177
+ 7: "Cervical spondylosis",
178
+ 32: "Paralysis (brain hemorrhage)",
179
+ 28: "Jaundice",
180
+ 29: "Malaria",
181
+ 8: "Chicken pox",
182
+ 11: "Dengue",
183
+ 37: "Typhoid",
184
+ 40: "hepatitis A",
185
+ 19: "Hepatitis B",
186
+ 20: "Hepatitis C",
187
+ 21: "Hepatitis D",
188
+ 22: "Hepatitis E",
189
+ 3: "Alcoholic hepatitis",
190
+ 36: "Tuberculosis",
191
+ 10: "Common Cold",
192
+ 34: "Pneumonia",
193
+ 13: "Dimorphic hemmorhoids(piles)",
194
+ 18: "Heart attack",
195
+ 39: "Varicose veins",
196
+ 26: "Hypothyroidism",
197
+ 24: "Hyperthyroidism",
198
+ 25: "Hypoglycemia",
199
+ 31: "Osteoarthristis",
200
+ 5: "Arthritis",
201
+ 0: "(vertigo) Paroymsal Positional Vertigo",
202
+ 2: "Acne",
203
+ 38: "Urinary tract infection",
204
+ 35: "Psoriasis",
205
+ 27: "Impetigo",
206
+ } # Keep your full diseases_list here
207
+
208
+
209
+ display_to_actual = {sym.replace("_", " "): sym for sym in symptoms_dict.keys()}
210
+
211
+
212
+ class SymptomsInput(BaseModel):
213
+ symptoms: list[str]
214
+
215
+
216
+ def get_predicted_value(symptom_list):
217
+ input_vector = np.zeros(len(symptoms_dict))
218
+ for sym in symptom_list:
219
+ sym_clean = display_to_actual.get(sym)
220
+ if sym_clean:
221
+ input_vector[symptoms_dict[sym_clean]] = 1
222
+ return diseases_list[svc.predict([input_vector])[0]]
223
+
224
+
225
+ def helper(disease):
226
+ desc = description[description["Disease"] == disease]["Description"]
227
+ desc = desc.values[0] if not desc.empty else "Description not available."
228
+
229
+ pre = precautions[precautions["Disease"] == disease].iloc[:, 1:].dropna(axis=1)
230
+ pre = (
231
+ pre.values.flatten().tolist()
232
+ if not pre.empty
233
+ else ["Precautions not available."]
234
+ )
235
+
236
+ med = medications[medications["Disease"] == disease]["Medication"]
237
+ med = (
238
+ ast.literal_eval(med.values[0])
239
+ if not med.empty
240
+ else ["Medications not available."]
241
+ )
242
+
243
+ die = diets[diets["Disease"] == disease]["Diet"]
244
+ die = (
245
+ ast.literal_eval(die.values[0])
246
+ if not die.empty
247
+ else ["Diet recommendations not available."]
248
+ )
249
+
250
+ wrkout = workout[workout["disease"] == disease]["workout"]
251
+ wrkout = (
252
+ wrkout.values.flatten().tolist()
253
+ if not wrkout.empty
254
+ else ["Workouts not available."]
255
+ )
256
+
257
+ return desc, pre, med, die, wrkout
258
+
259
+
260
+ @router.post(
261
+ "/predict", name="rog_dristi", description="Predict disease based on symptoms"
262
+ )
263
+ def predict_disease(data: SymptomsInput):
264
+ if not data.symptoms:
265
+ raise HTTPException(status_code=400, detail="No symptoms provided.")
266
+
267
+ try:
268
+ predicted_disease = get_predicted_value(data.symptoms)
269
+ desc, pre, med, die, wrkout = helper(predicted_disease)
270
+
271
+ return {
272
+ "predicted_disease": predicted_disease,
273
+ "description": desc,
274
+ "precautions": pre,
275
+ "medications": med,
276
+ "diet": die,
277
+ "workouts": wrkout,
278
+ }
279
+ except Exception as e:
280
+ raise HTTPException(status_code=500, detail=str(e))
api/pneumonia.py ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/api/pneumonia.py
2
+ from fastapi import APIRouter, UploadFile, File, HTTPException
3
+ from core.utils import preprocess_image_pil, generate_gemini_insights
4
+ import torch
5
+ import torch.nn as nn
6
+ import torchvision.models as models
7
+ import torchvision.transforms as T
8
+ import os
9
+ from typing import Tuple
10
+ from PIL import Image
11
+
12
+ router = APIRouter()
13
+
14
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
+ class_names = ["NORMAL", "PNEUMONIA"]
16
+
17
+ transform = T.Compose(
18
+ [
19
+ T.Resize((256, 256)),
20
+ T.CenterCrop(224),
21
+ T.ToTensor(),
22
+ T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
23
+ ]
24
+ )
25
+
26
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
27
+ MODEL_PATH = os.path.join(BASE_DIR, "models", "pneumonia.pt")
28
+
29
+
30
+ def load_model(model_path: str) -> nn.Module:
31
+ model = models.vgg19(pretrained=False)
32
+ in_features = (
33
+ model.classifier[0].in_features
34
+ if isinstance(model.classifier[0], nn.Linear)
35
+ else 25088
36
+ )
37
+ model.classifier = nn.Sequential(
38
+ nn.Linear(in_features, 4096), # type: ignore
39
+ nn.ReLU(inplace=True),
40
+ nn.Dropout(0.5),
41
+ nn.Linear(4096, 4096),
42
+ nn.ReLU(inplace=True),
43
+ nn.Dropout(0.5),
44
+ nn.Linear(4096, 2),
45
+ nn.LogSoftmax(dim=1),
46
+ )
47
+ model.load_state_dict(torch.load(model_path, map_location=device))
48
+ model.to(device).eval()
49
+ return model
50
+
51
+
52
+ model = load_model(MODEL_PATH)
53
+
54
+
55
+ def predict(image: Image.Image) -> Tuple[str, float]:
56
+ tensor_image: torch.Tensor = transform(image) # type: ignore
57
+ input_tensor = tensor_image.unsqueeze(0).to(device)
58
+ with torch.no_grad():
59
+ output = model(input_tensor)
60
+ probs = torch.exp(output)
61
+ confidence, predicted_idx = torch.max(probs, dim=1)
62
+ return class_names[predicted_idx.item()], float(confidence.item()) # type: ignore
63
+
64
+
65
+ @router.post(
66
+ "/predict",
67
+ name="shwaas_veda",
68
+ description="Predict pneumonia from chest X-ray images",
69
+ )
70
+ async def classify_image(file: UploadFile = File(...)):
71
+ try:
72
+ contents = await file.read()
73
+ image = preprocess_image_pil(contents)
74
+ label, confidence = predict(image)
75
+ analysis = await generate_gemini_insights(
76
+ label, {label: confidence}, mode="pneumonia"
77
+ )
78
+ return {
79
+ "prediction": label,
80
+ "confidence": round(confidence, 4),
81
+ "gemini_analysis": analysis,
82
+ }
83
+ except Exception as e:
84
+ raise HTTPException(status_code=500, detail=f"Prediction failed: {str(e)}")
api/tumor.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/api/tumor.py
2
+ from fastapi import APIRouter, UploadFile, File, HTTPException
3
+ from core.utils import preprocess_image_tf, generate_gemini_insights
4
+ from functools import lru_cache
5
+ import numpy as np
6
+ from keras import Sequential
7
+ from keras.layers import TFSMLayer
8
+ import os
9
+
10
+ router = APIRouter()
11
+
12
+ CLASS_LABELS = ["glioma", "meningioma", "no_tumor", "pituitary"]
13
+
14
+ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
15
+ MODEL_PATH = os.path.join(BASE_DIR, "models", "tumor_effnet")
16
+
17
+
18
+ @lru_cache(maxsize=1)
19
+ def load_model():
20
+ return Sequential([TFSMLayer(MODEL_PATH, call_endpoint="serving_default")])
21
+
22
+
23
+ @router.post(
24
+ "/classify",
25
+ name="neuro_setu",
26
+ description="Classify brain tumor type from MRI images",
27
+ )
28
+ async def classify(file: UploadFile = File(...)):
29
+ try:
30
+ contents = await file.read()
31
+ if file.content_type not in ["image/jpeg", "image/png"]:
32
+ raise HTTPException(status_code=400, detail="Only JPG/PNG supported.")
33
+
34
+ input_tensor = preprocess_image_tf(contents)
35
+ model = load_model()
36
+ predictions = model(input_tensor)
37
+
38
+ if isinstance(predictions, dict):
39
+ predictions = list(predictions.values())[0]
40
+
41
+ confidences = predictions[0].numpy().tolist() # type: ignore
42
+ predicted_class = CLASS_LABELS[np.argmax(confidences)]
43
+ confidence_dict = {
44
+ label: round(float(score), 4)
45
+ for label, score in zip(CLASS_LABELS, confidences)
46
+ }
47
+
48
+ insights = await generate_gemini_insights(
49
+ predicted_class, confidence_dict, mode="tumor"
50
+ )
51
+ return {
52
+ "predictedClass": predicted_class,
53
+ "confidences": confidence_dict,
54
+ "insights": insights,
55
+ }
56
+ except Exception as e:
57
+ raise HTTPException(status_code=500, detail=f"Classification failed: {str(e)}")
core/config.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/core/config.py
2
+ import os
3
+ from dotenv import load_dotenv
4
+ import google.generativeai as genai
5
+
6
+ load_dotenv()
7
+
8
+ GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
9
+
10
+ if GEMINI_API_KEY:
11
+ genai.configure(api_key=GEMINI_API_KEY) # type: ignore
12
+ GEMINI_MODEL = genai.GenerativeModel("gemini-2.5-flash") # type: ignore
13
+ else:
14
+ raise ValueError("Missing GEMINI_API_KEY in .env file")
core/utils.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/core/utils.py
2
+ import numpy as np
3
+ import tensorflow as tf
4
+ import io
5
+ from PIL import Image
6
+ from .config import GEMINI_MODEL
7
+
8
+
9
+ def preprocess_image_tf(image_bytes):
10
+ img = Image.open(io.BytesIO(image_bytes)).convert("RGB")
11
+ img = img.resize((224, 224))
12
+ img_array = tf.keras.preprocessing.image.img_to_array(img) # type: ignore
13
+ return np.expand_dims(img_array / 255.0, axis=0)
14
+
15
+
16
+ def preprocess_image_pil(image_bytes):
17
+ img = Image.open(io.BytesIO(image_bytes)).convert("RGB")
18
+ return img
19
+
20
+
21
+ async def generate_gemini_insights(label, confidences, mode="general"):
22
+ confidence = confidences[label] * 100
23
+
24
+ if mode == "tumor":
25
+ prompt = f"""
26
+ You are a medical assistant. Generate a tumor analysis report for diagnosis **{label}** with confidence {confidence:.1f}%.
27
+ Include:
28
+ - Description
29
+ - Common MRI findings
30
+ - Recommended medical steps
31
+ - Lifestyle/care suggestions
32
+ Avoid markdown or HTML.
33
+ """
34
+ elif mode == "alzheimers":
35
+ prompt = f"""
36
+ Generate Alzheimer’s medical report for type '{label}' with {confidence:.1f}% confidence.
37
+ Explain:
38
+ - Symptoms
39
+ - MRI observations
40
+ - Next steps
41
+ - Care strategies
42
+ Format as plain text only.
43
+ """
44
+ elif mode == "pneumonia":
45
+ prompt = f"""
46
+ Explain in layman terms the medical condition '{label}' with {confidence:.1f}% confidence.
47
+ Focus on:
48
+ - What it is
49
+ - Symptoms
50
+ - What the patient should do
51
+ Format in markdown.
52
+ """
53
+ else:
54
+ prompt = f"Explain medical condition '{label}' with {confidence:.1f}% confidence."
55
+
56
+ response = await GEMINI_MODEL.generate_content_async(prompt)
57
+ return response.text
58
+
main.py ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from routes.router import api_router
4
+ from scalar_fastapi import get_scalar_api_reference
5
+
6
+ app = FastAPI(
7
+ title="IntelliCure API",
8
+ description="A unified API for various medical models including Brain Tumor classification, Alzheimer's analysis, Pneumonia detection, and Disease prediction.",
9
+ version="1.0.0",
10
+ docs_url=None,
11
+ redoc_url=None,
12
+ )
13
+
14
+ app.add_middleware(
15
+ CORSMiddleware,
16
+ allow_origins=["*"],
17
+ allow_credentials=True,
18
+ allow_methods=["*"],
19
+ allow_headers=["*"],
20
+ )
21
+
22
+ app.include_router(api_router)
23
+
24
+
25
+ @app.get(
26
+ "/",
27
+ name="home",
28
+ description="Welcome to the IntelliCure API!",
29
+ )
30
+ async def root():
31
+ return {
32
+ "message": "🧠 Welcome to the IntelliCure API!",
33
+ "overview": (
34
+ "This API provides AI-assisted diagnostics for brain tumors, pneumonia, Alzheimer's disease, "
35
+ "and symptom-based illness detection."
36
+ ),
37
+ "available_endpoints": [
38
+ "/tumor/classify - Brain tumor classification from MRI images",
39
+ "/pneumonia/predict - Pneumonia prediction from chest X-ray images",
40
+ "/alzheimers/analyze - Alzheimer's analysis from MRI images",
41
+ "/disease/predict - Disease prediction based on symptoms",
42
+ "/health - Health check endpoint",
43
+ ],
44
+ "tip": "For request formats, supported fields, and model details, visit /docs.",
45
+ "disclaimer": (
46
+ "This API is for educational and experimental use. Predictions should not replace professional medical advice."
47
+ ),
48
+ }
49
+
50
+
51
+ @app.get("/health", summary="Health Check", description="Check if the API is healthy.")
52
+ async def health_check():
53
+ return {"status": "healthy"}
54
+
55
+
56
+ @app.get("/docs", include_in_schema=False)
57
+ async def scalar_html():
58
+ return get_scalar_api_reference(
59
+ openapi_url=app.openapi_url or "/openapi.json",
60
+ title=app.title,
61
+ hide_models=True,
62
+ hide_download_button=True,
63
+ )
pyproject.toml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [project]
2
+ name = "backend"
3
+ version = "0.1.0"
4
+ description = "Add your description here"
5
+ readme = "README.md"
6
+ requires-python = ">=3.12"
7
+ dependencies = [
8
+ "fastapi>=0.115.14",
9
+ "google-generativeai>=0.8.5",
10
+ "numpy>=2.1.3",
11
+ "pandas>=2.3.0",
12
+ "pillow>=11.2.1",
13
+ "python-dotenv>=1.1.1",
14
+ "python-multipart>=0.0.20",
15
+ "scalar-fastapi>=1.0.3",
16
+ "scikit-learn>=1.7.0",
17
+ "tensorflow>=2.19.0",
18
+ "torch>=2.7.1",
19
+ "torchvision>=0.22.1",
20
+ "uvicorn>=0.34.3",
21
+ ]
requirements.txt CHANGED
@@ -1,2 +1,15 @@
1
- fastapi
2
- uvicorn[standard]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # requirements.txt
2
+ fastapi
3
+ uvicorn
4
+ tensorflow
5
+ pillow
6
+ numpy
7
+ torch
8
+ torchvision
9
+ python-dotenv
10
+ google-generativeai
11
+ scikit-learn
12
+ pandas
13
+ scalar-fastapi
14
+ python-multipart
15
+ scalar-fastapi
routes/router.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/routes/router.py
2
+ from fastapi import APIRouter
3
+ from api import tumor, pneumonia, alzheimers, disease
4
+
5
+ api_router = APIRouter()
6
+ api_router.include_router(
7
+ tumor.router,
8
+ prefix="/tumor",
9
+ ) # Tumor Insight
10
+ api_router.include_router(
11
+ pneumonia.router,
12
+ prefix="/pneumonia",
13
+ ) # Pneumonia Insight
14
+ api_router.include_router(
15
+ alzheimers.router,
16
+ prefix="/alzheimers",
17
+ ) # Alzheimer Insight
18
+ api_router.include_router(
19
+ disease.router,
20
+ prefix="/disease",
21
+ ) # General Disease Classification
uv.lock ADDED
The diff for this file is too large to render. See raw diff