File size: 5,893 Bytes
b398c5e
 
 
 
 
 
 
 
 
 
 
7327b52
b80c713
7327b52
 
 
b398c5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7327b52
 
 
 
 
 
 
 
 
 
 
b80c713
b398c5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
b80c713
b398c5e
 
 
 
 
 
 
 
 
 
 
b80c713
b398c5e
b80c713
b398c5e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from flask import Flask, render_template, request, url_for
import pickle
import numpy as np
import os
from ocr_utils import extract_keywords_from_report, score_text_for_risk 
from image_utils import predict_xray_risk, generate_and_save_gradcam 

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

# ---------------- Load ML Artifacts (Lazy Initialization) ----------------
# Global variables are set to None to force Lazy Loading inside predict()
model = None
target_encoder = None
feature_order = None 

# ---------------- Constants ----------------
CSV_KEYS = [
    'Age', 'Gender', 'Air Pollution', 'Alcohol use', 'Dust Allergy', 'OccuPational Hazards',
    'Genetic Risk', 'chronic Lung Disease', 'Balanced Diet', 'Obesity', 'Smoking',
    'Passive Smoker', 'Chest Pain', 'Coughing of Blood', 'Fatigue', 'Weight Loss',
    'Shortness of Breath', 'Wheezing', 'Swallowing Difficulty', 'Clubbing of Finger Nails',
    'Frequent Cold', 'Dry Cough', 'Snoring'
]

# ---------------- Routes ----------------
@app.route('/')
def home():
    """Render main interactive UI"""
    return render_template('index.html')


@app.route('/predict', methods=['POST'])
def predict():
    """Handles the prediction request and renders the result page."""
    
    # 🛑 CRITICAL FIX: LAZY LOAD MODELS HERE 🛑
    global model, target_encoder, feature_order
    
    if model is None:
        try:
            model = pickle.load(open("model.pkl", "rb"))
            target_encoder = pickle.load(open("target_encoder.pkl", "rb"))
            feature_order = pickle.load(open("model_features.pkl", "rb"))
        except Exception as e:
            return render_template('result.html', final_risk_level="Error", combined_score=0, error_message=f"Initial model loading failed on request: {str(e)}")

    # 1. Check for final Model Load Error
    if not model:
        return render_template('result.html', final_risk_level="Error", combined_score=0, error_message="Model loading failed. Please check server logs.")

    try:
        # --- 1️⃣ Collect and sanitize form data ---
        data_dict = {}
        for key in CSV_KEYS:
            form_key = key.lower().replace(' ', '_')
            val = request.form.get(form_key)
            data_dict[key] = float(val) if val else 0.0

        # --- 2️⃣ Tabular model prediction ---
        features = [data_dict.get(col, 0.0) for col in feature_order]
        X = np.array(features).reshape(1, -1)
        
        if X.shape[1] != len(feature_order):
             raise ValueError("Feature count mismatch. Model features != Form inputs.")
             
        encoded_pred = model.predict(X)[0]
        tabular_proba = model.predict_proba(X)[0]
        tabular_confidence = float(np.max(tabular_proba) * 100)

        tabular_classes = target_encoder.classes_
        high_idx = np.where(tabular_classes == 'High')[0][0] if 'High' in tabular_classes else -1
        tabular_high_prob = float(tabular_proba[high_idx]) if high_idx != -1 else 0.0

        # --- 3️⃣ OCR Risk (PDF / Image) ---
        ocr_risk_score = 0.0
        ocr_keywords = []
        report_file = request.files.get('report')
        if report_file and report_file.filename:
            report_path = os.path.join(app.config['UPLOAD_FOLDER'], report_file.filename)
            report_file.save(report_path)
            extracted_text = extract_keywords_from_report(report_path)
            ocr_risk_score, ocr_keywords = score_text_for_risk(extracted_text)

        # --- 4️⃣ CNN Risk (X-ray) and Grad-CAM Generation ---
        cnn_risk_score = 0.0
        gradcam_url = None 
        xray_file = request.files.get('xray')

        if xray_file and xray_file.filename:
            xray_path = os.path.join(app.config['UPLOAD_FOLDER'], xray_file.filename)
            xray_file.save(xray_path)
            
            abs_xray_path = os.path.abspath(xray_path)

            cnn_risk_score = float(predict_xray_risk(abs_xray_path))
            gradcam_filename = generate_and_save_gradcam(abs_xray_path) 
            
            # 3. REVERTED URL ASSIGNMENT (Using filename directly)
            if gradcam_filename:
                gradcam_url = gradcam_filename # 👈 REVERTED TO FILENAME ASSIGNMENT

        # --- 5️⃣ Risk Fusion Logic ---
        WEIGHT_TABULAR = 0.5
        WEIGHT_OCR = 0.3
        WEIGHT_CNN = 0.2
        combined_score = (
            WEIGHT_TABULAR * tabular_high_prob +
            WEIGHT_OCR * ocr_risk_score +
            WEIGHT_CNN * cnn_risk_score
        )

        if combined_score >= 0.65:
            final_risk = "High"
        elif combined_score >= 0.35:
            final_risk = "Medium"
        else:
            final_risk = "Low"

        # --- 6️⃣ Render Template Response ---
        return render_template('result.html', 
                               final_risk_level=final_risk, 
                               confidence=round(tabular_confidence, 2),
                               user_data=data_dict,
                               ocr_score=round(ocr_risk_score * 100, 2),
                               ocr_keywords=ocr_keywords,
                               cnn_score=round(cnn_risk_score * 100, 2),
                               combined_score=round(combined_score * 100, 2),
                               gradcam_image_url=gradcam_url)

    except Exception as e:
        return render_template('result.html', 
                               final_risk_level="Error", 
                               combined_score=0, 
                               error_message=f"Processing Error: {str(e)}",
                               user_data={})


if __name__ == '__main__':
    app.run(debug=True)