File size: 6,159 Bytes
73f907e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
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) |