Abrar20's picture
Update app.py
09e56d5 verified
import gradio as gr
# ------------------------------------
# 1. DEFINE THE STVI THRESHOLDS
# ------------------------------------
STVI_THRESHOLDS = {
"N": {
"Very Low": (0.00, 0.09),
"Low": (0.091, 0.18),
"Medium": (0.181, 0.27),
"Optimum": (0.271, 0.36),
"High": (0.361, 0.45),
"Very High": (0.451, 999.999),
},
"P": {
# Olsen method (µg/g)
"Very Low": (0.00, 6.0),
"Low": (6.1, 12.0),
"Medium": (12.1, 18.0),
"Optimum": (18.1, 24.0),
"High": (24.1, 30.0),
"Very High": (30.1, 999.999),
},
"K": {
# meq/100g
"Very Low": (0.00, 0.075),
"Low": (0.076, 0.15),
"Medium": (0.151, 0.225),
"Optimum": (0.226, 0.30),
"High": (0.31, 0.375),
"Very High": (0.376, 999.999),
},
"S": {
# µg/g
"Very Low": (0.00, 9.0),
"Low": (9.1, 18.0),
"Medium": (18.1, 27.0),
"Optimum": (27.1, 36.0),
"High": (36.1, 45.0),
"Very High": (45.1, 999.999),
},
"Zn": {
# µg/g
"Very Low": (0.00, 0.45),
"Low": (0.451, 0.90),
"Medium": (0.91, 1.35),
"Optimum": (1.351, 1.80),
"High": (1.81, 2.25),
"Very High": (2.251, 999.999),
},
"B": {
# µg/g, as per your table
"Very Low": (0.00, 0.15),
"Low": (0.151, 0.30),
"Medium": (0.31, 0.45),
"Optimum": (0.451, 0.60),
"High": (0.61, 0.75),
"Very High": (0.751, 999.999),
},
}
# ------------------------------------
# 2. RECOMMENDED RANGES PER VARIETY/YIELD
aman_rice = {
"N": {
"Optimum": (0, 12),
"Medium": (13, 24),
"Low": (25, 36),
"Very Low": (37, 48),
"High": (0, 0),
"Very High": (0, 0),
},
"P": {
"Optimum": (0, 3),
"Medium": (4, 6),
"Low": (7, 9),
"Very Low": (10, 12),
"High": (0, 0),
"Very High": (0, 0),
},
"K": {
"Optimum": (0, 10),
"Medium": (11, 20),
"Low": (21, 30),
"Very Low": (31, 40),
"High": (0, 0),
"Very High": (0, 0),
},
"S": {
"Optimum": (0, 2),
"Medium": (3, 4),
"Low": (5, 6),
"Very Low": (7, 8),
"High": (0, 0),
"Very High": (0, 0),
},
"Zn": {
"Optimum": (0, 0),
"Medium": (0, 0.5),
"Low": (0.6, 1.0),
"Very Low": (1.1, 1.5),
"High": (0, 0),
"Very High": (0, 0),
},
"B": {
"Optimum": (0, 0),
"Medium": (0, 0.5),
"Low": (0.6, 1.0),
"Very Low": (1.1, 1.5),
"High": (0, 0),
"Very High": (0, 0),
},
}
big_list_5_0 = {
"N": {
"Optimum": (0, 30),
"Medium": (31, 60),
"Low": (61, 90),
"Very Low": (91, 120),
"High": (0, 0),
"Very High": (0, 0),
},
"P": {
"Optimum": (0, 5),
"Medium": (6, 10),
"Low": (11, 15),
"Very Low": (16, 20),
"High": (0, 0),
"Very High": (0, 0),
},
"K": {
"Optimum": (0, 25),
"Medium": (26, 50),
"Low": (51, 75),
"Very Low": (76, 100),
"High": (0, 0),
"Very High": (0, 0),
},
"S": {
"Optimum": (0, 4),
"Medium": (5, 8),
"Low": (9, 12),
"Very Low": (13, 16),
"High": (0, 0),
"Very High": (0, 0),
},
"Zn": {
"Optimum": (0, 0),
"Medium": (0, 0.8),
"Low": (0.9, 1.6),
"Very Low": (1.7, 2.4),
"High": (0, 0),
"Very High": (0, 0),
},
"B": {
"Optimum": (0, 0),
"Medium": (0, 0.8),
"Low": (0.9, 1.6),
"Very Low": (1.7, 2.4),
"High": (0, 0),
"Very High": (0, 0),
},
}
big_list_4_0 = {
"N": {
"Optimum": (0, 24),
"Medium": (25, 48),
"Low": (49, 72),
"Very Low": (73, 96),
"High": (0, 0),
"Very High": (0, 0),
},
"P": {
"Optimum": (0, 4),
"Medium": (5, 8),
"Low": (9, 12),
"Very Low": (13, 16),
"High": (0, 0),
"Very High": (0, 0),
},
"K": {
"Optimum": (0, 20),
"Medium": (21, 40),
"Low": (41, 60),
"Very Low": (61, 80),
"High": (0, 0),
"Very High": (0, 0),
},
"S": {
"Optimum": (0, 3),
"Medium": (4, 6),
"Low": (7, 9),
"Very Low": (10, 12),
"High": (0, 0),
"Very High": (0, 0),
},
"Zn": {
"Optimum": (0, 0),
"Medium": (0, 0.7),
"Low": (0.8, 1.4),
"Very Low": (1.5, 2.1),
"High": (0, 0),
"Very High": (0, 0),
},
"B": {
"Optimum": (0, 0),
"Medium": (0, 0.7),
"Low": (0.8, 1.4),
"Very Low": (1.5, 2.1),
"High": (0, 0),
"Very High": (0, 0),
},
}
big_list_3_0 = {
"N": {
"Optimum": (0, 18),
"Medium": (19, 36),
"Low": (37, 54),
"Very Low": (55, 72),
"High": (0, 0),
"Very High": (0, 0),
},
"P": {
"Optimum": (0, 3),
"Medium": (4, 6),
"Low": (7, 9),
"Very Low": (10, 12),
"High": (0, 0),
"Very High": (0, 0),
},
"K": {
"Optimum": (0, 15),
"Medium": (16, 30),
"Low": (31, 45),
"Very Low": (46, 60),
"High": (0, 0),
"Very High": (0, 0),
},
"S": {
"Optimum": (0, 3),
"Medium": (4, 6),
"Low": (7, 9),
"Very Low": (10, 12),
"High": (0, 0),
"Very High": (0, 0),
},
"Zn": {
"Optimum": (0, 0),
"Medium": (0, 0.6),
"Low": (0.7, 1.2),
"Very Low": (1.3, 1.8),
"High": (0, 0),
"Very High": (0, 0),
},
"B": {
"Optimum": (0, 0),
"Medium": (0, 0.6),
"Low": (0.7, 1.2),
"Very Low": (1.3, 1.8),
"High": (0, 0),
"Very High": (0, 0),
},
}
VARIETY_OPTIONS = {
"Aman Rice": aman_rice,
"BR 11, BR 22, BR 23, BRRI dhan40, BRRI dhan41, BRRI dhan44, BRRI dhan46, BRRI dhan49,\n"
"BRRI dhan51, BRRI dhan52, BRRI dhan53, BRRI dhan54, BRRI dhan56, BRRI dhan62,\n"
"BRRI dhan66, BRRI dhan70, BRRI dhan71, BRRI dhan72, BRRI dhan73, BRRI dhan75\n"
"BRRI dhan76, BRRI dhan78, BRRI dhan79, BRRI dhan80, BRRI hybrid dhan4, BRRI hybrid dhan6\n"
"and Binadhan-4, Binadhan-7, Binadhan-11, Binadhan-12, Binadhan-15, Binadhan-16, Binadhan-17, Binadhan-20": big_list_5_0,
"BR25, BRRI dhan33, BRRI dhan34, BRRI dhan37, BRRI dhan38,\nBRRI dhan39, BRRI dhan56, BRRI dhan57 and Binadhan-12, Binadhan-13": big_list_4_0,
"BR5, Binadhan-9; LIV: Kataribhog, Kalijira, Chinigura etc": big_list_3_0,
}
# ------------------------------------
# 3. FERTILIZER CONVERSIONS
# ------------------------------------
FERTILIZER_CONVERSION = {
"N": {
"product": "Urea",
"ratio": 2.17, # e.g., 1 kg N => ~2.17 kg Urea
},
"P": {
"product": "TSP",
"ratio": 5.0, # e.g., 1 kg P => ~5 kg TSP
},
"K": {
"product": "MoP",
"ratio": 2.0, # e.g., 1 kg K => 2 kg MOP
},
"S": {
"product": "Gypsum",
"ratio": 5.55, # e.g., 1 kg S => ~5.55 kg gypsum
},
"Zn": {
"product": "Zinc sulphate (heptahydrate)",
"ratio": 4.75,
},
"B": {
"product": "Boric acid",
"ratio": 5.88, # e.g., 1 kg B => 5.88 kg boric acid
},
}
def classify_soil_test(nutrient, value):
"""
Determine the STVI class (Very Low, Low, Medium, etc.) for a given nutrient
based on the user-supplied soil test 'value'.
"""
if nutrient not in STVI_THRESHOLDS:
return None
thresholds = STVI_THRESHOLDS[nutrient]
for stvi_class, (lo, hi) in thresholds.items():
if lo <= value <= hi:
return stvi_class
return None
def calculate_F_r(Uf, Ci, Cs, St, Ls):
"""
Fertilizer requirement formula:
F_r = U_f - (C_i / C_s) * (S_t - L_s)
"""
if Cs == 0: # Avoid division by zero
return Uf
return Uf - (Ci / Cs) * (St - Ls) # Corrected variable name to Ls
# ------------------------------------
# 5. MAIN CALCULATION LOGIC
# ------------------------------------
def fertilizer_calculator(
soilN, soilP, soilK, soilS, soilZn, soilB,
variety_choice
):
rec_dict = VARIETY_OPTIONS[variety_choice]
results = []
def process_nutrient(nutrient_name, soil_value):
if soil_value is None:
return None # user left it blank => skip
stvi_class = classify_soil_test(nutrient_name, soil_value)
if stvi_class is None:
return f"{nutrient_name}: Soil test value {soil_value} out of range or no data."
if nutrient_name not in rec_dict:
return f"{nutrient_name}: No recommendation data for {variety_choice}."
if stvi_class not in rec_dict[nutrient_name]:
return f"{nutrient_name}: No recommended range for STVI class '{stvi_class}'."
(range_lo, range_hi) = rec_dict[nutrient_name][stvi_class]
# U_f = the upper limit of that recommended range
Uf = range_hi
Ci = range_hi - range_lo
# The STVI boundaries for that class
(class_lo, class_hi) = STVI_THRESHOLDS[nutrient_name][stvi_class]
Ls = class_lo
Cs = class_hi - class_lo
St = soil_value
# Calculate F_r
Fr = calculate_F_r(Uf, Ci, Cs, St, Ls)
Fr = max(0, Fr) # Ensure no negative
if nutrient_name in FERTILIZER_CONVERSION:
fert_prod = FERTILIZER_CONVERSION[nutrient_name]["product"]
ratio = FERTILIZER_CONVERSION[nutrient_name]["ratio"]
fert_amount = Fr * ratio
return (
f"{nutrient_name} - STVI: {stvi_class} | "
f"Recommended Nutrient = {Fr:.2f} kg/ha | "
f"{fert_prod} needed ≈ {fert_amount:.2f} kg/ha"
)
else:
return (
f"{nutrient_name} - STVI: {stvi_class} | "
f"Recommended Nutrient = {Fr:.2f} kg/ha | "
f"No fertilizer product data."
)
# Process each nutrient in turn
for nname, sval in [
("N", soilN),
("P", soilP),
("K", soilK),
("S", soilS),
("Zn", soilZn),
("B", soilB),
]:
ans = process_nutrient(nname, sval)
if ans:
results.append(ans)
if not results:
return "No valid nutrient inputs given."
return "\n".join(results)
# ------------------------------------
# GRADIO UI
# ------------------------------------
import gradio as gr
import traceback
def on_calculate(soilN, soilP, soilK, soilS, soilZn, soilB, variety_choice):
try:
# Attempt the fertilizer calculation
return fertilizer_calculator(soilN, soilP, soilK, soilS, soilZn, soilB, variety_choice)
except Exception as e:
# Catch any errors and return the stack trace to the UI
error_message = f"An error occurred:\n{traceback.format_exc()}"
print(error_message) # Print to the console for debugging
return error_message # Return to the Gradio output
# Integrate with the Gradio app
with gr.Blocks(title="Fertilizer Calculator 🌾🚜") as demo:
gr.Markdown(
"""
# Fertilizer Calculator 🌾🚜
Enter your soil test values below (leave blank if unknown).
Then select your rice variety to see recommended fertilizer requirements!
"""
)
with gr.Row():
soilN = gr.Number(label="Nitrogen (%)", value=None, precision=4)
soilP = gr.Number(label="Phosphorus (µg/g, Olsen)", value=None, precision=4)
soilK = gr.Number(label="Potassium (meq/100g)", value=None, precision=4)
soilS = gr.Number(label="Sulfur (µg/g)", value=None, precision=4)
soilZn = gr.Number(label="Zinc (µg/g)", value=None, precision=4)
soilB = gr.Number(label="Boron (µg/g)", value=None, precision=4)
variety = gr.Dropdown(
label="Select Rice Variety",
choices=list(VARIETY_OPTIONS.keys()),
value="Aman Rice" # default
)
calc_button = gr.Button("Calculate Fertilizer Requirements ✅")
output_text = gr.Textbox(
label="Results",
lines=12,
placeholder="Your fertilizer recommendation will appear here..."
)
calc_button.click(
fn=on_calculate,
inputs=[soilN, soilP, soilK, soilS, soilZn, soilB, variety],
outputs=output_text
)
demo.launch()