|
from flask import Flask, render_template, request, jsonify
|
|
import requests
|
|
import google.generativeai as genai
|
|
import os
|
|
import json
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
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"}
|
|
|
|
|
|
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", [])
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
|
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
|
|
|
|
except Exception as e:
|
|
print(f"Model {model_name} failed: {e}")
|
|
last_error = e
|
|
continue
|
|
|
|
if not analysis_json:
|
|
|
|
raise Exception("All specified AI models failed to generate a response.") from last_error
|
|
|
|
return jsonify(analysis_json)
|
|
|
|
except Exception as e:
|
|
|
|
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) |