corp_and_soil / app.py
Maulidaaa's picture
Update app.py
adc6596 verified
import os
import numpy as np
import pandas as pd
import gradio as gr
from tensorflow.keras.models import load_model
from tensorflow.keras.utils import load_img, img_to_array
from math import radians, cos, sin, sqrt, atan2
import joblib
import requests
# Load model dan data
soil_model = load_model("models/soil-type-mobilenetv2.keras")
crop_model = joblib.load("models/model_random_forest.joblib")
crop_model_label = joblib.load("models/label_encoder.joblib")
soil_df = pd.read_csv("data/soil_data_with_class.csv")
agri_df = pd.read_csv("data/tips_menanam_dan_manfaat_tanaman.csv")
class_labels = ['Black Soil', 'Cinder Soil', 'Laterite Soil', 'Peat Soil', 'Yellow Soil']
OPENWEATHER_API_KEY = os.getenv("OPENWEATHER_API_KEY")
def preprocess_image(img):
img = img.resize((224, 224))
img_array = img_to_array(img) / 255.0
return np.expand_dims(img_array, axis=0)
def predict_soil_type(img):
img_array = preprocess_image(img)
prediction = soil_model.predict(img_array)
predicted_index = np.argmax(prediction)
return class_labels[predicted_index], float(prediction[0][predicted_index])
def find_nearest_soil_data_weighted(soil_type, lat, lon, n_points=1):
filtered = soil_df[soil_df['Class_Name'] == soil_type].copy()
if filtered.empty:
return None
user_lat, user_lon = radians(lat), radians(lon)
def haversine(row):
lat2, lon2 = radians(row['Location_Latitude']), radians(row['Location_Longitude'])
dlat = lat2 - user_lat
dlon = lon2 - user_lon
a = sin(dlat / 2) ** 2 + cos(user_lat) * cos(lat2) * sin(dlon / 2) ** 2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
return 6371 * c
filtered['Distance_km'] = filtered.apply(haversine, axis=1)
nearest = filtered.nsmallest(n_points, 'Distance_km').copy()
row = nearest.iloc[0]
return {
"latitude": float(row['Location_Latitude']),
"longitude": float(row['Location_Longitude']),
"pH": float(row['pH']),
"N": float(row['Nitrogen_N_ppm']),
"P": float(row['Phosphorus_P_ppm']),
"K": float(row['Potassium_K_ppm']),
"distance_km": float(row['Distance_km'])
}
def get_weather_data(lat, lon):
if not OPENWEATHER_API_KEY:
return {"temperature": 0, "humidity": 0}
url = f"https://api.openweathermap.org/data/2.5/weather?lat={lat}&lon={lon}&appid={OPENWEATHER_API_KEY}&units=metric"
res = requests.get(url)
if res.status_code != 200:
return None
data = res.json()
return {
"temperature": float(data['main']['temp']),
"humidity": float(data['main']['humidity']),
}
def get_farming_tips(df, crop_name):
match = df[df['Nama Tanaman'].str.lower() == crop_name.lower()]
if not match.empty:
row = match.iloc[0]
return {
"Nama Tanaman": row['Nama Tanaman'],
"Tips Menanam": row.get('Tips Menanam', 'Tidak tersedia'),
"Manfaat": row.get('Manfaat', 'Tidak tersedia')
}
return {"Nama Tanaman": crop_name, "Tips Menanam": "Tidak tersedia", "Manfaat": "Tidak tersedia"}
def analyze(image, lat, lon):
predicted_soil, soil_accuracy = predict_soil_type(image)
nearest_data = find_nearest_soil_data_weighted(predicted_soil, lat, lon)
if nearest_data is None:
return {"error": "Data tanah tidak ditemukan."}
weather = get_weather_data(lat, lon)
if not weather:
return {"error": "Cuaca tidak tersedia."}
input_data = pd.DataFrame([{
'temperature': weather['temperature'],
'humidity': weather['humidity'],
'ph': nearest_data['pH'],
'N': nearest_data['N'],
'P': nearest_data['P'],
'K': nearest_data['K'],
}])
if hasattr(crop_model, "predict_proba"):
proba = crop_model.predict_proba(input_data)[0]
top_idx = np.argsort(proba)[::-1][:5]
recommended_crops = [
crop_model_label.inverse_transform([crop_model.classes_[i]])[0]
for i in top_idx
]
crop_percentages = [round(float(proba[i]) * 100, 2) for i in top_idx]
else:
pred = crop_model.predict(input_data)[0]
recommended_crops = [crop_model_label.inverse_transform([pred])[0]]
crop_percentages = [100.0]
tips_list = [get_farming_tips(agri_df, crop) for crop in recommended_crops]
return {
"Jenis Tanah": predicted_soil,
"Akurasi Prediksi Tanah (%)": round(soil_accuracy * 100, 2),
"Cuaca": weather,
"Rekomendasi Tanaman": [
{"Tanaman": crop, "Persentase (%)": percent}
for crop, percent in zip(recommended_crops, crop_percentages)
],
"Tips dan Manfaat": tips_list,
"Data Tanah Terdekat": nearest_data
}
iface = gr.Interface(
fn=analyze,
inputs=[
gr.Image(type="pil", label="Gambar Tanah"),
gr.Number(label="Latitude"),
gr.Number(label="Longitude")
],
outputs=gr.JSON(),
title="Soil Type & Crop Recommendation",
)
if __name__ == "__main__":
iface.launch()