File size: 15,002 Bytes
8728572
 
162ee74
8728572
 
fbed134
8728572
 
 
 
 
 
 
 
 
fbed134
8728572
 
 
 
 
 
 
fbed134
8728572
 
 
 
 
 
 
 
 
 
 
b5c103c
8728572
 
 
fbed134
8728572
 
fbed134
8728572
 
 
fbed134
8728572
 
 
 
 
 
 
 
 
 
 
 
162ee74
8728572
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fbed134
8728572
 
 
 
 
 
 
 
 
 
 
 
162ee74
8728572
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162ee74
8728572
 
 
 
fbed134
8728572
b5c103c
8728572
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
# app.py - Fixed for 4-feature BioSentinel Model
import gradio as gr
import joblib
import numpy as np
from typing import Tuple

class BioSentinelPredictor:
    def __init__(self):
        try:
            self.model = joblib.load("model.joblib")
            self.model_loaded = True
            print(f"βœ… Model loaded successfully!")
        except Exception as e:
            print(f"❌ Error loading model: {e}")
            self.model_loaded = False
        
        # Only 4 features to match your trained model
        self.feature_columns = [
            "pH",
            "Hardness", 
            "Solids",
            "Chloramines"
        ]
        
        # Realistic ranges for water quality parameters
        self.feature_ranges = {
            "pH": (3.0, 9.5, 7.0),
            "Hardness": (47.0, 323.0, 196.0),
            "Solids": (320.0, 61227.0, 22000.0),
            "Chloramines": (0.35, 13.13, 7.0)
        }

    def predict(self, ph, hardness, solids, chloramines) -> Tuple[str, str, str]:
        if not self.model_loaded:
            return "❌ Model Error", "Could not load the trained model. Please check if model.joblib exists.", ""
        
        try:
            # Create input array with exactly 4 features (matching your model)
            features = np.array([[ph, hardness, solids, chloramines]])
            
            # Debug: Print input values
            print(f"πŸ” Input values: pH={ph}, Hardness={hardness}, Solids={solids}, Chloramines={chloramines}")
            
            # Make prediction
            prediction = self.model.predict(features)[0]
            print(f"🎯 Model prediction: {prediction}")
            
            # Get confidence score if available
            confidence_text = ""
            proba_values = None
            if hasattr(self.model, 'predict_proba'):
                try:
                    proba = self.model.predict_proba(features)[0]
                    proba_values = proba
                    confidence = max(proba)
                    confidence_text = f"\nConfidence: {confidence:.1%}"
                    print(f"πŸ“Š Probabilities: {proba}")
                except Exception as e:
                    print(f"Confidence error: {e}")
            
            # Create dynamic detailed analysis based on actual parameters
            detailed_analysis = self._create_dynamic_analysis(ph, hardness, solids, chloramines, prediction, proba_values)
            
            # Interpret results with more nuanced responses
            if prediction == 1:
                result = "βœ… SAFE TO DRINK"
                base_description = "Water quality analysis indicates this sample is generally SAFE for consumption."
            else:
                result = "⚠️ NOT SAFE"
                base_description = "Water quality analysis indicates potential safety concerns with this sample."
            
            # Add specific concerns based on parameters
            concerns = self._identify_concerns(ph, hardness, solids, chloramines)
            
            final_description = f"{base_description}\n\n{detailed_analysis}{confidence_text}"
            
            # Parameter breakdown
            feature_analysis = self._create_parameter_breakdown(ph, hardness, solids, chloramines)
            
            return result, final_description, feature_analysis
            
        except Exception as e:
            error_msg = str(e)
            print(f"❌ Prediction error: {error_msg}")
            return "❌ Prediction Failed", f"Error during prediction: {error_msg}", "Please check your input values and try again."

    def _create_dynamic_analysis(self, ph, hardness, solids, chloramines, prediction, proba_values):
        """Create dynamic analysis based on actual parameter values"""
        
        analysis_parts = []
        
        # pH Analysis
        if ph < 6.5:
            analysis_parts.append("πŸ”΄ **pH too acidic** - May cause corrosion and health issues")
        elif ph > 8.5:
            analysis_parts.append("πŸ”΄ **pH too alkaline** - May cause scaling and taste issues")
        elif 6.5 <= ph <= 8.5:
            analysis_parts.append("🟒 **pH within safe range** - Good for consumption")
        else:
            analysis_parts.append("🟑 **pH borderline** - Monitor closely")
        
        # Hardness Analysis
        if hardness > 300:
            analysis_parts.append("🟑 **High mineral content** - Very hard water")
        elif hardness > 180:
            analysis_parts.append("🟒 **Moderate mineral content** - Moderately hard water")
        else:
            analysis_parts.append("🟒 **Low to moderate hardness** - Acceptable levels")
        
        # Solids Analysis
        if solids > 1000:
            analysis_parts.append("πŸ”΄ **High dissolved solids** - Exceeds WHO guidelines")
        elif solids > 500:
            analysis_parts.append("🟑 **Elevated dissolved solids** - Above recommended levels")
        else:
            analysis_parts.append("🟒 **Dissolved solids acceptable** - Within safe range")
        
        # Chloramines Analysis
        if chloramines > 4.0:
            analysis_parts.append("πŸ”΄ **High chloramines** - Exceeds EPA maximum")
        elif chloramines > 2.0:
            analysis_parts.append("🟑 **Moderate chloramines** - Acceptable but elevated")
        else:
            analysis_parts.append("🟒 **Low chloramines** - Within safe limits")
        
        # Risk level based on prediction and confidence
        if prediction == 1:
            if proba_values is not None and max(proba_values) > 0.8:
                risk_text = "🟒 **Low Risk** - High confidence in safety assessment"
            elif proba_values is not None and max(proba_values) > 0.6:
                risk_text = "🟑 **Moderate Confidence** - Generally safe but monitor"
            else:
                risk_text = "🟑 **Low Confidence** - Additional testing recommended"
        else:
            if proba_values is not None and max(proba_values) > 0.8:
                risk_text = "πŸ”΄ **High Risk** - Strong indication of safety concerns"
            elif proba_values is not None and max(proba_values) > 0.6:
                risk_text = "🟑 **Moderate Risk** - Some safety concerns identified"
            else:
                risk_text = "🟑 **Uncertain Risk** - Requires professional testing"
        
        # Recommendations
        if prediction == 0:
            if ph < 6.5 or ph > 8.5:
                recommendations = "πŸ’‘ **Recommended Actions:** pH adjustment, professional water treatment"
            elif solids > 1000:
                recommendations = "πŸ’‘ **Recommended Actions:** Filtration system, reverse osmosis treatment"
            elif chloramines > 4.0:
                recommendations = "πŸ’‘ **Recommended Actions:** Carbon filtration, contact water utility"
            else:
                recommendations = "πŸ’‘ **Recommended Actions:** Professional water testing, consider treatment options"
        else:
            recommendations = "πŸ’‘ **Recommended Actions:** Regular monitoring, maintain current water source quality"
        
        return f"{risk_text}\n\n" + "\n".join(analysis_parts) + f"\n\n{recommendations}"

    def _identify_concerns(self, ph, hardness, solids, chloramines):
        """Identify specific parameter concerns"""
        concerns = []
        
        if ph < 6.5 or ph > 8.5:
            concerns.append("pH out of safe range")
        if hardness > 300:
            concerns.append("very hard water")
        if solids > 500:
            concerns.append("high dissolved solids")
        if chloramines > 4.0:
            concerns.append("excessive chloramines")
            
        return concerns

    def _create_parameter_breakdown(self, ph, hardness, solids, chloramines) -> str:
        """Create detailed parameter analysis"""
        
        analysis = "πŸ“Š **Parameter Analysis:**\n\n"
        values = [ph, hardness, solids, chloramines]
        units = ["", "(mg/L)", "(ppm)", "(ppm)"]
        
        # WHO/EPA standard ranges for reference
        safe_ranges = {
            "pH": (6.5, 8.5),
            "Hardness": (0, 300),
            "Solids": (0, 500),  # WHO guideline for TDS
            "Chloramines": (0, 4.0)  # EPA maximum
        }
        
        for i, (feature, value) in enumerate(zip(self.feature_columns, values)):
            unit = units[i]
            
            # Determine status based on WHO/EPA guidelines
            if feature in safe_ranges:
                min_safe, max_safe = safe_ranges[feature]
                if min_safe <= value <= max_safe:
                    status = "βœ… Within Safe Range"
                    color = "🟒"
                elif value < min_safe:
                    status = "⚠️ Below Safe Range" 
                    color = "🟑"
                else:
                    status = "❌ Above Safe Range"
                    color = "πŸ”΄"
            else:
                status = "ℹ️ Measured"
                color = "βšͺ"
            
            analysis += f"{color} **{feature}**: {value:.2f} {unit} - {status}\n"
        
        analysis += "\nπŸ“‹ **Guidelines Used**: WHO & EPA Water Quality Standards"
        return analysis

# Initialize the predictor
predictor = BioSentinelPredictor()

def create_interface():
    with gr.Blocks(
        title="🧬 BioSentinel Water Quality Predictor",
        theme=gr.themes.Soft(),
        css="""
        .gradio-container {
            max-width: 1200px !important;
        }
        """
    ) as interface:
        
        # Header
        gr.Markdown("""
        # 🧬 BioSentinel - Water Quality Predictor
        
        **AI-Powered Water Safety Assessment System**
        
        Enter water quality parameters below for instant safety analysis. This system uses machine learning 
        to evaluate water potability based on critical physicochemical properties.
        """)
        
        # Main interface
        with gr.Row():
            # Input Section
            with gr.Column(scale=1):
                gr.Markdown("### πŸ”¬ Water Quality Parameters")
                
                ph_input = gr.Slider(
                    minimum=3.0, maximum=9.5, value=7.0, step=0.1,
                    label="🌊 pH Level",
                    info="Acidity/Alkalinity measure (6.5-8.5 ideal)"
                )
                
                hardness_input = gr.Slider(
                    minimum=47.0, maximum=323.0, value=196.0, step=1.0,
                    label="πŸ’Ž Hardness (mg/L)",
                    info="Calcium & magnesium content (0-300 acceptable)"
                )
                
                solids_input = gr.Slider(
                    minimum=320.0, maximum=61227.0, value=22000.0, step=100.0,
                    label="βšͺ Total Dissolved Solids (ppm)",
                    info="Dissolved mineral content (<500 ideal)"
                )
                
                chloramines_input = gr.Slider(
                    minimum=0.35, maximum=13.13, value=7.0, step=0.1,
                    label="πŸ§ͺ Chloramines (ppm)",
                    info="Disinfection byproducts (<4.0 safe)"
                )
                
                # Analysis Button
                predict_button = gr.Button(
                    "πŸ” Analyze Water Quality", 
                    variant="primary", 
                    size="lg",
                    scale=1
                )
            
            # Results Section  
            with gr.Column(scale=1):
                gr.Markdown("### 🎯 Analysis Results")
                
                # Main result
                result_output = gr.Textbox(
                    label="Safety Assessment",
                    placeholder="Click 'Analyze Water Quality' to get results...",
                    lines=2,
                    max_lines=2
                )
                
                # Detailed analysis
                description_output = gr.Textbox(
                    label="Detailed Analysis",
                    placeholder="Detailed safety analysis will appear here...",
                    lines=4,
                    max_lines=6
                )
                
                # Parameter breakdown
                feature_output = gr.Textbox(
                    label="Parameter Breakdown",
                    placeholder="Individual parameter analysis will show here...",
                    lines=8,
                    max_lines=12
                )
        
        # Connect prediction function
        inputs = [ph_input, hardness_input, solids_input, chloramines_input]
        outputs = [result_output, description_output, feature_output]
        
        predict_button.click(
            fn=predictor.predict,
            inputs=inputs,
            outputs=outputs
        )
        
        # Quick Examples Section
        with gr.Row():
            gr.Markdown("### πŸ“‹ Quick Test Examples")
        
        with gr.Row():
            safe_btn = gr.Button("βœ… Safe Water Sample", variant="secondary")
            unsafe_btn = gr.Button("❌ Unsafe Water Sample", variant="secondary")
            neutral_btn = gr.Button("βš–οΈ Borderline Sample", variant="secondary")
        
        # Example functions with more varied data
        def load_safe_example():
            return [7.2, 150.0, 250.0, 2.5]  # Really good quality water
        
        def load_unsafe_example():
            return [4.5, 50.0, 45000.0, 11.0]  # Really poor quality water
        
        def load_borderline_example():
            return [8.8, 320.0, 800.0, 4.5]  # Borderline case with multiple issues
        
        # Connect example buttons
        safe_btn.click(load_safe_example, outputs=inputs)
        unsafe_btn.click(load_unsafe_example, outputs=inputs)
        neutral_btn.click(load_borderline_example, outputs=inputs)
        
        # Footer
        gr.Markdown("""
        ---
        ### ⚠️ Important Disclaimer
        
        This tool provides **AI-based predictions for educational and research purposes only**. 
        For official water quality certification and regulatory compliance, always consult:
        - Certified water testing laboratories
        - Local health departments  
        - Environmental protection agencies
        
        ### πŸ”¬ About This Model
        
        - **Technology**: Machine Learning classification model
        - **Parameters**: pH, Hardness, Total Dissolved Solids, Chloramines
        - **Standards**: Based on WHO and EPA water quality guidelines
        - **Purpose**: Educational demonstration of AI in water quality assessment
        
        **Built with ❀️ for water quality research and education**
        """)
    
    return interface

# Create the interface
demo = create_interface()

# Launch the app
if __name__ == "__main__":
    demo.launch()