from flask import Flask, render_template, request, jsonify import requests import google.generativeai as genai import os import json app = Flask(__name__) # Mapping of SoilGrids parameter codes PARAM_MAP = { "bdod": "Bulk Density", "cec": "Cation Exchange Capacity", "cfvo": "Coarse Fragment Volume", "clay": "Clay Content", "nitrogen": "Nitrogen Content", "ocd": "Organic Carbon Density", "ocs": "Organic Carbon Stock", "phh2o": "Soil pH", "sand": "Sand Content", "silt": "Silt Content", "soc": "Soil Organic Carbon", "wv0010": "Water Content (0-10cm)", "wv0033": "Water Content (0-33cm)", "wv1500": "Water Content (1500mm)" } @app.route('/') def index(): return render_template('index.html') @app.route('/get_soil_report', methods=['POST']) def get_soil_report(): data = request.get_json() lat, lon = data.get("lat"), data.get("lon") if not lat or not lon: return jsonify({"error": "Latitude and Longitude are required"}), 400 headers = {"accept": "application/json"} # Fetch Soil Classification try: class_response = requests.get( "https://rest.isric.org/soilgrids/v2.0/classification/query", params={"lon": lon, "lat": lat, "number_classes": 5}, headers=headers, timeout=15 ) class_response.raise_for_status() class_data = class_response.json() except requests.exceptions.RequestException as e: return jsonify({"error": f"Failed to fetch soil classification: {e}"}), 500 soil_classification = { "soil_type": class_data.get("wrb_class_name", "Unknown"), "probabilities": class_data.get("wrb_class_probability", []) } # Fetch Soil Properties try: prop_response = requests.get( "https://rest.isric.org/soilgrids/v2.0/properties/query", params={ "lon": lon, "lat": lat, "property": list(PARAM_MAP.keys()), "depth": "5-15cm", "value": "mean" }, headers=headers, timeout=15 ) prop_response.raise_for_status() prop_data = prop_response.json() except requests.exceptions.RequestException as e: return jsonify({"error": f"Failed to fetch soil properties: {e}"}), 500 properties_list = [] layers = prop_data.get("properties", {}).get("layers", []) for layer in layers: param_code = layer.get("name") name = PARAM_MAP.get(param_code, param_code.upper()) depth_info = layer.get("depths", [{}])[0] value = depth_info.get("values", {}).get("mean") unit = layer.get("unit_measure", {}).get("mapped_units", "") if value is not None: if param_code == "phh2o": value /= 10.0 unit = "pH" elif param_code in ["wv0010", "wv0033", "wv1500"]: value /= 100.0 unit = "cm³/cm³" properties_list.append({"parameter": name, "value": value, "unit": unit}) return jsonify({"classification": soil_classification, "properties": properties_list}) @app.route('/analyze_soil', methods=['POST']) def analyze_soil(): api_key = os.getenv("GEMINI_API") if not api_key: error_msg = "API key not configured. The server administrator must set the GEMINI_API environment variable." return jsonify({"error": error_msg}), 500 data = request.get_json() soil_report = data.get("soil_report") language = data.get("language", "English") if not soil_report: return jsonify({"error": "Soil report data is missing"}), 400 prompt = f""" Analyze the following soil report and provide recommendations. The response MUST be a single, valid JSON object, without any markdown formatting or surrounding text. The user wants the analysis in this language: {language}. Soil Report Data: {json.dumps(soil_report, indent=2)} JSON Structure to follow: {{ "soilType": "The primary soil type from the report", "generalInsights": ["Insight 1", "Insight 2", "Insight 3"], "parameters": [{{"parameter": "Parameter Name", "value": "Value with Unit", "range": "Low/Normal/High", "comment": "Brief comment."}}], "cropRecommendations": [{{"crop": "Crop Name", "reason": "Brief reason."}}], "managementRecommendations": {{"fertilization": "Recommendation.", "irrigation": "Recommendation."}} }} """ try: genai.configure(api_key=api_key) # --- NEW: Fallback Logic Implementation --- models_to_try = ['gemini-2.5-flash', 'gemini-2.0-flash', 'gemini-1.5-flash'] analysis_json = None last_error = None for model_name in models_to_try: try: print(f"Attempting to use model: {model_name}") model = genai.GenerativeModel(model_name) response = model.generate_content(prompt) cleaned_response = response.text.strip().replace("```json", "").replace("```", "") analysis_json = json.loads(cleaned_response) print(f"Successfully generated content with {model_name}") break # Exit the loop on success except Exception as e: print(f"Model {model_name} failed: {e}") last_error = e continue # Try the next model in the list if not analysis_json: # This block is reached only if all models in the loop failed. raise Exception("All specified AI models failed to generate a response.") from last_error return jsonify(analysis_json) except Exception as e: # This catches the final error if all models fail, or any other setup error. print(f"Error during Gemini API processing: {e}") return jsonify({"error": f"Failed to get analysis from AI models: {e}"}), 500 if __name__ == '__main__': app.run(debug=True, port=7860)