agentsay commited on
Commit
dcb82e9
·
verified ·
1 Parent(s): 1af162f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +393 -489
app.py CHANGED
@@ -1,489 +1,393 @@
1
- from flask import Flask, render_template, request, jsonify
2
- import pandas as pd
3
- from prophet import Prophet
4
- import matplotlib.pyplot as plt
5
- import os
6
-
7
- import matplotlib
8
- matplotlib.use("Agg")
9
-
10
- from flask_cors import CORS
11
-
12
-
13
- def get_soil_category(score):
14
- if score == 0:
15
- return "No Soil Health Data"
16
- elif score >= 4.5:
17
- return "Very Excellent Soil Health"
18
- elif score >= 4:
19
- return "Excellent Soil Health"
20
- elif score >= 3:
21
- return "Good Soil Health"
22
- elif score >= 2:
23
- return "Poor Soil Health"
24
- else:
25
- return "Very Poor Soil Health"
26
-
27
- def calculate_climate_score(yield_cat, soil_cat):
28
- score_map = {
29
- "Highly Recommended Crop": 90,
30
- "Good Crop": 70,
31
- "Poor Crop": 50,
32
- "Very Poor Crop": 30,
33
- "Very Excellent Soil Health": 95,
34
- "Excellent Soil Health": 85,
35
- "Good Soil Health": 65,
36
- "Poor Soil Health": 45,
37
- "Very Poor Soil Health": 25,
38
- "No Soil Health Data": 0
39
- }
40
- return int((score_map[yield_cat] * 0.6) + (score_map[soil_cat] * 0.4))
41
-
42
- app = Flask(__name__)
43
- CORS(app)
44
-
45
- UPLOAD_FOLDER = 'static'
46
- if not os.path.exists(UPLOAD_FOLDER):
47
- os.makedirs(UPLOAD_FOLDER)
48
-
49
- yield_file = 'ICRISAT-District_Level_Data_30_Years.csv'
50
- soil_file = 'SoilHealthScores_by_District_2.csv'
51
-
52
- yield_df = pd.read_csv(yield_file)
53
- soil_df = pd.read_csv(soil_file)
54
- soil_df['Soil_Category'] = soil_df['SoilHealthScore'].apply(get_soil_category)
55
-
56
- yield_columns = [col for col in yield_df.columns if 'YIELD (Kg per ha)' in col]
57
- base_crop_names = {col.split(' YIELD')[0]: col for col in yield_columns}
58
-
59
- @app.route('/', methods=['GET', 'POST'])
60
- def home():
61
- return render_template('index.html', crops=base_crop_names.keys())
62
-
63
- @app.route('/api/crops', methods=['GET'])
64
- def get_crops():
65
- return jsonify({"crops": list(base_crop_names.keys())})
66
-
67
- @app.route('/predict', methods=['POST'])
68
- def predict():
69
- crop_input = request.form.get('crop')
70
- district_input = request.form.get('district')
71
- land_area = request.form.get('land_area')
72
- print(crop_input)
73
-
74
- if not crop_input or not district_input or crop_input not in base_crop_names:
75
- return "Invalid input. Please enter a valid crop and district.", 400
76
-
77
- yield_col = base_crop_names[crop_input]
78
- district_yield = yield_df[yield_df['Dist Name'] == district_input]
79
- district_soil = soil_df[soil_df['Dist Name'] == district_input]
80
-
81
- if district_yield.empty or district_soil.empty:
82
- return "District data not found.", 400
83
-
84
- ts_data = district_yield[['Year', yield_col]].dropna()
85
- ts_data.columns = ['ds', 'y']
86
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
87
-
88
- model = Prophet(yearly_seasonality=True, growth='flat')
89
- model.fit(ts_data)
90
-
91
- future = model.make_future_dataframe(periods=1, freq='YS')
92
- forecast = model.predict(future)
93
- predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
94
-
95
- if predicted_yield > 1000:
96
- yield_cat = "Highly Recommended Crop"
97
- color = "green"
98
- elif predicted_yield > 500:
99
- yield_cat = "Good Crop"
100
- color = "yellow"
101
- elif predicted_yield > 200:
102
- yield_cat = "Poor Crop"
103
- color = "orange"
104
- else:
105
- yield_cat = "Very Poor Crop"
106
- color = "red"
107
-
108
- soil_score = district_soil['SoilHealthScore'].values[0]
109
- soil_cat = district_soil['Soil_Category'].values[0]
110
- climate_score = calculate_climate_score(yield_cat, soil_cat)
111
-
112
- plt.figure(figsize=(10, 5))
113
- model.plot(forecast)
114
- image_path = os.path.join(UPLOAD_FOLDER, "forecast.png")
115
- plt.savefig(image_path)
116
- plt.close()
117
- loan_amount = calculate_loan(crop_input,predicted_yield, yield_cat, soil_cat, climate_score)
118
-
119
-
120
-
121
- #
122
-
123
- best_crop = None
124
- max_yield = 0
125
- for crop, column in base_crop_names.items():
126
- ts_data = district_yield[['Year', column]].dropna()
127
- ts_data.columns = ['ds', 'y']
128
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
129
- if len(ts_data) >= 5:
130
- model = Prophet(yearly_seasonality=True, growth='flat')
131
- model.fit(ts_data)
132
- future = model.make_future_dataframe(periods=1, freq='YS')
133
- forecast = model.predict(future)
134
- predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
135
- if predicted_yield > max_yield:
136
- max_yield = predicted_yield
137
- best_crop = crop
138
- if best_crop:
139
- print(f"\n{'='*40}")
140
- print(f"Maximum Yield Prediction for {district_input}:")
141
- print(f"Best Crop: {best_crop}")
142
- print(f"Predicted Yield: {max_yield:.2f} Kg/ha (HighlyRecommended Crop)")
143
- print(f"{'='*40}")
144
- #
145
-
146
- plt.figure(figsize=(10, 5))
147
- ts_data = district_yield[['Year', yield_col]].dropna()
148
- ts_data.columns = ['ds', 'y']
149
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
150
- plt.plot(ts_data['ds'], ts_data['y'], label=f'{crop_input} Yield')
151
-
152
- best_crop_data = district_yield[['Year', base_crop_names[best_crop]]].dropna()
153
- best_crop_data.columns = ['ds', 'y']
154
- best_crop_data['ds'] = pd.to_datetime(best_crop_data['ds'], format='%Y')
155
- plt.plot(best_crop_data['ds'], best_crop_data['y'], label=f'{best_crop} Yield', linestyle='--')
156
-
157
- plt.xlabel('Year')
158
-
159
- plt.ylabel('Yield (Kg/ha)')
160
- plt.title(f"Yield Comparison for {crop_input} and Best Crop ({best_crop}) in {district_input}")
161
- plt.legend()
162
- image_path2 = os.path.join(UPLOAD_FOLDER, "forecast2.png")
163
- plt.grid(True)
164
- plt.savefig(image_path2)
165
- plt.close()
166
- # plt.show()
167
- result = {
168
- "crop": crop_input,
169
- "district": district_input,
170
- "predicted_yield": (f"{round(predicted_yield, 2)}Kg/ha"),
171
- "loan_amount": float(loan_amount)*float(land_area),
172
- "best_crop": best_crop,
173
- "yield_cat": yield_cat,
174
- "color": color,
175
- "soil_health": soil_cat,
176
- "climate_score": climate_score
177
- }
178
-
179
-
180
- return render_template('index.html', result=result, image_path=image_path, image_path2=image_path2,crops=base_crop_names.keys())
181
-
182
- def calculate_loan(c,predicted_yield, yield_cat, soil_cat, climate_score):
183
- # base_loan = 50000 # Base loan amount in INR
184
- crop_base_prices_per_hectare = {
185
- "RICE": 75000,
186
- "WHEAT": 65000,
187
- "KHARIF SORGHUM": 60000,
188
- "RABI SORGHUM": 62000,
189
- "SORGHUM": 61000,
190
- "PEARL MILLET": 50000,
191
- "MAIZE": 55000,
192
- "FINGER MILLET": 77000,
193
- "BARLEY": 48000,
194
- "CHICKPEA": 90000,
195
- "PIGEONPEA": 95000,
196
- "MINOR PULSES": 85000,
197
- "GROUNDNUT": 110000,
198
- "SESAMUM": 130000,
199
- "RAPESEED AND MUSTARD": 100000,
200
- "SAFFLOWER": 95000,
201
- "CASTOR": 88000,
202
- "LINSEED": 90000,
203
- "SUNFLOWER": 102000,
204
- "SOYABEAN": 98000,
205
- "OILSEEDS": 94000,
206
- "SUGARCANE": 150000,
207
- "COTTON": 120000
208
- }
209
- base_loan = crop_base_prices_per_hectare[c]
210
- # Yield category weightage
211
- yield_multiplier = {
212
- "Highly Recommended Crop": 1.5,
213
- "Good Crop": 1.2,
214
- "Poor Crop": 0.8,
215
- "Very Poor Crop": 0.5
216
- }
217
-
218
- # Soil health weightage
219
- soil_multiplier = {
220
- "Very Excellent Soil Health": 1.5,
221
- "Excellent Soil Health": 1.3,
222
- "Good Soil Health": 1.1,
223
- "Poor Soil Health": 0.9,
224
- "Very Poor Soil Health": 0.7,
225
- "No Soil Health Data": 0.5
226
- }
227
-
228
- # Climate score impact (normalized)
229
- climate_multiplier = climate_score / 100
230
-
231
- # Calculate final loan amount
232
- loan_amount = base_loan * yield_multiplier[yield_cat] * soil_multiplier[soil_cat] * climate_multiplier
233
- return round(loan_amount, 2) # Return rounded loan amount
234
-
235
- @app.route('/api/predict', methods=['GET'])
236
- def api_predict():
237
- crop_input = request.args.get('crop')
238
- district_input = request.args.get('district')
239
- area = request.args.get('land')
240
-
241
- if not crop_input or not district_input:
242
- return jsonify({"error": "Missing crop or district in request."}), 400
243
-
244
- return predict2(crop_input, district_input, area)
245
-
246
-
247
-
248
- @app.route('/predict2', methods=['POST'])
249
- def predict2(c, d, a):
250
- crop_input = c
251
- district_input = d
252
- area = a
253
-
254
- if not crop_input or not district_input or crop_input not in base_crop_names:
255
- return jsonify({"error": "Invalid input. Please enter a valid crop and district."}), 400
256
-
257
- yield_col = base_crop_names[crop_input]
258
- district_yield = yield_df[yield_df['Dist Name'] == district_input]
259
- district_soil = soil_df[soil_df['Dist Name'] == district_input]
260
-
261
- if district_yield.empty or district_soil.empty:
262
- return jsonify({"error": "District data not found."}), 400
263
-
264
- ts_data = district_yield[['Year', yield_col]].dropna()
265
- ts_data.columns = ['ds', 'y']
266
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
267
-
268
- model = Prophet(yearly_seasonality=True, growth='flat')
269
- model.fit(ts_data)
270
-
271
- future = model.make_future_dataframe(periods=1, freq='YS')
272
- forecast = model.predict(future)
273
- predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
274
-
275
- if predicted_yield > 1000:
276
- yield_cat = "Highly Recommended Crop"
277
- color = "green"
278
- elif predicted_yield > 500:
279
- yield_cat = "Good Crop"
280
- color = "yellow"
281
- elif predicted_yield > 200:
282
- yield_cat = "Poor Crop"
283
- color = "orange"
284
- else:
285
- yield_cat = "Very Poor Crop"
286
- color = "red"
287
-
288
- soil_score = district_soil['SoilHealthScore'].values[0]
289
- soil_cat = district_soil['Soil_Category'].values[0]
290
- climate_score = calculate_climate_score(yield_cat, soil_cat)
291
-
292
- # Calculate Loan Amount
293
- loan_amount = calculate_loan(crop_input,predicted_yield, yield_cat, soil_cat, climate_score)
294
- #
295
-
296
- best_crop = None
297
- max_yield = 0
298
- for crop, column in base_crop_names.items():
299
- ts_data = district_yield[['Year', column]].dropna()
300
- ts_data.columns = ['ds', 'y']
301
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
302
- if len(ts_data) >= 5:
303
- model = Prophet(yearly_seasonality=True, growth='flat')
304
- model.fit(ts_data)
305
- future = model.make_future_dataframe(periods=1, freq='YS')
306
- forecast = model.predict(future)
307
- predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
308
- if predicted_yield > max_yield:
309
- max_yield = predicted_yield
310
- best_crop = crop
311
- if best_crop:
312
- print(f"\n{'='*40}")
313
- print(f"Maximum Yield Prediction for {district_input}:")
314
- print(f"Best Crop: {best_crop}")
315
- print(f"Predicted Yield: {max_yield:.2f} Kg/ha (Highly Recommended Crop)")
316
- print(f"{'='*40}")
317
-
318
- top_crops = []
319
- crop_yields = []
320
-
321
- for crop, column in base_crop_names.items():
322
- ts_data = district_yield[['Year', column]].dropna()
323
- ts_data.columns = ['ds', 'y']
324
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
325
-
326
- if len(ts_data) >= 5:
327
- model = Prophet(yearly_seasonality=True, growth='flat')
328
- model.fit(ts_data)
329
- future = model.make_future_dataframe(periods=1, freq='YS')
330
- forecast = model.predict(future)
331
- predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
332
-
333
- crop_yields.append((crop, predicted_yield))
334
-
335
- # Sort crops by predicted yield in descending order and get top 3
336
- top_crops = sorted(crop_yields, key=lambda x: x[1], reverse=True)[:3]
337
-
338
- # Convert to array format
339
- top_crops_array = [crop for crop, yield_value in top_crops]
340
-
341
- print(top_crops_array)
342
-
343
-
344
-
345
- import json
346
-
347
- # Extracting data points from the original crop
348
- ts_data = district_yield[['Year', yield_col]].dropna()
349
- ts_data.columns = ['ds', 'y']
350
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
351
-
352
- ts_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(ts_data['ds'], ts_data['y'])]
353
-
354
- # Extracting data points for the best crop
355
- best_crop_data = district_yield[['Year', base_crop_names[best_crop]]].dropna()
356
- best_crop_data.columns = ['ds', 'y']
357
- best_crop_data['ds'] = pd.to_datetime(best_crop_data['ds'], format='%Y')
358
-
359
- best_crop_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(best_crop_data['ds'], best_crop_data['y'])]
360
-
361
-
362
- #
363
- result = {
364
- "crop": crop_input,
365
- "district": district_input,
366
- "predicted_yield": f"{round(predicted_yield, 2)} Kg/ha",
367
- "yield_category": yield_cat,
368
- "best_crop": top_crops_array,
369
- "soil_health": soil_cat,
370
- "score": climate_score,
371
- "loan_amount": f"{float(loan_amount)*float(area)}",
372
-
373
- }
374
-
375
-
376
- return jsonify(result), 200
377
- @app.route('/api/map', methods=['GET'])
378
- def api_map():
379
- crop_input = request.args.get('crop')
380
- district_input = request.args.get('district')
381
- area = request.args.get('land')
382
-
383
- if not crop_input or not district_input:
384
- return jsonify({"error": "Missing crop or district in request."}), 400
385
-
386
- return map(crop_input, district_input, area)
387
- @app.route('/map', methods=['POST'])
388
- def map(c, d, a):
389
- crop_input = c
390
- district_input = d
391
- area = a
392
-
393
- if not crop_input or not district_input or crop_input not in base_crop_names:
394
- return jsonify({"error": "Invalid input. Please enter a valid crop and district."}), 400
395
-
396
- yield_col = base_crop_names[crop_input]
397
- district_yield = yield_df[yield_df['Dist Name'] == district_input]
398
- district_soil = soil_df[soil_df['Dist Name'] == district_input]
399
-
400
- if district_yield.empty or district_soil.empty:
401
- return jsonify({"error": "District data not found."}), 400
402
-
403
- ts_data = district_yield[['Year', yield_col]].dropna()
404
- ts_data.columns = ['ds', 'y']
405
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
406
-
407
- model = Prophet(yearly_seasonality=True, growth='flat')
408
- model.fit(ts_data)
409
-
410
- future = model.make_future_dataframe(periods=1, freq='YS')
411
- forecast = model.predict(future)
412
- predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
413
-
414
- if predicted_yield > 1000:
415
- yield_cat = "Highly Recommended Crop"
416
- color = "green"
417
- elif predicted_yield > 500:
418
- yield_cat = "Good Crop"
419
- color = "yellow"
420
- elif predicted_yield > 200:
421
- yield_cat = "Poor Crop"
422
- color = "orange"
423
- else:
424
- yield_cat = "Very Poor Crop"
425
- color = "red"
426
-
427
- soil_score = district_soil['SoilHealthScore'].values[0]
428
- soil_cat = district_soil['Soil_Category'].values[0]
429
- climate_score = calculate_climate_score(yield_cat, soil_cat)
430
-
431
- # Calculate Loan Amount
432
- loan_amount = calculate_loan(crop_input,predicted_yield, yield_cat, soil_cat, climate_score)
433
- #
434
-
435
- best_crop = None
436
- max_yield = 0
437
- for crop, column in base_crop_names.items():
438
- ts_data = district_yield[['Year', column]].dropna()
439
- ts_data.columns = ['ds', 'y']
440
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
441
- if len(ts_data) >= 5:
442
- model = Prophet(yearly_seasonality=True, growth='flat')
443
- model.fit(ts_data)
444
- future = model.make_future_dataframe(periods=1, freq='YS')
445
- forecast = model.predict(future)
446
- predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
447
- if predicted_yield > max_yield:
448
- max_yield = predicted_yield
449
- best_crop = crop
450
- if best_crop:
451
- print(f"\n{'='*40}")
452
- print(f"Maximum Yield Prediction for {district_input}:")
453
- print(f"Best Crop: {best_crop}")
454
- print(f"Predicted Yield: {max_yield:.2f} Kg/ha (Highly Recommended Crop)")
455
- print(f"{'='*40}")
456
-
457
-
458
- import json
459
-
460
- # Extracting data points from the original crop
461
- ts_data = district_yield[['Year', yield_col]].dropna()
462
- ts_data.columns = ['ds', 'y']
463
- ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
464
-
465
- ts_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(ts_data['ds'], ts_data['y'])]
466
-
467
- # Extracting data points for the best crop
468
- best_crop_data = district_yield[['Year', base_crop_names[best_crop]]].dropna()
469
- best_crop_data.columns = ['ds', 'y']
470
- best_crop_data['ds'] = pd.to_datetime(best_crop_data['ds'], format='%Y')
471
-
472
- best_crop_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(best_crop_data['ds'], best_crop_data['y'])]
473
-
474
-
475
- #
476
- result = {
477
-
478
- "ts_data": ts_data_json,
479
- "best_crop_data": best_crop_data_json
480
-
481
- }
482
-
483
- # result.headers.add("Access-Control-Allow-Origin","*")
484
- return jsonify(result), 200
485
-
486
-
487
- # if __name__ == '__main__':
488
- # app.run(host='0.0.0.0' ,debug=True)
489
-
 
1
+ from fastapi import FastAPI, HTTPException, Request
2
+ from fastapi.responses import HTMLResponse, JSONResponse
3
+ from fastapi.templating import Jinja2Templates
4
+ from fastapi.staticfiles import StaticFiles
5
+ import pandas as pd
6
+ from prophet import Prophet
7
+ import matplotlib.pyplot as plt
8
+ import os
9
+ import matplotlib
10
+ matplotlib.use("Agg")
11
+ from pydantic import BaseModel
12
+ import json
13
+
14
+ app = FastAPI()
15
+
16
+ # Mount static files
17
+ app.mount("/static", StaticFiles(directory="static"), name="static")
18
+
19
+ # Templates
20
+ templates = Jinja2Templates(directory="templates")
21
+
22
+ UPLOAD_FOLDER = 'static'
23
+ if not os.path.exists(UPLOAD_FOLDER):
24
+ os.makedirs(UPLOAD_FOLDER)
25
+
26
+ # Load data
27
+ yield_file = 'ICRISAT-District_Level_Data_30_Years.csv'
28
+ soil_file = 'SoilHealthScores_by_District_2.csv'
29
+
30
+ yield_df = pd.read_csv(yield_file)
31
+ soil_df = pd.read_csv(soil_file)
32
+
33
+ # Helper functions
34
+ def get_soil_category(score):
35
+ if score == 0:
36
+ return "No Soil Health Data"
37
+ elif score >= 4.5:
38
+ return "Very Excellent Soil Health"
39
+ elif score >= 4:
40
+ return "Excellent Soil Health"
41
+ elif score >= 3:
42
+ return "Good Soil Health"
43
+ elif score >= 2:
44
+ return "Poor Soil Health"
45
+ else:
46
+ return "Very Poor Soil Health"
47
+
48
+ def calculate_climate_score(yield_cat, soil_cat):
49
+ score_map = {
50
+ "Highly Recommended Crop": 90,
51
+ "Good Crop": 70,
52
+ "Poor Crop": 50,
53
+ "Very Poor Crop": 30,
54
+ "Very Excellent Soil Health": 95,
55
+ "Excellent Soil Health": 85,
56
+ "Good Soil Health": 65,
57
+ "Poor Soil Health": 45,
58
+ "Very Poor Soil Health": 25,
59
+ "No Soil Health Data": 0
60
+ }
61
+ return int((score_map[yield_cat] * 0.6) + (score_map[soil_cat] * 0.4))
62
+
63
+ soil_df['Soil_Category'] = soil_df['SoilHealthScore'].apply(get_soil_category)
64
+ yield_columns = [col for col in yield_df.columns if 'YIELD (Kg per ha)' in col]
65
+ base_crop_names = {col.split(' YIELD')[0]: col for col in yield_columns}
66
+
67
+ def calculate_loan(c, predicted_yield, yield_cat, soil_cat, climate_score):
68
+ crop_base_prices_per_hectare = {
69
+ "RICE": 75000,
70
+ "WHEAT": 65000,
71
+ "KHARIF SORGHUM": 60000,
72
+ "RABI SORGHUM": 62000,
73
+ "SORGHUM": 61000,
74
+ "PEARL MILLET": 50000,
75
+ "MAIZE": 55000,
76
+ "FINGER MILLET": 77000,
77
+ "BARLEY": 48000,
78
+ "CHICKPEA": 90000,
79
+ "PIGEONPEA": 95000,
80
+ "MINOR PULSES": 85000,
81
+ "GROUNDNUT": 110000,
82
+ "SESAMUM": 130000,
83
+ "RAPESEED AND MUSTARD": 100000,
84
+ "SAFFLOWER": 95000,
85
+ "CASTOR": 88000,
86
+ "LINSEED": 90000,
87
+ "SUNFLOWER": 102000,
88
+ "SOYABEAN": 98000,
89
+ "OILSEEDS": 94000,
90
+ "SUGARCANE": 150000,
91
+ "COTTON": 120000
92
+ }
93
+ base_loan = crop_base_prices_per_hectare[c]
94
+
95
+ yield_multiplier = {
96
+ "Highly Recommended Crop": 1.5,
97
+ "Good Crop": 1.2,
98
+ "Poor Crop": 0.8,
99
+ "Very Poor Crop": 0.5
100
+ }
101
+
102
+ soil_multiplier = {
103
+ "Very Excellent Soil Health": 1.5,
104
+ "Excellent Soil Health": 1.3,
105
+ "Good Soil Health": 1.1,
106
+ "Poor Soil Health": 0.9,
107
+ "Very Poor Soil Health": 0.7,
108
+ "No Soil Health Data": 0.5
109
+ }
110
+
111
+ climate_multiplier = climate_score / 100
112
+ loan_amount = base_loan * yield_multiplier[yield_cat] * soil_multiplier[soil_cat] * climate_multiplier
113
+ return round(loan_amount, 2)
114
+
115
+ @app.get("/", response_class=HTMLResponse)
116
+ async def home(request: Request):
117
+ return templates.TemplateResponse("index.html", {"request": request, "crops": base_crop_names.keys()})
118
+
119
+ @app.get("/api/crops")
120
+ async def get_crops():
121
+ return {"crops": list(base_crop_names.keys())}
122
+
123
+ class PredictInput(BaseModel):
124
+ crop: str
125
+ district: str
126
+ land_area: str
127
+
128
+ @app.post("/predict", response_class=HTMLResponse)
129
+ async def predict(request: Request, input_data: PredictInput):
130
+ crop_input = input_data.crop
131
+ district_input = input_data.district
132
+ land_area = input_data.land_area
133
+
134
+ if not crop_input or not district_input or crop_input not in base_crop_names:
135
+ raise HTTPException(status_code=400, detail="Invalid input. Please enter a valid crop and district.")
136
+
137
+ yield_col = base_crop_names[crop_input]
138
+ district_yield = yield_df[yield_df['Dist Name'] == district_input]
139
+ district_soil = soil_df[soil_df['Dist Name'] == district_input]
140
+
141
+ if district_yield.empty or district_soil.empty:
142
+ raise HTTPException(status_code=400, detail="District data not found.")
143
+
144
+ ts_data = district_yield[['Year', yield_col]].dropna()
145
+ ts_data.columns = ['ds', 'y']
146
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
147
+
148
+ model = Prophet(yearly_seasonality=True, growth='flat')
149
+ model.fit(ts_data)
150
+
151
+ future = model.make_future_dataframe(periods=1, freq='YS')
152
+ forecast = model.predict(future)
153
+ predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
154
+
155
+ if predicted_yield > 1000:
156
+ yield_cat = "Highly Recommended Crop"
157
+ color = "green"
158
+ elif predicted_yield > 500:
159
+ yield_cat = "Good Crop"
160
+ color = "yellow"
161
+ elif predicted_yield > 200:
162
+ yield_cat = "Poor Crop"
163
+ color = "orange"
164
+ else:
165
+ yield_cat = "Very Poor Crop"
166
+ color = "red"
167
+
168
+ soil_score = district_soil['SoilHealthScore'].values[0]
169
+ soil_cat = district_soil['Soil_Category'].values[0]
170
+ climate_score = calculate_climate_score(yield_cat, soil_cat)
171
+
172
+ plt.figure(figsize=(10, 5))
173
+ model.plot(forecast)
174
+ image_path = os.path.join(UPLOAD_FOLDER, "forecast.png")
175
+ plt.savefig(image_path)
176
+ plt.close()
177
+
178
+ loan_amount = calculate_loan(crop_input, predicted_yield, yield_cat, soil_cat, climate_score)
179
+
180
+ best_crop = None
181
+ max_yield = 0
182
+ for crop, column in base_crop_names.items():
183
+ ts_data = district_yield[['Year', column]].dropna()
184
+ ts_data.columns = ['ds', 'y']
185
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
186
+ if len(ts_data) >= 5:
187
+ model = Prophet(yearly_seasonality=True, growth='flat')
188
+ model.fit(ts_data)
189
+ future = model.make_future_dataframe(periods=1, freq='YS')
190
+ forecast = model.predict(future)
191
+ predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
192
+ if predicted_yield > max_yield:
193
+ max_yield = predicted_yield
194
+ best_crop = crop
195
+
196
+ plt.figure(figsize=(10, 5))
197
+ ts_data = district_yield[['Year', yield_col]].dropna()
198
+ ts_data.columns = ['ds', 'y']
199
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
200
+ plt.plot(ts_data['ds'], ts_data['y'], label=f'{crop_input} Yield')
201
+
202
+ best_crop_data = district_yield[['Year', base_crop_names[best_crop]]].dropna()
203
+ best_crop_data.columns = ['ds', 'y']
204
+ best_crop_data['ds'] = pd.to_datetime(best_crop_data['ds'], format='%Y')
205
+ plt.plot(best_crop_data['ds'], best_crop_data['y'], label=f'{best_crop} Yield', linestyle='--')
206
+
207
+ plt.xlabel('Year')
208
+ plt.ylabel('Yield (Kg/ha)')
209
+ plt.title(f"Yield Comparison for {crop_input} and Best Crop ({best_crop}) in {district_input}")
210
+ plt.legend()
211
+ image_path2 = os.path.join(UPLOAD_FOLDER, "forecast2.png")
212
+ plt.grid(True)
213
+ plt.savefig(image_path2)
214
+ plt.close()
215
+
216
+ result = {
217
+ "crop": crop_input,
218
+ "district": district_input,
219
+ "predicted_yield": f"{round(predicted_yield, 2)}Kg/ha",
220
+ "loan_amount": float(loan_amount) * float(land_area),
221
+ "best_crop": best_crop,
222
+ "yield_cat": yield_cat,
223
+ "color": color,
224
+ "soil_health": soil_cat,
225
+ "climate_score": climate_score
226
+ }
227
+
228
+ return templates.TemplateResponse("index.html", {
229
+ "request": request,
230
+ "result": result,
231
+ "image_path": image_path,
232
+ "image_path2": image_path2,
233
+ "crops": base_crop_names.keys()
234
+ })
235
+
236
+ @app.get("/api/predict")
237
+ async def api_predict(crop: str, district: str, land: str):
238
+ if not crop or not district:
239
+ raise HTTPException(status_code=400, detail="Missing crop or district in request.")
240
+ return await predict2(crop, district, land)
241
+
242
+ async def predict2(crop_input: str, district_input: str, area: str):
243
+ if not crop_input or not district_input or crop_input not in base_crop_names:
244
+ raise HTTPException(status_code=400, detail="Invalid input. Please enter a valid crop and district.")
245
+
246
+ yield_col = base_crop_names[crop_input]
247
+ district_yield = yield_df[yield_df['Dist Name'] == district_input]
248
+ district_soil = soil_df[soil_df['Dist Name'] == district_input]
249
+
250
+ if district_yield.empty or district_soil.empty:
251
+ raise HTTPException(status_code=400, detail="District data not found.")
252
+
253
+ ts_data = district_yield[['Year', yield_col]].dropna()
254
+ ts_data.columns = ['ds', 'y']
255
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
256
+
257
+ model = Prophet(yearly_seasonality=True, growth='flat')
258
+ model.fit(ts_data)
259
+
260
+ future = model.make_future_dataframe(periods=1, freq='YS')
261
+ forecast = model.predict(future)
262
+ predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
263
+
264
+ if predicted_yield > 1000:
265
+ yield_cat = "Highly Recommended Crop"
266
+ color = "green"
267
+ elif predicted_yield > 500:
268
+ yield_cat = "Good Crop"
269
+ color = "yellow"
270
+ elif predicted_yield > 200:
271
+ yield_cat = "Poor Crop"
272
+ color = "orange"
273
+ else:
274
+ yield_cat = "Very Poor Crop"
275
+ color = "red"
276
+
277
+ soil_score = district_soil['SoilHealthScore'].values[0]
278
+ soil_cat = district_soil['Soil_Category'].values[0]
279
+ climate_score = calculate_climate_score(yield_cat, soil_cat)
280
+
281
+ loan_amount = calculate_loan(crop_input, predicted_yield, yield_cat, soil_cat, climate_score)
282
+
283
+ best_crop = None
284
+ max_yield = 0
285
+ for crop, column in base_crop_names.items():
286
+ ts_data = district_yield[['Year', column]].dropna()
287
+ ts_data.columns = ['ds', 'y']
288
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
289
+ if len(ts_data) >= 5:
290
+ model = Prophet(yearly_seasonality=True, growth='flat')
291
+ model.fit(ts_data)
292
+ future = model.make_future_dataframe(periods=1, freq='YS')
293
+ forecast = model.predict(future)
294
+ predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
295
+ if predicted_yield > max_yield:
296
+ max_yield = predicted_yield
297
+ best_crop = crop
298
+
299
+ top_crops = []
300
+ crop_yields = []
301
+ for crop, column in base_crop_names.items():
302
+ ts_data = district_yield[['Year', column]].dropna()
303
+ ts_data.columns = ['ds', 'y']
304
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
305
+ if len(ts_data) >= 5:
306
+ model = Prophet(yearly_seasonality=True, growth='flat')
307
+ model.fit(ts_data)
308
+ future = model.make_future_dataframe(periods=1, freq='YS')
309
+ forecast = model.predict(future)
310
+ predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
311
+ crop_yields.append((crop, predicted_yield))
312
+
313
+ top_crops = sorted(crop_yields, key=lambda x: x[1], reverse=True)[:3]
314
+ top_crops_array = [crop for crop, yield_value in top_crops]
315
+
316
+ ts_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(ts_data['ds'], ts_data['y'])]
317
+ best_crop_data = district_yield[['Year', base_crop_names[best_crop]]].dropna()
318
+ best_crop_data.columns = ['ds', 'y']
319
+ best_crop_data['ds'] = pd.to_datetime(best_crop_data['ds'], format='%Y')
320
+ best_crop_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(best_crop_data['ds'], best_crop_data['y'])]
321
+
322
+ result = {
323
+ "crop": crop_input,
324
+ "district": district_input,
325
+ "predicted_yield": f"{round(predicted_yield, 2)} Kg/ha",
326
+ "yield_category": yield_cat,
327
+ "best_crop": top_crops_array,
328
+ "soil_health": soil_cat,
329
+ "score": climate_score,
330
+ "loan_amount": f"{float(loan_amount)*float(area)}",
331
+ }
332
+ return result
333
+
334
+ @app.get("/api/map")
335
+ async def api_map(crop: str, district: str, land: str):
336
+ if not crop or not district:
337
+ raise HTTPException(status_code=400, detail="Missing crop or district in request.")
338
+ return await map_data(crop, district, land)
339
+
340
+ async def map_data(crop_input: str, district_input: str, area: str):
341
+ if not crop_input or not district_input or crop_input not in base_crop_names:
342
+ raise HTTPException(status_code=400, detail="Invalid input. Please enter a valid crop and district.")
343
+
344
+ yield_col = base_crop_names[crop_input]
345
+ district_yield = yield_df[yield_df['Dist Name'] == district_input]
346
+ district_soil = soil_df[soil_df['Dist Name'] == district_input]
347
+
348
+ if district_yield.empty or district_soil.empty:
349
+ raise HTTPException(status_code=400, detail="District data not found.")
350
+
351
+ ts_data = district_yield[['Year', yield_col]].dropna()
352
+ ts_data.columns = ['ds', 'y']
353
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
354
+
355
+ model = Prophet(yearly_seasonality=True, growth='flat')
356
+ model.fit(ts_data)
357
+
358
+ future = model.make_future_dataframe(periods=1, freq='YS')
359
+ forecast = model.predict(future)
360
+ predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
361
+
362
+ best_crop = None
363
+ max_yield = 0
364
+ for crop, column in base_crop_names.items():
365
+ ts_data = district_yield[['Year', column]].dropna()
366
+ ts_data.columns = ['ds', 'y']
367
+ ts_data['ds'] = pd.to_datetime(ts_data['ds'], format='%Y')
368
+ if len(ts_data) >= 5:
369
+ model = Prophet(yearly_seasonality=True, growth='flat')
370
+ model.fit(ts_data)
371
+ future = model.make_future_dataframe(periods=1, freq='YS')
372
+ forecast = model.predict(future)
373
+ predicted_yield = max(forecast.iloc[-1]['yhat'], 0)
374
+ if predicted_yield > max_yield:
375
+ max_yield = predicted_yield
376
+ best_crop = crop
377
+
378
+ ts_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(ts_data['ds'], ts_data['y'])]
379
+ best_crop_data = district_yield[['Year', base_crop_names[best_crop]]].dropna()
380
+ best_crop_data.columns = ['ds', 'y']
381
+ best_crop_data['ds'] = pd.to_datetime(best_crop_data['ds'], format='%Y')
382
+ best_crop_data_json = [{"Year": str(year.year), "Yield": yield_value} for year, yield_value in zip(best_crop_data['ds'], best_crop_data['y'])]
383
+
384
+ result = {
385
+ "ts_data": ts_data_json,
386
+ "best_crop_data": best_crop_data_json
387
+ }
388
+ return result
389
+
390
+ # To run the application:
391
+ # if __name__ == "__main__":
392
+ # import uvicorn
393
+ # uvicorn.run(app, host="0.0.0.0", port=8000)