VIJAYARAGUL commited on
Commit
d0a59c3
·
1 Parent(s): 92423e0

version 1

Browse files
Files changed (5) hide show
  1. Dockerfile +25 -0
  2. Random_forest_model.pkl +3 -0
  3. XGBOOST.pkl +3 -0
  4. app.py +278 -0
  5. requirements.txt +9 -0
Dockerfile ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # Install system dependencies
6
+ RUN apt-get update && apt-get install -y \
7
+ gcc \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ # Copy requirements first for better caching
11
+ COPY requirements.txt .
12
+
13
+ # Install Python dependencies
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Copy application code and model files
17
+ COPY main.py .
18
+ COPY Random_forest_model.pkl .
19
+ COPY XGBOOST.pkl .
20
+
21
+ # Expose port
22
+ EXPOSE 7860
23
+
24
+ # Command to run the application
25
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
Random_forest_model.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a2adcefa09f3ca261a95544dad06ea3e023e150b6af989299daa8f3f164d3552
3
+ size 17882537
XGBOOST.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1fee72a3b0ab0560272f82f3e94263723c39b30fbc2e9cd7cbf07afedaca6b37
3
+ size 1050250
app.py ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import joblib
2
+ from fastapi import FastAPI, HTTPException
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from fastapi.responses import HTMLResponse
5
+ import numpy as np
6
+ from pydantic import BaseModel, Field
7
+ from typing import List, Dict, Any
8
+ import json
9
+ from datetime import datetime
10
+
11
+ # FastAPI app with enhanced metadata
12
+ app = FastAPI(
13
+ title="Flood Disaster Management API",
14
+ description="ML-powered API for flood prediction and damage assessment using Random Forest and XGBoost models",
15
+ version="1.0.0",
16
+ docs_url="/", # Swagger UI at root
17
+ redoc_url="/redoc"
18
+ )
19
+
20
+ # Add CORS middleware for web frontend compatibility
21
+ app.add_middleware(
22
+ CORSMiddleware,
23
+ allow_origins=["*"],
24
+ allow_credentials=True,
25
+ allow_methods=["*"],
26
+ allow_headers=["*"],
27
+ )
28
+
29
+
30
+ class PredictionInput(BaseModel):
31
+ features: List[float] = Field(
32
+ ...,
33
+ description="List of input features for prediction",
34
+ example=[40.7128, -74.0060, 100, 25.5, 80, 1013.25]
35
+ )
36
+
37
+
38
+ class PredictionResponse(BaseModel):
39
+ prediction: List[float]
40
+ timestamp: str
41
+ model_used: str
42
+
43
+
44
+ class BatchPredictionInput(BaseModel):
45
+ batch_features: List[List[float]] = Field(
46
+ ...,
47
+ description="List of feature arrays for batch prediction",
48
+ example=[[40.7128, -74.0060, 100, 25.5, 80, 1013.25], [41.8781, -87.6298, 120, 22.3, 75, 1015.2]]
49
+ )
50
+
51
+
52
+ class ModelInfo(BaseModel):
53
+ model_name: str
54
+ model_type: str
55
+ feature_count: int
56
+ description: str
57
+
58
+
59
+ # Load models with error handling
60
+ try:
61
+ with open('Random_forest_model.pkl', 'rb') as file:
62
+ model = joblib.load(file)
63
+ print("✅ Random Forest model loaded successfully")
64
+ except Exception as e:
65
+ print(f"❌ Error loading Random Forest model: {e}")
66
+ model = None
67
+
68
+ try:
69
+ with open('XGBOOST.pkl', 'rb') as file:
70
+ model2 = joblib.load(file)
71
+ print("✅ XGBoost model loaded successfully")
72
+ except Exception as e:
73
+ print(f"❌ Error loading XGBoost model: {e}")
74
+ model2 = None
75
+
76
+
77
+ def transform_features(features: List[float]) -> np.ndarray:
78
+ """Convert lat/lon to sin/cos and keep rest of features."""
79
+ lat, lon = features[0], features[1]
80
+ lat_sin, lat_cos = np.sin(np.radians(lat)), np.cos(np.radians(lat))
81
+ lon_sin, lon_cos = np.sin(np.radians(lon)), np.cos(np.radians(lon))
82
+
83
+ # Build final array
84
+ # arr = [lat_sin, lat_cos, lon_sin, lon_cos] + features[2:]
85
+ arr = features
86
+ return np.array(arr).reshape(1, -1)
87
+
88
+
89
+ @app.post("/predict/happen", response_model=PredictionResponse, tags=["Predictions"])
90
+ async def predict_happen(input_data: PredictionInput):
91
+ """Predict flood occurrence probability using Random Forest model."""
92
+ if model is None:
93
+ raise HTTPException(status_code=500, detail="Random Forest model not available")
94
+
95
+ try:
96
+ arr = transform_features(input_data.features)
97
+ prediction = model.predict(arr)
98
+ return PredictionResponse(
99
+ prediction=prediction.tolist(),
100
+ timestamp=datetime.now().isoformat(),
101
+ model_used="Random Forest"
102
+ )
103
+ except Exception as e:
104
+ raise HTTPException(status_code=400, detail=f"Prediction error: {str(e)}")
105
+
106
+
107
+ @app.post("/predict/damage", response_model=PredictionResponse, tags=["Predictions"])
108
+ async def predict_damage(input_data: PredictionInput):
109
+ """Predict flood damage assessment using XGBoost model."""
110
+ if model2 is None:
111
+ raise HTTPException(status_code=500, detail="XGBoost model not available")
112
+
113
+ try:
114
+ arr = transform_features(input_data.features)
115
+ prediction = model2.predict(arr) # <- Correct model used
116
+ return PredictionResponse(
117
+ prediction=prediction.tolist(),
118
+ timestamp=datetime.now().isoformat(),
119
+ model_used="XGBoost"
120
+ )
121
+ except Exception as e:
122
+ raise HTTPException(status_code=400, detail=f"Prediction error: {str(e)}")
123
+
124
+
125
+ @app.post("/predict/batch", tags=["Predictions"])
126
+ async def predict_batch(input_data: BatchPredictionInput, model_type: str = "happen"):
127
+ """Make batch predictions for multiple samples."""
128
+ if model_type not in ["happen", "damage"]:
129
+ raise HTTPException(status_code=400, detail="model_type must be 'happen' or 'damage'")
130
+
131
+ selected_model = model if model_type == "happen" else model2
132
+ model_name = "Random Forest" if model_type == "happen" else "XGBoost"
133
+
134
+ if selected_model is None:
135
+ raise HTTPException(status_code=500, detail=f"{model_name} model not available")
136
+
137
+ try:
138
+ predictions = []
139
+ for features in input_data.batch_features:
140
+ arr = transform_features(features)
141
+ pred = selected_model.predict(arr)
142
+ predictions.append(pred.tolist()[0])
143
+
144
+ return {
145
+ "predictions": predictions,
146
+ "count": len(predictions),
147
+ "model_used": model_name,
148
+ "timestamp": datetime.now().isoformat()
149
+ }
150
+ except Exception as e:
151
+ raise HTTPException(status_code=400, detail=f"Batch prediction error: {str(e)}")
152
+
153
+
154
+ @app.get("/models/info", response_model=List[ModelInfo], tags=["Model Information"])
155
+ async def get_model_info():
156
+ """Get information about loaded models."""
157
+ models_info = []
158
+
159
+ if model is not None:
160
+ try:
161
+ feature_count = model.n_features_in_ if hasattr(model, 'n_features_in_') else "Unknown"
162
+ except:
163
+ feature_count = "Unknown"
164
+
165
+ models_info.append(ModelInfo(
166
+ model_name="Random Forest",
167
+ model_type="Classification/Regression",
168
+ feature_count=feature_count,
169
+ description="Used for flood occurrence prediction"
170
+ ))
171
+
172
+ if model2 is not None:
173
+ try:
174
+ feature_count = model2.n_features_in_ if hasattr(model2, 'n_features_in_') else "Unknown"
175
+ except:
176
+ feature_count = "Unknown"
177
+
178
+ models_info.append(ModelInfo(
179
+ model_name="XGBoost",
180
+ model_type="Gradient Boosting",
181
+ feature_count=feature_count,
182
+ description="Used for flood damage assessment"
183
+ ))
184
+
185
+ return models_info
186
+
187
+
188
+ @app.get("/predict/demo", response_class=HTMLResponse, tags=["Demo"])
189
+ async def demo_interface():
190
+ """Simple HTML demo interface for testing the API."""
191
+ return HTMLResponse(content="""
192
+ <!DOCTYPE html>
193
+ <html>
194
+ <head>
195
+ <title>Flood Prediction Demo</title>
196
+ <style>
197
+ body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
198
+ .container { background: #f5f5f5; padding: 20px; border-radius: 10px; margin: 10px 0; }
199
+ input, button { margin: 5px; padding: 8px; }
200
+ button { background: #007bff; color: white; border: none; border-radius: 4px; cursor: pointer; }
201
+ button:hover { background: #0056b3; }
202
+ .result { background: #e9ecef; padding: 10px; border-radius: 4px; margin-top: 10px; }
203
+ </style>
204
+ </head>
205
+ <body>
206
+ <h1>🌊 Flood Disaster Management API Demo</h1>
207
+
208
+ <div class="container">
209
+ <h3>Test Flood Occurrence Prediction</h3>
210
+ <p>Enter features (comma-separated): Latitude, Longitude, Elevation, Temperature, Humidity, Pressure</p>
211
+ <input type="text" id="features1" placeholder="40.7128,-74.0060,100,25.5,80,1013.25" style="width: 400px;">
212
+ <button onclick="testHappen()">Predict Occurrence</button>
213
+ <div id="result1" class="result" style="display: none;"></div>
214
+ </div>
215
+
216
+ <div class="container">
217
+ <h3>Test Damage Assessment</h3>
218
+ <p>Enter features (comma-separated):</p>
219
+ <input type="text" id="features2" placeholder="40.7128,-74.0060,100,25.5,80,1013.25" style="width: 400px;">
220
+ <button onclick="testDamage()">Predict Damage</button>
221
+ <div id="result2" class="result" style="display: none;"></div>
222
+ </div>
223
+
224
+ <script>
225
+ async function testHappen() {
226
+ const features = document.getElementById('features1').value.split(',').map(x => parseFloat(x.trim()));
227
+ const response = await fetch('/predict/happen', {
228
+ method: 'POST',
229
+ headers: {'Content-Type': 'application/json'},
230
+ body: JSON.stringify({features: features})
231
+ });
232
+ const result = await response.json();
233
+ document.getElementById('result1').style.display = 'block';
234
+ document.getElementById('result1').innerHTML = '<strong>Result:</strong> ' + JSON.stringify(result, null, 2);
235
+ }
236
+
237
+ async function testDamage() {
238
+ const features = document.getElementById('features2').value.split(',').map(x => parseFloat(x.trim()));
239
+ const response = await fetch('/predict/damage', {
240
+ method: 'POST',
241
+ headers: {'Content-Type': 'application/json'},
242
+ body: JSON.stringify({features: features})
243
+ });
244
+ const result = await response.json();
245
+ document.getElementById('result2').style.display = 'block';
246
+ document.getElementById('result2').innerHTML = '<strong>Result:</strong> ' + JSON.stringify(result, null, 2);
247
+ }
248
+ </script>
249
+ </body>
250
+ </html>
251
+ """)
252
+
253
+
254
+ @app.api_route("/health", methods=["GET", "HEAD"], tags=["Health"])
255
+ async def health_check():
256
+ """Health check endpoint with detailed system status."""
257
+ return {
258
+ "status": "alive",
259
+ "service": "flood-disaster-management",
260
+ "timestamp": datetime.now().isoformat(),
261
+ "models": {
262
+ "random_forest": "loaded" if model is not None else "failed",
263
+ "xgboost": "loaded" if model2 is not None else "failed"
264
+ },
265
+ "version": "1.0.0"
266
+ }
267
+
268
+
269
+ @app.get("/", tags=["Documentation"])
270
+ async def root():
271
+ """Root endpoint redirects to API documentation."""
272
+ return {
273
+ "message": "Flood Disaster Management API",
274
+ "documentation": "/docs",
275
+ "demo": "/predict/demo",
276
+ "health": "/health",
277
+ "version": "1.0.0"
278
+ }
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.112.0
2
+ uvicorn==0.30.0
3
+ scikit-learn==1.6.1
4
+ numpy==1.26.4
5
+ pydantic==2.8.0
6
+ gunicorn==22.0.0
7
+ joblib==1.4.2
8
+ xgboost>=2.1.0
9
+ imbalanced-learn>=0.12.0