Ahmed-El-Sharkawy commited on
Commit
f99c21b
·
verified ·
1 Parent(s): 9817a5c

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +16 -0
  2. app.py +133 -0
  3. requirements.txt +48 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use official Python 3.12.4 image
2
+ FROM python:3.12.4-slim
3
+
4
+ # FROM python:3.9
5
+
6
+ RUN useradd -m -u 1000 user
7
+ USER user
8
+ ENV PATH="/home/user/.local/bin:$PATH"
9
+
10
+ WORKDIR /app
11
+
12
+ COPY --chown=user ./requirements.txt requirements.txt
13
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
14
+
15
+ COPY --chown=user . /app
16
+ CMD ["gunicorn","-b", "0.0.0.0:7860", "main:app"]
app.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ import pandas as pd
3
+ import numpy as np
4
+ from data import StrokeData,HeartData
5
+ from sklearn.preprocessing import LabelEncoder
6
+ from sklearn.preprocessing import StandardScaler
7
+ from sklearn.ensemble import RandomForestClassifier
8
+
9
+ import joblib
10
+ import pickle
11
+
12
+
13
+ class HeartData:
14
+ def __init__(self, age, sex, chest_pain_type, resting_bp, restecg, max_hr, exang, oldpeak, slope, thal):
15
+ self.features = [age, sex, chest_pain_type, resting_bp, restecg, max_hr, exang, oldpeak, slope, thal]
16
+
17
+ class StrokeData:
18
+ def __init__(self, age, hypertension, heart_disease, ever_married, work_type, avg_glucose_level, bmi, smoking_status):
19
+ self.features = [age, hypertension, heart_disease, ever_married, work_type, avg_glucose_level, bmi, smoking_status]
20
+
21
+ class HealthPredictor:
22
+ def __init__(self):
23
+ self.heart_model_path = 'Heart_Disease/Saved_Model_Status/HeartModelRandomForest'
24
+ self.heart_scaler_path = 'Heart_Disease/Saved_Model_Status/Standard_scaler.pkl'
25
+ self.stroke_model_path = 'Stroke_Code/Saved_Model_Status/StrokeModelRandomForest'
26
+ self.stroke_scaler_path = 'Stroke_Code/Saved_Model_Status/Standard_scaler.pkl'
27
+ self.encoders_paths = {
28
+ 'ever_married': 'Stroke_Code/Saved_Model_Status/ever_married_encoder.pkl',
29
+ 'work_type': 'Stroke_Code/Saved_Model_Status/work_type_encoder.pkl',
30
+ 'smoking_status': 'Stroke_Code/Saved_Model_Status/smoking_status_encoder.pkl'
31
+ }
32
+
33
+ self.heart_model = self.load_model(self.heart_model_path)
34
+ self.heart_scaler = self.load_scaler(self.heart_scaler_path)
35
+ self.stroke_model = self.load_model(self.stroke_model_path)
36
+ self.stroke_scaler = self.load_scaler(self.stroke_scaler_path)
37
+
38
+ self.ever_married_encoder = self.load_encoder(self.encoders_paths['ever_married'])
39
+ self.work_type_encoder = self.load_encoder(self.encoders_paths['work_type'])
40
+ self.smoking_status_encoder = self.load_encoder(self.encoders_paths['smoking_status'])
41
+
42
+ def load_model(self, path):
43
+ with open(path, 'rb') as file:
44
+ return pickle.load(file)
45
+
46
+ def load_scaler(self, path):
47
+ return joblib.load(path)
48
+
49
+ def load_encoder(self, path):
50
+ return joblib.load(path)
51
+
52
+ def predict_heart(self, data_point):
53
+ data_point_scaled = self.heart_scaler.transform(np.array([data_point]))
54
+ return self.heart_model.predict(data_point_scaled)[0]
55
+
56
+ def predict_stroke(self, data_point):
57
+ data_point[3] = self.ever_married_encoder.transform([data_point[3]])[0]
58
+ data_point[4] = self.work_type_encoder.transform([data_point[4]])[0]
59
+ data_point[7] = self.smoking_status_encoder.transform([data_point[7]])[0]
60
+
61
+ data_point_scaled = self.stroke_scaler.transform(np.array([data_point]))
62
+
63
+ # Get prediction probability
64
+ probabilities = self.stroke_model.predict_proba(data_point_scaled)[0]
65
+
66
+ # You can return both prediction and probabilities if needed
67
+ prediction = np.argmax(probabilities)
68
+ return prediction, probabilities
69
+
70
+ # return self.stroke_model.predict(data_point_scaled)[0]
71
+
72
+
73
+ class PersonData:
74
+ def __init__(self, age, sex, chest_pain_type, resting_bp, restecg, max_hr, exang, oldpeak, slope, thal,
75
+ hypertension, ever_married, work_type, avg_glucose_level, bmi, smoking_status):
76
+ self.features = [age, sex, chest_pain_type, resting_bp, restecg, max_hr, exang, oldpeak, slope, thal,
77
+ hypertension, ever_married, work_type, avg_glucose_level, bmi, smoking_status]
78
+ self.predictor = HealthPredictor()
79
+ self.heart_prediction = self.predict_heart()
80
+ self.stroke_prediction, self.stroke_proba = self.predict_stroke()
81
+
82
+ def predict_heart(self):
83
+ heart_data = HeartData(*self.features[:10])
84
+ return self.predictor.predict_heart(heart_data.features)
85
+
86
+ def predict_stroke(self):
87
+ self.heart_prediction
88
+ stroke_data = StrokeData(self.features[0], self.features[10], self.heart_prediction, self.features[11], self.features[12],
89
+ self.features[13], self.features[14], self.features[15])
90
+ return self.predictor.predict_stroke(stroke_data.features)
91
+
92
+ app = Flask(__name__)
93
+
94
+ @app.route('/', methods=['GET'])
95
+ def home():
96
+ return "✅ Sahha Health Prediction API is Running", 200
97
+
98
+ @app.route('/predict', methods=['POST'])
99
+ def predict():
100
+ try:
101
+ data = request.get_json()
102
+
103
+ person_data = PersonData(
104
+ age=data['age'],
105
+ sex=data['sex'],
106
+ chest_pain_type=data['chest_pain_type'],
107
+ resting_bp=data['resting_bp'],
108
+ restecg=data['restecg'],
109
+ max_hr=data['max_hr'],
110
+ exang=data['exang'],
111
+ oldpeak=data['oldpeak'],
112
+ slope=data['slope'],
113
+ thal=data['thal'],
114
+ hypertension=data['hypertension'],
115
+ ever_married=data['ever_married'],
116
+ work_type=data['work_type'],
117
+ avg_glucose_level=data['avg_glucose_level'],
118
+ bmi=data['bmi'],
119
+ smoking_status=data['smoking_status']
120
+ )
121
+
122
+ return jsonify({
123
+ 'heart_prediction': int(person_data.heart_prediction),
124
+ 'stroke_prediction': int(person_data.stroke_prediction),
125
+ 'stroke_probability': round(float(person_data.stroke_proba[person_data.stroke_prediction]), 4)
126
+ })
127
+
128
+ except Exception as e:
129
+ return jsonify({'error': str(e)}), 500
130
+
131
+ if __name__ == "__main__":
132
+ app.run(host='0.0.0.0', port=8087, debug=True)
133
+
requirements.txt ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ blinker==1.9.0
2
+ certifi==2025.4.26
3
+ charset-normalizer==3.4.2
4
+ click==8.1.8
5
+ colorama==0.4.6
6
+ contourpy==1.3.2
7
+ cycler==0.12.1
8
+ filelock==3.18.0
9
+ Flask==3.1.0
10
+ fonttools==4.57.0
11
+ fsspec==2025.5.1
12
+ idna==3.10
13
+ imbalanced-learn==0.13.0
14
+ itsdangerous==2.2.0
15
+ Jinja2==3.1.6
16
+ joblib==1.4.2
17
+ kiwisolver==1.4.8
18
+ MarkupSafe==3.0.2
19
+ matplotlib==3.10.1
20
+ mpmath==1.3.0
21
+ narwhals==1.36.0
22
+ networkx==3.5
23
+ numpy==2.2.5
24
+ opencv-python==4.11.0.86
25
+ packaging==25.0
26
+ pandas==2.2.3
27
+ pillow==11.2.1
28
+ plotly==6.0.1
29
+ pyparsing==3.2.3
30
+ python-dateutil==2.9.0.post0
31
+ pytz==2025.2
32
+ requests==2.32.3
33
+ scikit-learn==1.6.1
34
+ scipy==1.15.2
35
+ seaborn==0.13.2
36
+ setuptools==80.9.0
37
+ six==1.17.0
38
+ sklearn-compat==0.1.3
39
+ sympy==1.14.0
40
+ threadpoolctl==3.6.0
41
+ torch==2.7.0
42
+ torchvision==0.22.0
43
+ typing_extensions==4.13.2
44
+ tzdata==2025.2
45
+ urllib3==2.4.0
46
+ Werkzeug==3.1.3
47
+ xgboost==3.0.0
48
+ gunicorn