agritech-api / src /api /services.py
github-actions
Deploy API from GitHub Actions
42dfbed
Raw
History Blame Contribute Delete
4.08 kB
"""
Ce module contient les fonctions de service pour la prédiction de rendement et la recommandation de cultures.
- predict_yield: Prédit la production de la culture en fonction des données d'entrée.
- recommend: Recommande les meilleures cultures à planter en fonction des conditions d'entrée.
"""
from src.recommendations.recommender import recommend_best_crop
import pandas as pd
import numpy as np
def predict_yield(model, input_data: dict, crops_by_area: dict):
"""
Prédit le rendement d'une culture en fonction des données d'entrée.
Si la zone ou la culture spécifiée dans les données d'entrée n'est pas présente dans crops_by_area, une exception ValueError est levée avec un message d'erreur approprié.
args:
- model: Le modèle de prédiction pré-entraîné.
- input_data: Un dictionnaire contenant les données d'entrée pour la prédiction.
- crops_by_area: Un dictionnaire contenant les cultures disponibles par zone.
returns:
- float: La prédiction du rendement de la culture.
"""
# =========================
# Validation métier
# =========================
area = input_data.get("area")
crop = input_data.get("item")
if area is None:
raise ValueError("Le champ 'area' est requis")
if crop is None:
raise ValueError("Le champ 'item' est requis")
all_areas = {
area_
for areas in crops_by_area.values()
for area_ in areas
}
if area not in all_areas:
raise ValueError(f"Pays inconnu ou non présent dans les données : {area}")
if crop not in crops_by_area:
raise ValueError(f"Culture inconnue : {crop}")
if area not in crops_by_area[crop]:
raise ValueError(
f"La culture '{crop}' n'est pas observée dans le pays '{area}'"
)
# =========================
# Préparation des données
# =========================
df = pd.DataFrame([input_data])
df["temp_rainfall"] = df["temp"] * df["rainfall_mm"]
df["temp_pesticides"] = df["temp"] * df["pesticides"]
df["rainfall_pesticides"] = df["rainfall_mm"] * df["pesticides"]
# =========================
# Prédiction
# =========================
pred_log = model.predict(df)[0]
pred_real = float(np.expm1(pred_log))
return pred_real
def recommend(model, input_data, crops_by_area):
"""
Recommande les meilleures cultures à planter en fonction des conditions d'entrée.
Si la zone spécifiée dans les données d'entrée n'est pas présente dans crops_by_area, une exception ValueError est levée avec un message d'erreur approprié.
args:
- model: Le modèle de recommandation pré-entraîné
- input_data: Un dictionnaire contenant les données d'entrée pour la recommandation
- crops_by_area: Un dictionnaire contenant les cultures disponibles par zone
returns:
- tuple: Un tuple contenant le meilleur choix de culture et le classement des cultures
"""
if input_data["area"] not in {
area for areas in crops_by_area.values() for area in areas
}:
raise ValueError(f"Pays inconnu ou non présent dans les données : {input_data['area']}")
best_crop, ranking_df = recommend_best_crop(
model=model,
input_conditions=input_data,
crops_by_area=crops_by_area,
top_k=5
)
# Conversion en types Python natifs pour FastAPI / JSON
best_crop_dict = {
key: (
float(value) if isinstance(value, (np.float32, np.float64)) else
int(value) if isinstance(value, (np.int32, np.int64)) else
value
)
for key, value in best_crop.to_dict().items()
}
ranking = ranking_df.to_dict(orient="records")
for row in ranking:
for key, value in row.items():
if isinstance(value, (np.float32, np.float64)):
row[key] = float(value)
elif isinstance(value, (np.int32, np.int64)):
row[key] = int(value)
return best_crop_dict, ranking