Abrar20 commited on
Commit
69c8022
·
verified ·
1 Parent(s): b148304

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +470 -0
app.py ADDED
@@ -0,0 +1,470 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ # ------------------------------------
4
+ # 1. DEFINE THE STVI THRESHOLDS
5
+ # ------------------------------------
6
+ STVI_THRESHOLDS = {
7
+ "N": {
8
+ "Very Low": (0.00, 0.09),
9
+ "Low": (0.091, 0.18),
10
+ "Medium": (0.181, 0.27),
11
+ "Optimum": (0.271, 0.36),
12
+ "High": (0.361, 0.45),
13
+ "Very High": (0.451, 999.999),
14
+ },
15
+ "P": {
16
+ # Olsen method (µg/g)
17
+ "Very Low": (0.00, 6.0),
18
+ "Low": (6.1, 12.0),
19
+ "Medium": (12.1, 18.0),
20
+ "Optimum": (18.1, 24.0),
21
+ "High": (24.1, 30.0),
22
+ "Very High": (30.1, 999.999),
23
+ },
24
+ "K": {
25
+ # meq/100g
26
+ "Very Low": (0.00, 0.075),
27
+ "Low": (0.076, 0.15),
28
+ "Medium": (0.151, 0.225),
29
+ "Optimum": (0.226, 0.30),
30
+ "High": (0.31, 0.375),
31
+ "Very High": (0.376, 999.999),
32
+ },
33
+ "S": {
34
+ # µg/g
35
+ "Very Low": (0.00, 9.0),
36
+ "Low": (9.1, 18.0),
37
+ "Medium": (18.1, 27.0),
38
+ "Optimum": (27.1, 36.0),
39
+ "High": (36.1, 45.0),
40
+ "Very High": (45.1, 999.999),
41
+ },
42
+ "Zn": {
43
+ # µg/g
44
+ "Very Low": (0.00, 0.45),
45
+ "Low": (0.451, 0.90),
46
+ "Medium": (0.91, 1.35),
47
+ "Optimum": (1.351, 1.80),
48
+ "High": (1.81, 2.25),
49
+ "Very High": (2.251, 999.999),
50
+ },
51
+ "B": {
52
+ # µg/g, as per your table
53
+ "Very Low": (0.00, 0.15),
54
+ "Low": (0.151, 0.30),
55
+ "Medium": (0.31, 0.45),
56
+ "Optimum": (0.451, 0.60),
57
+ "High": (0.61, 0.75),
58
+ "Very High": (0.751, 999.999),
59
+ },
60
+ }
61
+
62
+ # ------------------------------------
63
+ # 2. RECOMMENDED RANGES PER VARIETY/YIELD
64
+
65
+ aman_rice = {
66
+ "N": {
67
+ "Optimum": (0, 12),
68
+ "Medium": (13, 24),
69
+ "Low": (25, 36),
70
+ "Very Low": (37, 48),
71
+ "High": (0, 0),
72
+ "Very High": (0, 0),
73
+ },
74
+ "P": {
75
+ "Optimum": (0, 3),
76
+ "Medium": (4, 6),
77
+ "Low": (7, 9),
78
+ "Very Low": (10, 12),
79
+ "High": (0, 0),
80
+ "Very High": (0, 0),
81
+ },
82
+ "K": {
83
+ "Optimum": (0, 10),
84
+ "Medium": (11, 20),
85
+ "Low": (21, 30),
86
+ "Very Low": (31, 40),
87
+ "High": (0, 0),
88
+ "Very High": (0, 0),
89
+ },
90
+ "S": {
91
+ "Optimum": (0, 2),
92
+ "Medium": (3, 4),
93
+ "Low": (5, 6),
94
+ "Very Low": (7, 8),
95
+ "High": (0, 0),
96
+ "Very High": (0, 0),
97
+ },
98
+ "Zn": {
99
+ "Optimum": (0, 0),
100
+ "Medium": (0, 0.5),
101
+ "Low": (0.6, 1.0),
102
+ "Very Low": (1.1, 1.5),
103
+ "High": (0, 0),
104
+ "Very High": (0, 0),
105
+ },
106
+ "B": {
107
+ "Optimum": (0, 0),
108
+ "Medium": (0, 0.5),
109
+ "Low": (0.6, 1.0),
110
+ "Very Low": (1.1, 1.5),
111
+ "High": (0, 0),
112
+ "Very High": (0, 0),
113
+ },
114
+ }
115
+
116
+ big_list_5_0 = {
117
+ "N": {
118
+ "Optimum": (0, 30),
119
+ "Medium": (31, 60),
120
+ "Low": (61, 90),
121
+ "Very Low": (91, 120),
122
+ "High": (0, 0),
123
+ "Very High": (0, 0),
124
+ },
125
+ "P": {
126
+ "Optimum": (0, 5),
127
+ "Medium": (6, 10),
128
+ "Low": (11, 15),
129
+ "Very Low": (16, 20),
130
+ "High": (0, 0),
131
+ "Very High": (0, 0),
132
+ },
133
+ "K": {
134
+ "Optimum": (0, 25),
135
+ "Medium": (26, 50),
136
+ "Low": (51, 75),
137
+ "Very Low": (76, 100),
138
+ "High": (0, 0),
139
+ "Very High": (0, 0),
140
+ },
141
+ "S": {
142
+ "Optimum": (0, 4),
143
+ "Medium": (5, 8),
144
+ "Low": (9, 12),
145
+ "Very Low": (13, 16),
146
+ "High": (0, 0),
147
+ "Very High": (0, 0),
148
+ },
149
+ "Zn": {
150
+ "Optimum": (0, 0),
151
+ "Medium": (0, 0.8),
152
+ "Low": (0.9, 1.6),
153
+ "Very Low": (1.7, 2.4),
154
+ "High": (0, 0),
155
+ "Very High": (0, 0),
156
+ },
157
+ "B": {
158
+ "Optimum": (0, 0),
159
+ "Medium": (0, 0.8),
160
+ "Low": (0.9, 1.6),
161
+ "Very Low": (1.7, 2.4),
162
+ "High": (0, 0),
163
+ "Very High": (0, 0),
164
+ },
165
+ }
166
+
167
+ big_list_4_0 = {
168
+ "N": {
169
+ "Optimum": (0, 24),
170
+ "Medium": (25, 48),
171
+ "Low": (49, 72),
172
+ "Very Low": (73, 96),
173
+ "High": (0, 0),
174
+ "Very High": (0, 0),
175
+ },
176
+ "P": {
177
+ "Optimum": (0, 4),
178
+ "Medium": (5, 8),
179
+ "Low": (9, 12),
180
+ "Very Low": (13, 16),
181
+ "High": (0, 0),
182
+ "Very High": (0, 0),
183
+ },
184
+ "K": {
185
+ "Optimum": (0, 20),
186
+ "Medium": (21, 40),
187
+ "Low": (41, 60),
188
+ "Very Low": (61, 80),
189
+ "High": (0, 0),
190
+ "Very High": (0, 0),
191
+ },
192
+ "S": {
193
+ "Optimum": (0, 3),
194
+ "Medium": (4, 6),
195
+ "Low": (7, 9),
196
+ "Very Low": (10, 12),
197
+ "High": (0, 0),
198
+ "Very High": (0, 0),
199
+ },
200
+ "Zn": {
201
+ "Optimum": (0, 0),
202
+ "Medium": (0, 0.7),
203
+ "Low": (0.8, 1.4),
204
+ "Very Low": (1.5, 2.1),
205
+ "High": (0, 0),
206
+ "Very High": (0, 0),
207
+ },
208
+ "B": {
209
+ "Optimum": (0, 0),
210
+ "Medium": (0, 0.7),
211
+ "Low": (0.8, 1.4),
212
+ "Very Low": (1.5, 2.1),
213
+ "High": (0, 0),
214
+ "Very High": (0, 0),
215
+ },
216
+ }
217
+
218
+ big_list_3_0 = {
219
+ "N": {
220
+ "Optimum": (0, 18),
221
+ "Medium": (19, 36),
222
+ "Low": (37, 54),
223
+ "Very Low": (55, 72),
224
+ "High": (0, 0),
225
+ "Very High": (0, 0),
226
+ },
227
+ "P": {
228
+ "Optimum": (0, 3),
229
+ "Medium": (4, 6),
230
+ "Low": (7, 9),
231
+ "Very Low": (10, 12),
232
+ "High": (0, 0),
233
+ "Very High": (0, 0),
234
+ },
235
+ "K": {
236
+ "Optimum": (0, 15),
237
+ "Medium": (16, 30),
238
+ "Low": (31, 45),
239
+ "Very Low": (46, 60),
240
+ "High": (0, 0),
241
+ "Very High": (0, 0),
242
+ },
243
+ "S": {
244
+ "Optimum": (0, 3),
245
+ "Medium": (4, 6),
246
+ "Low": (7, 9),
247
+ "Very Low": (10, 12),
248
+ "High": (0, 0),
249
+ "Very High": (0, 0),
250
+ },
251
+ "Zn": {
252
+ "Optimum": (0, 0),
253
+ "Medium": (0, 0.6),
254
+ "Low": (0.7, 1.2),
255
+ "Very Low": (1.3, 1.8),
256
+ "High": (0, 0),
257
+ "Very High": (0, 0),
258
+ },
259
+ "B": {
260
+ "Optimum": (0, 0),
261
+ "Medium": (0, 0.6),
262
+ "Low": (0.7, 1.2),
263
+ "Very Low": (1.3, 1.8),
264
+ "High": (0, 0),
265
+ "Very High": (0, 0),
266
+ },
267
+ }
268
+
269
+ VARIETY_OPTIONS = {
270
+ "Aman Rice": aman_rice,
271
+ "BR 11, BR 22, BR 23, BRRI dhan40, BRRI dhan41, BRRI dhan44, BRRI dhan46, BRRI dhan49,\n"
272
+ "BRRI dhan51, BRRI dhan52, BRRI dhan53, BRRI dhan54, BRRI dhan56, BRRI dhan62,\n"
273
+ "BRRI dhan66, BRRI dhan70, BRRI dhan71, BRRI dhan72, BRRI dhan73, BRRI dhan75\n"
274
+ "BRRI dhan76, BRRI dhan78, BRRI dhan79, BRRI dhan80, BRRI hybrid dhan4, BRRI hybrid dhan6\n"
275
+ "and Binadhan-4, Binadhan-7, Binadhan-11, Binadhan-12, Binadhan-15, Binadhan-16, Binadhan-17, Binadhan-20": big_list_5_0,
276
+ "BR25, BRRI dhan33, BRRI dhan34, BRRI dhan37, BRRI dhan38,\nBRRI dhan39, BRRI dhan56, BRRI dhan57 and Binadhan-12, Binadhan-13": big_list_4_0,
277
+ "BR5, Binadhan-9; LIV: Kataribhog, Kalijira, Chinigura etc": big_list_3_0,
278
+ }
279
+
280
+ # ------------------------------------
281
+ # 3. FERTILIZER CONVERSIONS
282
+ # ------------------------------------
283
+ FERTILIZER_CONVERSION = {
284
+ "N": {
285
+ "product": "Urea",
286
+ "ratio": 2.17, # e.g., 1 kg N => ~2.17 kg Urea
287
+ },
288
+ "P": {
289
+ "product": "TSP",
290
+ "ratio": 5.0, # e.g., 1 kg P => ~5 kg TSP
291
+ },
292
+ "K": {
293
+ "product": "MoP",
294
+ "ratio": 2.0, # e.g., 1 kg K => 2 kg MOP
295
+ },
296
+ "S": {
297
+ "product": "Gypsum",
298
+ "ratio": 5.55, # e.g., 1 kg S => ~5.55 kg gypsum
299
+ },
300
+ "Zn": {
301
+ "product": "Zinc sulphate (heptahydrate)",
302
+ "ratio": 4.75,
303
+ },
304
+ "B": {
305
+ "product": "Boric acid",
306
+ "ratio": 5.88, # e.g., 1 kg B => 5.88 kg boric acid
307
+ },
308
+ }
309
+
310
+
311
+ def classify_soil_test(nutrient, value):
312
+ """
313
+ Determine the STVI class (Very Low, Low, Medium, etc.) for a given nutrient
314
+ based on the user-supplied soil test 'value'.
315
+ """
316
+ if nutrient not in STVI_THRESHOLDS:
317
+ return None
318
+
319
+ thresholds = STVI_THRESHOLDS[nutrient]
320
+ for stvi_class, (lo, hi) in thresholds.items():
321
+ if lo <= value <= hi:
322
+ return stvi_class
323
+ return None
324
+
325
+ def calculate_F_r(Uf, Ci, Cs, St, Ls):
326
+ """
327
+ Fertilizer requirement formula:
328
+ F_r = U_f - (C_i / C_s) * (S_t - L_s)
329
+ """
330
+ if Cs == 0: # Avoid division by zero
331
+ return Uf
332
+ return Uf - (Ci / Cs) * (St - Ls) # Corrected variable name to Ls
333
+
334
+ # ------------------------------------
335
+ # 5. MAIN CALCULATION LOGIC
336
+ # ------------------------------------
337
+ def fertilizer_calculator(
338
+ soilN, soilP, soilK, soilS, soilZn, soilB,
339
+ variety_choice
340
+ ):
341
+ """
342
+ 1) Classify each nutrient's STVI class based on the soil test value.
343
+ 2) Look up recommended range (min, max) from the variety dict.
344
+ 3) Use U_f = max of that recommended range.
345
+ 4) C_i = (U_f - min_of_that_range).
346
+ 5) For the STVI class, find L_s (lower) and C_s (upper-lower).
347
+ 6) F_r = formula result.
348
+ 7) Convert F_r to fertilizer product using FERTILIZER_CONVERSION.
349
+ 8) Return a textual summary.
350
+ """
351
+ rec_dict = VARIETY_OPTIONS[variety_choice]
352
+ results = []
353
+
354
+ def process_nutrient(nutrient_name, soil_value):
355
+ if soil_value is None:
356
+ return None # user left it blank => skip
357
+
358
+ stvi_class = classify_soil_test(nutrient_name, soil_value)
359
+ if stvi_class is None:
360
+ return f"{nutrient_name}: Soil test value {soil_value} out of range or no data."
361
+
362
+ if nutrient_name not in rec_dict:
363
+ return f"{nutrient_name}: No recommendation data for {variety_choice}."
364
+ if stvi_class not in rec_dict[nutrient_name]:
365
+ return f"{nutrient_name}: No recommended range for STVI class '{stvi_class}'."
366
+
367
+ (range_lo, range_hi) = rec_dict[nutrient_name][stvi_class]
368
+ # U_f = the upper limit of that recommended range
369
+ Uf = range_hi
370
+ Ci = range_hi - range_lo
371
+
372
+ # The STVI boundaries for that class
373
+ (class_lo, class_hi) = STVI_THRESHOLDS[nutrient_name][stvi_class]
374
+ Ls = class_lo
375
+ Cs = class_hi - class_lo
376
+ St = soil_value
377
+
378
+ # Calculate F_r
379
+ Fr = calculate_F_r(Uf, Ci, Cs, St, Ls)
380
+ Fr = max(0, Fr) # Ensure no negative
381
+
382
+ if nutrient_name in FERTILIZER_CONVERSION:
383
+ fert_prod = FERTILIZER_CONVERSION[nutrient_name]["product"]
384
+ ratio = FERTILIZER_CONVERSION[nutrient_name]["ratio"]
385
+ fert_amount = Fr * ratio
386
+ return (
387
+ f"{nutrient_name} - STVI: {stvi_class} | "
388
+ f"Recommended Nutrient = {Fr:.2f} kg/ha | "
389
+ f"{fert_prod} needed ≈ {fert_amount:.2f} kg/ha"
390
+ )
391
+ else:
392
+ return (
393
+ f"{nutrient_name} - STVI: {stvi_class} | "
394
+ f"Recommended Nutrient = {Fr:.2f} kg/ha | "
395
+ f"No fertilizer product data."
396
+ )
397
+
398
+ # Process each nutrient in turn
399
+ for nname, sval in [
400
+ ("N", soilN),
401
+ ("P", soilP),
402
+ ("K", soilK),
403
+ ("S", soilS),
404
+ ("Zn", soilZn),
405
+ ("B", soilB),
406
+ ]:
407
+ ans = process_nutrient(nname, sval)
408
+ if ans:
409
+ results.append(ans)
410
+
411
+ if not results:
412
+ return "No valid nutrient inputs given."
413
+ return "\n".join(results)
414
+
415
+ # ------------------------------------
416
+ # GRADIO UI
417
+ # ------------------------------------
418
+ import gradio as gr
419
+ import traceback
420
+
421
+
422
+ def on_calculate(soilN, soilP, soilK, soilS, soilZn, soilB, variety_choice):
423
+ try:
424
+ # Attempt the fertilizer calculation
425
+ return fertilizer_calculator(soilN, soilP, soilK, soilS, soilZn, soilB, variety_choice)
426
+ except Exception as e:
427
+ # Catch any errors and return the stack trace to the UI
428
+ error_message = f"An error occurred:\n{traceback.format_exc()}"
429
+ print(error_message) # Print to the console for debugging
430
+ return error_message # Return to the Gradio output
431
+
432
+ # Integrate with the Gradio app
433
+ with gr.Blocks(title="Fertilizer Calculator 🌾🚜") as demo:
434
+ gr.Markdown(
435
+ """
436
+ # Fertilizer Calculator 🌾🚜
437
+ Enter your soil test values below (leave blank if unknown).
438
+ Then select your rice variety (and yield goal) to see recommended fertilizer requirements!
439
+ """
440
+ )
441
+
442
+ with gr.Row():
443
+ soilN = gr.Number(label="Nitrogen (%)", value=None, precision=4)
444
+ soilP = gr.Number(label="Phosphorus (µg/g, Olsen)", value=None, precision=4)
445
+ soilK = gr.Number(label="Potassium (meq/100g)", value=None, precision=4)
446
+ soilS = gr.Number(label="Sulfur (µg/g)", value=None, precision=4)
447
+ soilZn = gr.Number(label="Zinc (µg/g)", value=None, precision=4)
448
+ soilB = gr.Number(label="Boron (µg/g)", value=None, precision=4)
449
+
450
+ variety = gr.Dropdown(
451
+ label="Select Rice Variety / Yield Goal",
452
+ choices=list(VARIETY_OPTIONS.keys()),
453
+ value="Aman Rice" # default
454
+ )
455
+
456
+ calc_button = gr.Button("Calculate Fertilizer Requirements ✅")
457
+ output_text = gr.Textbox(
458
+ label="Results",
459
+ lines=12,
460
+ placeholder="Your fertilizer recommendation will appear here..."
461
+ )
462
+
463
+ calc_button.click(
464
+ fn=on_calculate,
465
+ inputs=[soilN, soilP, soilK, soilS, soilZn, soilB, variety],
466
+ outputs=output_text
467
+ )
468
+
469
+ demo.launch()
470
+