""" 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