File size: 6,090 Bytes
e07612a 49d61d9 e07612a 3c73a45 d2a9e4c e07612a 3c73a45 e07612a 252515f e07612a bb3f74f 71c1dfa bb3f74f 49d61d9 bb3f74f e07612a bb3f74f 0bd26fe e07612a 71c1dfa e07612a 71c1dfa e07612a 71c1dfa 96c4c27 2de7a63 e07612a 3c73a45 e07612a 71c1dfa e07612a 71c1dfa e07612a 71c1dfa e07612a 49d61d9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | from fastapi import FastAPI, HTTPException
from fastapi import BackgroundTasks
from pydantic import BaseModel
from typing import Literal
import pandas as pd
import boto3
import joblib
import os
import io
# === Initialisation FastAPI ===
app = FastAPI(
title="Fraude Détection API",
description="""
### 🎯 Description
Cette API permet de détecter automatiquement les transactions potentiellement frauduleuses en se basant sur un modèle de machine learning entraîné avec des données historiques de paiements.
Elle reçoit en entrée les caractéristiques complètes d’une transaction bancaire (hors identifiants techniques comme Unnamed: 0 et trans_num), puis renvoie une prédiction :
1 → transaction frauduleuse
0 → transaction légitime
Le modèle est chargé dynamiquement depuis le registre de modèles MLflow (ou S3), garantissant une traçabilité complète et une mise à jour continue.
🧾 Champs d’entrée attendus (JSON)
Champ Type Description
cc_num float Numéro de carte anonymisé
merchant string Nom du commerçant ou de l’établissement
category string Catégorie du commerçant (ex : "gas_transport", "shopping_net", "travel")
amt float Montant de la transaction
first string Prénom du client
last string Nom du client
gender string Sexe du client ("M" ou "F")
street string Adresse postale du client
city string Ville du client
state string Code État ou Région (ex : "TX", "CA")
zip int Code postal
lat float Latitude du domicile
long float Longitude du domicile
city_pop int Population de la ville
job string Profession du client
merch_lat float Latitude du commerçant
merch_long float Longitude du commerçant
year int Année de la transaction
month int Mois de la transaction
day int Jour de la transaction
hour int Heure de la transaction
minute int Minute de la transaction
second int Seconde de la transaction
dob_year : int année de naissance
dob_month : int mois de naissance
dob_day : int jour de naissance
Voici un exemple :
{
"cc_num": 3593118134380341,
"merchant": "fraud_Jacobi and Sons",
"category": "shopping_pos",
"amt": 9.01,
"first": "Laura",
"last": "Casey",
"gender": "F",
"street": "6114 Moran Way",
"city": "Steuben",
"state": "WI",
"zip": 54657,
"lat": 43.1457,
"long": -91.1021,
"city_pop": 291,
"job": "Scientist, clinical (histocompatibility and immunogenetics)",
"merch_lat": 43.1503,
"merch_long": -91.0976,
"year": 2025,
"month": 11,
"day": 22,
"hour": 10,
"minute": 29,
"second": 6,
"dob_year": 1959,
"dob_month": 5,
"dob_day": 10
}
""",
version="1.0"
)
# === Schéma attendu pour l'entrée ===
class InputData(BaseModel):
cc_num: int
merchant: str
category: str
amt: float
first: str
last: str
gender: Literal["M", "F"]
street: str
city: str
state: str
zip: int
lat: float
long: float
city_pop: int
job: str
merch_lat: float
merch_long: float
year : int
month : int
day : int
hour : int
minute : int
second : int
dob_year : int
dob_month : int
dob_day : int
# === Configuration S3 ===
S3_BUCKET = os.getenv("S3_BUCKET")
S3_PREFIX = "mlflow/models/"
s3 = boto3.client("s3")
def get_latest_model_key():
try:
response = s3.list_objects_v2(
Bucket=S3_BUCKET,
Prefix=S3_PREFIX
)
if "Contents" not in response:
raise ValueError("Aucun modèle trouvé dans le bucket S3.")
# Filtrer uniquement les .joblib
models = [
obj for obj in response["Contents"]
if obj["Key"].endswith(".joblib")
]
if not models:
raise ValueError("Aucun fichier .joblib trouvé.")
# Trier par LastModified (date d'upload dans S3)
models.sort(key=lambda x: x["LastModified"], reverse=True)
latest_key = models[0]["Key"]
print(f"Dernier modèle détecté : {latest_key}")
return latest_key
except Exception as e:
raise RuntimeError(f"Erreur récupération modèle S3 : {e}")
def load_latest_model():
global model
latest_model_key = get_latest_model_key()
print(f"Rechargement du modèle : {latest_model_key}")
response = s3.get_object(Bucket=S3_BUCKET, Key=latest_model_key)
model_bytes = io.BytesIO(response["Body"].read())
model = joblib.load(model_bytes)
print("Nouveau modèle chargé avec succès")
return latest_model_key
@app.on_event("startup")
def load_model():
global model
try:
latest_model_key = get_latest_model_key()
print(f"Téléchargement du dernier modèle depuis s3://{S3_BUCKET}/{latest_model_key}")
# print(f"Téléchargement du modèle depuis s3://{S3_BUCKET}/{MODEL_KEY}")
response = s3.get_object(Bucket=S3_BUCKET, Key=latest_model_key)
model_bytes = io.BytesIO(response["Body"].read())
model = joblib.load(model_bytes)
print("Modèle chargé avec succès")
except Exception as e:
print(f"Erreur chargement modèle : {e}")
raise RuntimeError(f"Impossible de charger le modèle : {e}")
# === Routes ===
@app.get("/")
def home():
return {"message": "Bienvenue sur l'API Fraude détéction - Utilisez /predict pour faire une prédiction"}
@app.post("/predict")
def predict(data: InputData):
try:
df = pd.DataFrame([data.dict()])
print("Données reçues :", df.head(1).to_dict())
prediction = model.predict(df)
is_fraud = int(prediction[0])
return {"is_fraud": is_fraud}
except Exception as e:
print(f"Erreur prédiction : {e}")
raise HTTPException(status_code=500, detail=str(e))
@app.post("/reload-model")
def reload_model(background_tasks: BackgroundTasks):
"""
Recharge le dernier modèle S3 sans redémarrer l'API.
"""
background_tasks.add_task(load_latest_model)
latest_key = get_latest_model_key()
return {"status - Rechargement en arrière-plan modèle :", latest_key}
|