third / app.py
twist-turn's picture
Upload 22 files
1c796e1 verified
Raw History Blame Contribute Delete
5.42 kB
import os
import uuid
from datetime import datetime
from flask import Flask, render_template, request, flash, url_for
from models.config import Config
from models.data_loader import DataManager
from models.temporal_forecaster import TemporalForecaster
from models.rotation_optimizer import CropRotationOptimizer
from models.image_generator import CropImageGenerator
def create_app():
app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ.get("FLASK_SECRET_KEY", "dev-secret-key")
app.config["UPLOAD_FOLDER"] = os.path.join("static", "uploads")
app.config["GENERATED_FOLDER"] = os.path.join("static", "generated")
os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)
os.makedirs(app.config["GENERATED_FOLDER"], exist_ok=True)
data_manager = DataManager(Config)
forecaster = TemporalForecaster(Config)
optimizer = CropRotationOptimizer(Config)
image_generator = CropImageGenerator(Config)
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "POST":
try:
region = request.form.get("region") or "Field-001"
crop = request.form.get("crop") or "Maize"
seasons = int(request.form.get("seasons") or 2)
scenario = request.form.get("scenario") or "baseline"
start_date_str = request.form.get("start_date") or datetime.today().strftime("%Y-%m-%d")
start_date = datetime.strptime(start_date_str, "%Y-%m-%d")
rotation_plan_text = (request.form.get("rotation_plan") or "").strip()
rotation_file = request.files.get("rotation_file")
rotation_file_path = None
if rotation_file and rotation_file.filename:
filename = f"{uuid.uuid4().hex}_{rotation_file.filename}"
rotation_file_path = os.path.join(app.config["UPLOAD_FOLDER"], filename)
rotation_file.save(rotation_file_path)
ndvi_data = data_manager.load_ndvi_series(region=region)
weather_forecast = data_manager.load_weather_forecast(region=region)
soil_terrain = data_manager.load_soil_and_terrain(region=region)
commons_data = data_manager.load_ag_commons_metadata()
growth_forecast = forecaster.forecast_growth(
ndvi_data=ndvi_data,
weather=weather_forecast,
soil=soil_terrain,
crop=crop,
start_date=start_date,
seasons=seasons,
scenario=scenario,
)
optimized_rotation, rl_metrics = optimizer.optimize_rotation(
base_plan_text=rotation_plan_text,
uploaded_plan_path=rotation_file_path,
crop=crop,
seasons=seasons,
scenario=scenario,
)
img_filename = f"crop_sim_{uuid.uuid4().hex}.png"
img_path = os.path.join(app.config["GENERATED_FOLDER"], img_filename)
rel_img_path = os.path.join("generated", img_filename)
image_generator.generate_growth_visualization(
ndvi_series=ndvi_data,
forecast=growth_forecast,
rotation_plan=optimized_rotation,
output_path=img_path,
scenario=scenario,
)
metrics = {
"yield_index": growth_forecast.get("yield_index", 0.0),
"stress_risk": growth_forecast.get("stress_risk", 0.0),
"weather_volatility": growth_forecast.get("weather_volatility", 0.0),
"soil_score": growth_forecast.get("soil_score", 0.0),
}
return render_template(
"results.html",
region=region,
crop=crop,
seasons=seasons,
scenario=scenario,
start_date=start_date_str,
metrics=metrics,
rotation_plan=optimized_rotation,
rl_metrics=rl_metrics,
growth_forecast=growth_forecast,
image_path=rel_img_path,
commons_data=commons_data,
)
except Exception as e:
flash(f"Simulation failed: {e}", "danger")
regions = ["Field-001", "Field-002", "Field-Highland", "Field-Lowland"]
crops = ["Maize", "Wheat", "Rice", "Soybean", "Cotton"]
scenarios = [
("baseline", "Baseline"),
("wet_year", "Wet year (↑ rainfall)"),
("dry_year", "Dry year (↓ rainfall)"),
("heatwave", "Heatwave risk"),
("low_inputs", "Low fertilizer / low inputs"),
]
return render_template(
"index.html",
regions=regions,
crops=crops,
scenarios=scenarios,
today=datetime.today().strftime("%Y-%m-%d"),
)
@app.route("/api/health")
def health():
return {"status": "ok", "feature": "future_crop_visualization"}
return app
if __name__ == "__main__":
app = create_app()
app.run(host="0.0.0.0", port=int(os.environ.get("PORT", 5003)), debug=True)