stroke_model / app.py
omaralaa2004's picture
Update app.py
78b4eda verified
from flask import Flask, request, jsonify, render_template, send_file
import pandas as pd
import numpy as np
import joblib
import sqlite3
import io
from datetime import datetime
import xlsxwriter
from flask_httpauth import HTTPBasicAuth
import os
app = Flask(__name__, template_folder='templates')
app.config['WTF_CSRF_ENABLED'] = False # Disable CSRF for testing
auth = HTTPBasicAuth()
# Global variable to hold the model (lazy-loaded)
model = None
# Admin credentials for report access
users = {
"admin": "your_secure_password" # Replace with a strong password
}
@auth.verify_password
def verify_password(username, password):
if username in users and users[username] == password:
return username
return None
# Initialize SQLite database
def init_db():
db_path = '/tmp/submissions.db'
print(f"Initializing database at {db_path}")
try:
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS submissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT,
age REAL,
gender TEXT,
ever_married TEXT,
residence_type TEXT,
work_type TEXT,
hypertension INTEGER,
heart_disease INTEGER,
avg_glucose_level REAL,
bmi REAL,
smoking_status TEXT,
probability INTEGER,
risk_level TEXT
)
''')
conn.commit()
print("Database initialized successfully")
except Exception as e:
print(f"Error initializing database: {str(e)}")
finally:
conn.close()
init_db()
@app.route('/')
def home():
print("Serving home page")
return render_template('index.html')
@app.route('/predict', methods=['POST'])
def predict():
global model
print("Received predict request at /predict endpoint")
# Check and resolve model file path
model_path = os.path.join(os.getcwd(), 'stroke_prediction_model.pkl')
print(f"Checking model file at: {model_path}")
if not os.path.exists(model_path):
print(f"Model file not found at {model_path}")
return jsonify({'success': False, 'error': f'Model file not found at {model_path}'}), 500
# Load model if not already loaded
if model is None:
try:
model = joblib.load(model_path)
print("Model loaded successfully")
except Exception as e:
print(f"Error loading model: {str(e)}")
return jsonify({'success': False, 'error': f'Model failed to load: {str(e)}'}), 500
try:
# Parse incoming data
data = request.json
print(f"Received JSON data: {data}")
if not data or 'input' not in data:
print("Invalid input data format")
return jsonify({'success': False, 'error': 'Invalid input data'}), 400
input_data = data['input']
print(f"Processed input data: {input_data}")
# Validate and convert input data with fallback
features = {
'age': float(input_data.get('age', 0)) if input_data.get('age') else 0,
'gender': input_data.get('gender', 'Unknown'),
'ever_married': input_data.get('ever_married', 'No'),
'residence_type': input_data.get('residence_type', 'Unknown'),
'work_type': input_data.get('work_type', 'Unknown'),
'hypertension': int(input_data.get('hypertension', 0)) if input_data.get('hypertension') else 0,
'heart_disease': int(input_data.get('heart_disease', 0)) if input_data.get('heart_disease') else 0,
'avg_glucose_level': float(input_data.get('avg_glucose_level', 0)) if input_data.get('avg_glucose_level') else 0,
'bmi': float(input_data.get('bmi', 0)) if input_data.get('bmi') else 0,
'smoking_status': input_data.get('smoking_status', 'Unknown')
}
print(f"Converted features: {features}")
# Create DataFrame and handle categorical variables
df = pd.DataFrame([features])
categorical_cols = ['gender', 'ever_married', 'residence_type', 'work_type', 'smoking_status']
df = pd.get_dummies(df, columns=categorical_cols, drop_first=True)
print(f"DataFrame after get_dummies: {df.columns.tolist()}")
# Define expected columns based on model training
expected_columns = model.feature_names_in_ if hasattr(model, 'feature_names_in_') else [
'age', 'hypertension', 'heart_disease', 'avg_glucose_level', 'bmi',
'gender_Male', 'gender_Other', 'ever_married_Yes', 'residence_type_Urban',
'work_type_Govt_job', 'work_type_Never_worked', 'work_type_Private',
'work_type_Self-employed',
'smoking_status_formerly smoked', 'smoking_status_never smoked',
'smoking_status_smokes'
]
print(f"Expected columns: {expected_columns}")
# Align DataFrame columns
for col in expected_columns:
if col not in df.columns:
df[col] = 0
df = df[expected_columns]
print(f"Aligned DataFrame columns: {df.columns.tolist()}")
# Make prediction
try:
probability = model.predict_proba(df)[0][1] * 100
risk_prediction = "Stroke Risk" if probability > 50 else "No Stroke Risk"
print(f"Prediction result: probability={probability}%, prediction={risk_prediction}")
except Exception as pred_error:
print(f"Prediction error: {str(pred_error)}")
return jsonify({'success': False, 'error': f'Prediction failed: {str(pred_error)}'}), 500
# Determine contributing factors
contributing_factors = {
'glucose': features['avg_glucose_level'] > 140,
'hypertension': features['hypertension'] == 1,
'heartDisease': features['heart_disease'] == 1,
'smoking': features['smoking_status'] in ['smokes', 'formerly smoked']
}
print(f"Contributing factors: {contributing_factors}")
# Attempt to store in database with fallback
try:
conn = sqlite3.connect('/tmp/submissions.db')
c = conn.cursor()
c.execute('''
INSERT INTO submissions (
timestamp, age, gender, ever_married, residence_type, work_type,
hypertension, heart_disease, avg_glucose_level, bmi, smoking_status,
probability, risk_level
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
datetime.now().isoformat(),
features['age'],
features['gender'],
features['ever_married'],
features['residence_type'],
features['work_type'],
features['hypertension'],
features['heart_disease'],
features['avg_glucose_level'],
features['bmi'],
features['smoking_status'],
round(probability),
risk_prediction
))
conn.commit()
print("Data successfully written to database")
except Exception as db_error:
print(f"Database write error (non-critical): {str(db_error)}")
finally:
conn.close()
# Return prediction result
return jsonify({
'success': True,
'prediction': risk_prediction,
'probability': round(probability),
'contributingFactors': contributing_factors
})
except Exception as e:
print(f"Unexpected error during prediction: {str(e)}")
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/admin/report', methods=['GET'])
@auth.login_required
def admin_report():
try:
today = datetime.now().strftime('%Y-%m-%d')
conn = sqlite3.connect('/tmp/submissions.db')
df = pd.read_sql_query('SELECT * FROM submissions WHERE DATE(timestamp) = ?', conn, params=[today])
conn.close()
if df.empty:
return "No submissions for today.", 200
df['hypertension'] = df['hypertension'].apply(lambda x: 'Yes' if x == 1 else 'No')
df['heart_disease'] = df['heart_disease'].apply(lambda x: 'Yes' if x == 1 else 'No')
df = df[[
'timestamp', 'age', 'gender', 'ever_married', 'residence_type', 'work_type',
'hypertension', 'heart_disease', 'avg_glucose_level', 'bmi', 'smoking_status',
'probability', 'risk_level'
]]
df.columns = [
'Timestamp', 'Age', 'Gender', 'Ever Married', 'Residence Type', 'Work Type',
'Hypertension', 'Heart Disease', 'Avg Glucose Level', 'BMI', 'Smoking Status',
'Probability (%)', 'Risk Level'
]
output = io.BytesIO()
with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
df.to_excel(writer, sheet_name='Daily Report', index=False)
worksheet = writer.sheets['Daily Report']
for idx, col in enumerate(df.columns):
max_len = max(df[col].astype(str).map(len).max(), len(col)) + 2
worksheet.set_column(idx, idx, max_len)
output.seek(0)
return send_file(
output,
download_name=f'report_{today}.xlsx',
as_attachment=True,
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
except Exception as e:
print(f"Error generating report: {str(e)}")
return f"Error generating report: {str(e)}", 500