tchamfi/pollution-api
0
1import openai2import os3import pandas as pd4from fastapi import FastAPI, Query, HTTPException5import joblib6 7# Charger le modèle et les données8 9# Utiliser le bon chemin relatif pour les fichiers10BASE_DIR = os.path.dirname(os.path.abspath(__file__))11MODEL_PATH = os.path.join(BASE_DIR, "pollution_model.pkl")12CSV_PATH = os.path.join(BASE_DIR, "pollution_cleaned.csv")13df = pd.read_csv(CSV_PATH)14model = joblib.load(MODEL_PATH)15 16# Définir les features utilisées pour la prédiction (sans 'Date' et 'City')17features = ['temperature_median', 'humidity_median', 'pressure_median', 18 'dew_median', 'wind-gust_median', 'wind-speed_median', 'pp_feat']19 20app = FastAPI()21 22@app.get("/chatbot")23def chatbot_response(city: str = Query(..., description="Ville à analyser"), 24 date: str = Query(..., description="Date de prédiction au format YYYY-MM-DD"),25 question: str = Query(..., description="Question sur la pollution")):26 """27 Chatbot IA qui répond aux questions sur la pollution avec un modèle prédictif.28 """29 30 # Vérifier si la ville existe dans les données31 city_data = df[df["City"].str.lower() == city.lower()]32 33 if city_data.empty:34 raise HTTPException(status_code=404, detail=f"Désolé, je n'ai pas de données pour {city}.")35 36 # Vérifier que les features sont bien des colonnes numériques37 numeric_features = city_data[features].select_dtypes(include=['number'])38 39 if numeric_features.empty:40 raise HTTPException(status_code=400, detail="Aucune donnée numérique disponible pour faire la prédiction.")41 42 # Vérifier si le modèle contient bien les noms des features43 expected_features = model.get_booster().feature_names44 if expected_features is None:45 expected_features = [f"f{i}" for i in range(model.get_booster().num_features())] # Génère des noms par défaut46 print("⚠️ Attention : Le modèle ne contient pas de noms de features. Utilisation de noms générés.")47 48 input_features = list(numeric_features.columns)49 50 # Vérifier les différences entre features attendues et réelles51 missing_features = set(expected_features) - set(input_features)52 extra_features = set(input_features) - set(expected_features)53 54 print("🚨 Features attendues mais manquantes :", missing_features)55 print("🔹 Features en trop :", extra_features)56 57 # Réordonner et compléter les features manquantes avec 058 numeric_features = numeric_features.reindex(columns=expected_features, fill_value=0)59 60 # ✅ Assurer qu'on a bien une seule ligne (évite l'erreur de shape mismatch)61 input_data = numeric_features.mean().values.reshape(1, -1)62 63 # Vérifier la forme finale64 print("📊 Shape de input_data après correction :", input_data.shape) # Devrait être (1, 53)65 66 # Prédiction67 predicted_pm25 = float(model.predict(input_data)[0])68 69 # ✅ prompt GPT-4 engageant et structuré70 context = (71 "🌍 **Bienvenue !** Tu es un expert en qualité de l’air et en recommandations sanitaires. "72 "Ton objectif est d’aider l’utilisateur à comprendre les niveaux de pollution et à adapter ses activités en conséquence. "73 "Utilise un ton **clair, pédagogique et engageant**.\n\n"74 75 "💨 **Comprendre le PM2.5** : Ces particules fines peuvent affecter la santé, surtout chez les personnes vulnérables. "76 "Voici l’échelle officielle de la qualité de l’air :\n\n"77 78 "🌿 **PM2.5 < 50** : 🟢 **Excellente qualité de l'air !** Profitez de votre journée sans restriction. 😃\n"79 "🌤 **50 ≤ PM2.5 < 100** : 🟡 **Qualité de l'air correcte.** Aucune gêne pour la plupart des gens, mais les personnes sensibles doivent éviter les efforts prolongés.\n"80 "😷 **100 ≤ PM2.5 < 150** : 🟠 **Attention aux personnes sensibles !** Réduisez l’activité en extérieur si vous êtes asthmatique ou allergique.\n"81 "🚨 **150 ≤ PM2.5 < 200** : 🔴 **Pollution élevée !** Limitez les sorties et évitez le sport en extérieur.\n"82 "⚠️ **PM2.5 ≥ 200** : 🟣 **Alerte pollution !** Il est recommandé de rester à l’intérieur et de porter un masque FFP2 en cas de sortie.\n\n"83 84 "🔹 **Ton rôle** : Fournis une réponse détaillée et adaptée en fonction du niveau de pollution. "85 "Si la pollution est faible, encourage l’utilisateur à profiter de l’extérieur. "86 "Si elle est élevée, conseille des alternatives (masques, air purifié, etc.).\n\n"87 88 "📌 **Situation actuelle :**"89 )90 91 # ✅ Amélioration de l'appel GPT-4 pour des réponses plus développées92 api = openai.OpenAI(api_key="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")93 94 response = api.chat.completions.create(95 model="gpt-4",96 messages=[97 {"role": "system", "content": context},98 {"role": "user", "content": f"🌍 Ville : {city}\n📅 Date : {date}\n💨 Niveau de pollution PM2.5 prévu : {predicted_pm25:.2f}\n\n{question}"}99 ],100 temperature=0.7, # 🔹 Réponses plus variées et naturelles101 max_tokens=200, # 🔹 Réponses plus détaillées102 top_p=0.9 # 🔹 Plus de diversité dans la réponse103 )104 105 # ✅ Ajout d'une mise en forme plus agréable à lire106 gpt_response = response.choices[0].message.content107 108 formatted_response = f"""109🌍 Ville : {city} 110📅 Date : {date} 111💨 Niveau de pollution PM2.5 prévu : {predicted_pm25:.2f} 112 113🗣 Réponse de l'expert pollution : 114 115{gpt_response} 116"""117 118 return {119 "city": city,120 "date": date,121 "predicted_pm25": predicted_pm25,122 "response": formatted_response123 }124 