rajkhanke commited on
Commit
3c77aee
·
verified ·
1 Parent(s): e843391

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +121 -0
  2. rf_model.pkl +3 -0
  3. templates/index.html +269 -0
app.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request
2
+ import pandas as pd
3
+ import joblib
4
+ import plotly.graph_objects as go
5
+ from plotly.subplots import make_subplots
6
+ import plotly.io as pio
7
+
8
+ app = Flask(__name__)
9
+
10
+ # Load the pre-trained model from joblib (adjust the file path as needed)
11
+ model = joblib.load('rf_model.pkl')
12
+
13
+ # Define mapping dictionaries (must match those used during training)
14
+ gender_mapping = {'Male': 0, 'Female': 1, 'Other': 2}
15
+ ever_married_mapping = {'No': 0, 'Yes': 1}
16
+ work_type_mapping = {'Private': 0, 'Self-employed': 1, 'Govt_job': 2, 'children': 3, 'Never_worked': 4}
17
+ residence_mapping = {'Urban': 0, 'Rural': 1}
18
+ smoking_status_mapping = {'never smoked': 0, 'formerly smoked': 1, 'smokes': 2, 'Unknown': 3}
19
+ hypertension_mapping = {'No': 0, 'Yes': 1}
20
+ heart_disease_mapping = {'No': 0, 'Yes': 1}
21
+ stroke_mapping = {0: "No", 1: "Yes"}
22
+
23
+
24
+ @app.route('/')
25
+ def index():
26
+ return render_template('index.html')
27
+
28
+
29
+ @app.route('/predict', methods=['POST'])
30
+ def predict():
31
+ # Retrieve user input from the form
32
+ gender = request.form['gender']
33
+ age = float(request.form['age'])
34
+ hypertension = request.form['hypertension']
35
+ heart_disease = request.form['heart_disease']
36
+ ever_married = request.form['ever_married']
37
+ work_type = request.form['work_type']
38
+ residence = request.form['residence']
39
+ avg_glucose_level = float(request.form['avg_glucose_level'])
40
+ bmi = float(request.form['bmi'])
41
+ smoking_status = request.form['smoking_status']
42
+
43
+ # Convert categorical values using predefined mappings
44
+ gender_enc = gender_mapping.get(gender)
45
+ hypertension_enc = hypertension_mapping.get(hypertension)
46
+ heart_disease_enc = heart_disease_mapping.get(heart_disease)
47
+ ever_married_enc = ever_married_mapping.get(ever_married)
48
+ work_type_enc = work_type_mapping.get(work_type)
49
+ residence_enc = residence_mapping.get(residence)
50
+ smoking_status_enc = smoking_status_mapping.get(smoking_status)
51
+
52
+ # Prepare a DataFrame for prediction (one row)
53
+ input_data = pd.DataFrame([{
54
+ 'gender': gender_enc,
55
+ 'age': age,
56
+ 'hypertension': hypertension_enc,
57
+ 'heart_disease': heart_disease_enc,
58
+ 'ever_married': ever_married_enc,
59
+ 'work_type': work_type_enc,
60
+ 'Residence_type': residence_enc,
61
+ 'avg_glucose_level': avg_glucose_level,
62
+ 'bmi': bmi,
63
+ 'smoking_status': smoking_status_enc
64
+ }])
65
+
66
+ # Predict stroke risk
67
+ pred_numeric = model.predict(input_data)[0]
68
+ prediction_label = stroke_mapping[pred_numeric]
69
+ prediction_text = f"Predicted Stroke Risk: {prediction_label}"
70
+
71
+ # --- Create Gauge Charts for four key features ---
72
+ # We create four individual gauge indicators and arrange them in a 2x2 grid.
73
+ fig = make_subplots(rows=2, cols=2,
74
+ specs=[[{'type': 'indicator'}, {'type': 'indicator'}],
75
+ [{'type': 'indicator'}, {'type': 'indicator'}]],
76
+ subplot_titles=("Age", "Avg Glucose Level", "BMI", "Smoking Status"))
77
+
78
+ # Gauge for Age (example range: 0 to 100)
79
+ fig.add_trace(go.Indicator(
80
+ mode="gauge+number",
81
+ value=age,
82
+ gauge={'axis': {'range': [None, 100]}}
83
+ ), row=1, col=1)
84
+
85
+ # Gauge for Avg Glucose Level (example range: 0 to 300)
86
+ fig.add_trace(go.Indicator(
87
+ mode="gauge+number",
88
+ value=avg_glucose_level,
89
+ gauge={'axis': {'range': [None, 300]}}
90
+ ), row=1, col=2)
91
+
92
+ # Gauge for BMI (example range: 10 to 60)
93
+ fig.add_trace(go.Indicator(
94
+ mode="gauge+number",
95
+ value=bmi,
96
+ gauge={'axis': {'range': [None, 60]}}
97
+ ), row=2, col=1)
98
+
99
+ # Gauge for Smoking Status (encoded: 0-3; lower is "better")
100
+ fig.add_trace(go.Indicator(
101
+ mode="gauge+number",
102
+ value=smoking_status_enc,
103
+ gauge={'axis': {'range': [None, 3]},
104
+ 'bar': {'color': "darkorange"},
105
+ 'steps': [
106
+ {'range': [0, 1], 'color': "lightgreen"},
107
+ {'range': [1, 2], 'color': "yellow"},
108
+ {'range': [2, 3], 'color': "tomato"}
109
+ ]}
110
+ ), row=2, col=2)
111
+
112
+ fig.update_layout(height=500, margin=dict(t=50, b=0, l=25, r=25))
113
+
114
+ # Convert the Plotly figure to an HTML div string
115
+ gauge_html = pio.to_html(fig, full_html=False, include_plotlyjs='cdn')
116
+
117
+ return render_template('index.html', prediction_text=prediction_text, gauge_html=gauge_html)
118
+
119
+
120
+ if __name__ == '__main__':
121
+ app.run(debug=True)
rf_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9a7b7982aacb04be08aff27e085cee29e276636430e53d10e0e230db37c2e3ba
3
+ size 7104489
templates/index.html ADDED
@@ -0,0 +1,269 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Brain Stroke Prediction</title>
7
+ <!-- Tailwind CSS CDN -->
8
+ <script src="https://cdn.tailwindcss.com"></script>
9
+ <!-- Google Fonts -->
10
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
11
+ <link
12
+ href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap"
13
+ rel="stylesheet"
14
+ />
15
+ <style>
16
+ body {
17
+ font-family: "Poppins", sans-serif;
18
+ }
19
+ /* Fade-in animation for the container */
20
+ @keyframes fadeIn {
21
+ from {
22
+ opacity: 0;
23
+ transform: translateY(20px);
24
+ }
25
+ to {
26
+ opacity: 1;
27
+ transform: translateY(0);
28
+ }
29
+ }
30
+ .fade-in {
31
+ animation: fadeIn 0.8s ease-out;
32
+ }
33
+ /* Custom focus style for inputs and selects */
34
+ input:focus,
35
+ select:focus {
36
+ outline: none;
37
+ border-color: #60a5fa; /* Tailwind's blue-400 */
38
+ box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.5);
39
+ }
40
+ </style>
41
+ </head>
42
+ <body class="bg-gradient-to-r from-gray-100 via-blue-50 to-gray-100 min-h-screen">
43
+ <div class="max-w-3xl mx-auto p-8 mt-10 bg-white shadow-xl rounded-lg fade-in">
44
+ <!-- Page Title -->
45
+ <h1 class="text-4xl font-bold text-center mb-6 text-blue-700 animate-bounce">
46
+ Brain Stroke Prediction
47
+ </h1>
48
+
49
+ <!-- Form -->
50
+ <form action="/predict" method="post" class="space-y-6">
51
+ <!-- Gender -->
52
+ <div>
53
+ <label for="gender" class="block text-lg font-medium text-gray-800">
54
+ Gender
55
+ </label>
56
+ <select
57
+ name="gender"
58
+ id="gender"
59
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
60
+ transition duration-300 ease-in-out hover:border-blue-500"
61
+ >
62
+ <option>Male</option>
63
+ <option>Female</option>
64
+ <option>Other</option>
65
+ </select>
66
+ </div>
67
+
68
+ <!-- Age -->
69
+ <div>
70
+ <label for="age" class="block text-lg font-medium text-gray-800">
71
+ Age
72
+ </label>
73
+ <input
74
+ type="number"
75
+ step="any"
76
+ name="age"
77
+ id="age"
78
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
79
+ transition duration-300 ease-in-out hover:border-blue-500"
80
+ required
81
+ />
82
+ </div>
83
+
84
+ <!-- Hypertension -->
85
+ <div>
86
+ <label
87
+ for="hypertension"
88
+ class="block text-lg font-medium text-gray-800"
89
+ >
90
+ Hypertension
91
+ </label>
92
+ <select
93
+ name="hypertension"
94
+ id="hypertension"
95
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
96
+ transition duration-300 ease-in-out hover:border-blue-500"
97
+ >
98
+ <option>No</option>
99
+ <option>Yes</option>
100
+ </select>
101
+ </div>
102
+
103
+ <!-- Heart Disease -->
104
+ <div>
105
+ <label
106
+ for="heart_disease"
107
+ class="block text-lg font-medium text-gray-800"
108
+ >
109
+ Heart Disease
110
+ </label>
111
+ <select
112
+ name="heart_disease"
113
+ id="heart_disease"
114
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
115
+ transition duration-300 ease-in-out hover:border-blue-500"
116
+ >
117
+ <option>Yes</option>
118
+ <option>No</option>
119
+ </select>
120
+ </div>
121
+
122
+ <!-- Ever Married -->
123
+ <div>
124
+ <label
125
+ for="ever_married"
126
+ class="block text-lg font-medium text-gray-800"
127
+ >
128
+ Ever Married
129
+ </label>
130
+ <select
131
+ name="ever_married"
132
+ id="ever_married"
133
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
134
+ transition duration-300 ease-in-out hover:border-blue-500"
135
+ >
136
+ <option>Yes</option>
137
+ <option>No</option>
138
+ </select>
139
+ </div>
140
+
141
+ <!-- Work Type -->
142
+ <div>
143
+ <label for="work_type" class="block text-lg font-medium text-gray-800">
144
+ Work Type
145
+ </label>
146
+ <select
147
+ name="work_type"
148
+ id="work_type"
149
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
150
+ transition duration-300 ease-in-out hover:border-blue-500"
151
+ >
152
+ <option>Private</option>
153
+ <option>Self-employed</option>
154
+ <option>Govt_job</option>
155
+ <option>children</option>
156
+ <option>Never_worked</option>
157
+ </select>
158
+ </div>
159
+
160
+ <!-- Residence Type -->
161
+ <div>
162
+ <label for="residence" class="block text-lg font-medium text-gray-800">
163
+ Residence Type
164
+ </label>
165
+ <select
166
+ name="residence"
167
+ id="residence"
168
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
169
+ transition duration-300 ease-in-out hover:border-blue-500"
170
+ >
171
+ <option>Urban</option>
172
+ <option>Rural</option>
173
+ </select>
174
+ </div>
175
+
176
+ <!-- Average Glucose Level -->
177
+ <div>
178
+ <label
179
+ for="avg_glucose_level"
180
+ class="block text-lg font-medium text-gray-800"
181
+ >
182
+ Average Glucose Level
183
+ </label>
184
+ <input
185
+ type="number"
186
+ step="any"
187
+ name="avg_glucose_level"
188
+ id="avg_glucose_level"
189
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
190
+ transition duration-300 ease-in-out hover:border-blue-500"
191
+ required
192
+ />
193
+ </div>
194
+
195
+ <!-- BMI -->
196
+ <div>
197
+ <label for="bmi" class="block text-lg font-medium text-gray-800">
198
+ BMI
199
+ </label>
200
+ <input
201
+ type="number"
202
+ step="any"
203
+ name="bmi"
204
+ id="bmi"
205
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
206
+ transition duration-300 ease-in-out hover:border-blue-500"
207
+ required
208
+ />
209
+ </div>
210
+
211
+ <!-- Smoking Status -->
212
+ <div>
213
+ <label
214
+ for="smoking_status"
215
+ class="block text-lg font-medium text-gray-800"
216
+ >
217
+ Smoking Status
218
+ </label>
219
+ <select
220
+ name="smoking_status"
221
+ id="smoking_status"
222
+ class="mt-1 block w-full border border-gray-300 rounded-md p-2
223
+ transition duration-300 ease-in-out hover:border-blue-500"
224
+ >
225
+ <option>never smoked</option>
226
+ <option>formerly smoked</option>
227
+ <option>smokes</option>
228
+ <option>Unknown</option>
229
+ </select>
230
+ </div>
231
+
232
+ <!-- Submit Button -->
233
+ <button
234
+ type="submit"
235
+ class="w-full bg-blue-600 text-white py-3 px-4 rounded-md
236
+ hover:bg-blue-700 hover:shadow-lg transition
237
+ duration-300 ease-in-out transform hover:scale-105
238
+ text-xl font-semibold"
239
+ >
240
+ Predict Stroke Risk
241
+ </button>
242
+ </form>
243
+
244
+ <!-- Prediction output below the form -->
245
+ {% if prediction_text %}
246
+ <div
247
+ class="mt-8 p-4 bg-green-100 border border-green-400 text-green-700
248
+ rounded text-center transition duration-300 ease-in-out
249
+ transform hover:scale-105"
250
+ >
251
+ <p class="text-2xl font-bold">{{ prediction_text }}</p>
252
+ </div>
253
+ {% endif %}
254
+
255
+ <!-- Gauge charts output below the prediction -->
256
+ {% if gauge_html %}
257
+ <!-- No extra heading here to avoid duplication.
258
+ Make sure your gauge_html does NOT contain repeated headings. -->
259
+ <div
260
+ class="mt-8 fade-in bg-gradient-to-r from-blue-50 to-blue-100
261
+ p-4 rounded-lg shadow-inner hover:shadow-xl
262
+ transition duration-300 ease-in-out transform hover:scale-105"
263
+ >
264
+ {{ gauge_html|safe }}
265
+ </div>
266
+ {% endif %}
267
+ </div>
268
+ </body>
269
+ </html>