Spaces:
Sleeping
Sleeping
Upload 5 files
Browse files- Dockerfile (1) +26 -0
- app (1).py +141 -0
- microalgae_pot_experiment_corrected_doses (1).xlsx +0 -0
- minmax_scaler (1).pkl +3 -0
- xgb_model_corn_final (1).json +0 -0
Dockerfile (1)
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ✅ Force Python 3.11 to match local environment
|
| 2 |
+
FROM python:3.11-slim
|
| 3 |
+
|
| 4 |
+
WORKDIR /app
|
| 5 |
+
COPY . /app
|
| 6 |
+
|
| 7 |
+
# ✅ Clean upgrade and install lightweight dependencies first
|
| 8 |
+
RUN apt-get update && apt-get install -y gcc g++ && rm -rf /var/lib/apt/lists/*
|
| 9 |
+
|
| 10 |
+
# ✅ Install compatible libraries
|
| 11 |
+
RUN pip install --upgrade pip
|
| 12 |
+
RUN pip install --no-cache-dir \
|
| 13 |
+
gradio==5.49.1 \
|
| 14 |
+
xgboost==2.1.0 \
|
| 15 |
+
scikit-learn==1.7.2 \
|
| 16 |
+
pandas==2.3.3 \
|
| 17 |
+
numpy==2.3.4 \
|
| 18 |
+
joblib==1.4.2 \
|
| 19 |
+
openpyxl==3.1.5 \
|
| 20 |
+
tabulate==0.9.0
|
| 21 |
+
|
| 22 |
+
EXPOSE 7860
|
| 23 |
+
|
| 24 |
+
CMD ["python", "app.py"]
|
| 25 |
+
|
| 26 |
+
|
app (1).py
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import numpy as np
|
| 4 |
+
from xgboost import XGBRegressor
|
| 5 |
+
import joblib
|
| 6 |
+
import os
|
| 7 |
+
import logging
|
| 8 |
+
|
| 9 |
+
# -----------------------------
|
| 10 |
+
# 1️⃣ File paths
|
| 11 |
+
# -----------------------------
|
| 12 |
+
MODEL_PATH = "xgb_model_corn_final.json"
|
| 13 |
+
SCALER_PATH = "minmax_scaler.pkl"
|
| 14 |
+
EXCEL_PATH = "microalgae_pot_experiment_corrected_doses.xlsx"
|
| 15 |
+
|
| 16 |
+
# Check files exist
|
| 17 |
+
for path in [MODEL_PATH, SCALER_PATH, EXCEL_PATH]:
|
| 18 |
+
if not os.path.exists(path):
|
| 19 |
+
raise FileNotFoundError(f"File not found: {path}")
|
| 20 |
+
|
| 21 |
+
# -----------------------------
|
| 22 |
+
# 2️⃣ Load model, scaler, and data
|
| 23 |
+
# -----------------------------
|
| 24 |
+
xgb_model = XGBRegressor()
|
| 25 |
+
xgb_model.load_model(MODEL_PATH)
|
| 26 |
+
scaler = joblib.load(SCALER_PATH)
|
| 27 |
+
df = pd.read_excel(EXCEL_PATH)
|
| 28 |
+
|
| 29 |
+
# Only one strain exists
|
| 30 |
+
strain_names = df['Microalgae_Strain'].unique().tolist()
|
| 31 |
+
single_strain_value = 0 # training used LabelEncoder -> 0
|
| 32 |
+
|
| 33 |
+
# -----------------------------
|
| 34 |
+
# 3️⃣ Prediction function
|
| 35 |
+
# -----------------------------
|
| 36 |
+
def predict_dose(crop, microalgae_strain, soil_n, soil_p, soil_k, soil_ec, soil_moisture,
|
| 37 |
+
chlorophyll, shoot_length, root_length, yield_g, relative_yield,
|
| 38 |
+
actual_dose):
|
| 39 |
+
logs = [] # Capture all debug info
|
| 40 |
+
|
| 41 |
+
# 1️⃣ Validate inputs
|
| 42 |
+
required = [soil_n, soil_p, soil_k, soil_ec, soil_moisture,
|
| 43 |
+
chlorophyll, shoot_length, root_length, yield_g, relative_yield]
|
| 44 |
+
if any(v is None for v in required):
|
| 45 |
+
logs.append("[DEBUG] Missing numeric inputs!")
|
| 46 |
+
return "⚠️ Please fill all numeric input fields.", None, None, "\n".join(logs)
|
| 47 |
+
logs.append("[DEBUG] All inputs received.")
|
| 48 |
+
|
| 49 |
+
# 2️⃣ Encode strain
|
| 50 |
+
strain_encoded = single_strain_value
|
| 51 |
+
logs.append(f"[DEBUG] Using Microalgae_Strain encoded value: {strain_encoded}")
|
| 52 |
+
|
| 53 |
+
# 3️⃣ Create DataFrame
|
| 54 |
+
feature_cols = ['Soil_N_ppm','Soil_P_ppm','Soil_K_ppm','Soil_EC_dS_m',
|
| 55 |
+
'Soil_Moisture_%','Chlorophyll_SPAD','Shoot_Length_cm',
|
| 56 |
+
'Root_Length_cm','Yield_g_per_pot','Relative_Yield_%','Microalgae_Strain']
|
| 57 |
+
X_input_df = pd.DataFrame([[soil_n, soil_p, soil_k, soil_ec, soil_moisture,
|
| 58 |
+
chlorophyll, shoot_length, root_length, yield_g,
|
| 59 |
+
relative_yield, strain_encoded]],
|
| 60 |
+
columns=feature_cols).astype(float)
|
| 61 |
+
logs.append(f"[DEBUG] Input DataFrame:\n{X_input_df}")
|
| 62 |
+
|
| 63 |
+
# 4️⃣ Scale
|
| 64 |
+
X_input_scaled = scaler.transform(X_input_df)
|
| 65 |
+
logs.append(f"[DEBUG] Scaled Input:\n{X_input_scaled}")
|
| 66 |
+
|
| 67 |
+
# 5️⃣ Predict
|
| 68 |
+
predicted_dose = xgb_model.predict(X_input_scaled)[0]
|
| 69 |
+
logs.append(f"[DEBUG] Predicted dose (raw): {predicted_dose}")
|
| 70 |
+
|
| 71 |
+
# 6️⃣ Compute error
|
| 72 |
+
if actual_dose is not None:
|
| 73 |
+
abs_error = abs(predicted_dose - actual_dose)
|
| 74 |
+
logs.append(f"[DEBUG] Actual dose: {actual_dose}")
|
| 75 |
+
logs.append(f"[DEBUG] Absolute Error: {abs_error}")
|
| 76 |
+
return (f"🌱 **Predicted Dose:** {predicted_dose:.2f} g/pot",
|
| 77 |
+
f"📏 **Actual Dose:** {actual_dose:.2f} g/pot",
|
| 78 |
+
f"❌ **Absolute Error:** {abs_error:.2f} g/pot",
|
| 79 |
+
"\n".join(logs))
|
| 80 |
+
else:
|
| 81 |
+
logs.append("[DEBUG] Actual dose not provided.")
|
| 82 |
+
return (f"🌱 **Predicted Dose:** {predicted_dose:.2f} g/pot",
|
| 83 |
+
"📏 Actual Dose: Not provided",
|
| 84 |
+
"❌ Absolute Error: N/A",
|
| 85 |
+
"\n".join(logs))
|
| 86 |
+
|
| 87 |
+
# -----------------------------
|
| 88 |
+
# 4️⃣ Gradio Interface
|
| 89 |
+
# -----------------------------
|
| 90 |
+
with gr.Blocks(
|
| 91 |
+
theme=gr.themes.Soft(primary_hue="green", secondary_hue="lime", neutral_hue="gray"),
|
| 92 |
+
title="EcoGrowAI — Microalgae Dose Inference"
|
| 93 |
+
) as demo:
|
| 94 |
+
gr.Markdown(
|
| 95 |
+
"""
|
| 96 |
+
<div style='text-align:center'>
|
| 97 |
+
<h1 style='color:#00b16a; margin-bottom:8px;'>🌿 EcoGrowAI — Inference App</h1>
|
| 98 |
+
<p style='color:#555;'>Predict the optimal <b>microalgae dose (g/pot)</b> for Corn based on soil and growth parameters.</p>
|
| 99 |
+
</div>
|
| 100 |
+
<hr style='margin: 10px 0;'>
|
| 101 |
+
"""
|
| 102 |
+
)
|
| 103 |
+
with gr.Row():
|
| 104 |
+
with gr.Column(scale=1):
|
| 105 |
+
gr.Markdown("### 🌾 Crop & Microalgae Selection")
|
| 106 |
+
crop = gr.Dropdown(["Corn"], label="Select Crop", value="Corn")
|
| 107 |
+
strain = gr.Dropdown(strain_names, label="Microalgae Strain", value=strain_names[0])
|
| 108 |
+
gr.Markdown("### 🌱 Soil Parameters")
|
| 109 |
+
soil_n = gr.Number(label="Soil N (ppm)")
|
| 110 |
+
soil_p = gr.Number(label="Soil P (ppm)")
|
| 111 |
+
soil_k = gr.Number(label="Soil K (ppm)")
|
| 112 |
+
soil_ec = gr.Number(label="Soil EC (dS/m)")
|
| 113 |
+
soil_moisture = gr.Number(label="Soil Moisture (%)")
|
| 114 |
+
gr.Markdown("### 🌾 Plant Growth Parameters")
|
| 115 |
+
chlorophyll = gr.Number(label="Chlorophyll (SPAD)")
|
| 116 |
+
shoot_length = gr.Number(label="Shoot Length (cm)")
|
| 117 |
+
root_length = gr.Number(label="Root Length (cm)")
|
| 118 |
+
yield_g = gr.Number(label="Yield (g/pot)")
|
| 119 |
+
relative_yield = gr.Number(label="Relative Yield (%)")
|
| 120 |
+
gr.Markdown("### 📏 Actual Dose (optional)")
|
| 121 |
+
actual_dose = gr.Number(label="Actual Dose (g/pot)")
|
| 122 |
+
predict_btn = gr.Button("🔍 Predict Dose", variant="primary")
|
| 123 |
+
with gr.Column(scale=1):
|
| 124 |
+
gr.Markdown("### 📊 Inference Result")
|
| 125 |
+
pred_box = gr.Markdown("Awaiting prediction...")
|
| 126 |
+
actual_box = gr.Markdown("")
|
| 127 |
+
abs_box = gr.Markdown("")
|
| 128 |
+
log_box = gr.Textbox(label="Debug Logs", lines=15) # <-- Add this
|
| 129 |
+
predict_btn.click(
|
| 130 |
+
fn=predict_dose,
|
| 131 |
+
inputs=[crop, strain, soil_n, soil_p, soil_k, soil_ec, soil_moisture,
|
| 132 |
+
chlorophyll, shoot_length, root_length, yield_g, relative_yield,
|
| 133 |
+
actual_dose],
|
| 134 |
+
outputs=[pred_box, actual_box, abs_box, log_box]
|
| 135 |
+
)
|
| 136 |
+
|
| 137 |
+
# -----------------------------
|
| 138 |
+
# 5️⃣ Launch
|
| 139 |
+
# -----------------------------
|
| 140 |
+
if __name__ == "__main__":
|
| 141 |
+
demo.launch(server_name="0.0.0.0", server_port=7860)
|
microalgae_pot_experiment_corrected_doses (1).xlsx
ADDED
|
Binary file (12.1 kB). View file
|
|
|
minmax_scaler (1).pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:fc3eeaadab72cbf85ef6b7653110f9316e48e6fcdeb1fe871f133e2a44ade7b3
|
| 3 |
+
size 1551
|
xgb_model_corn_final (1).json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|