DavidJyes's picture
Update app.py
fa0092c verified
Raw
History Blame Contribute Delete
3.52 kB
import sys
import pandas as pd
import numpy as np
import joblib
import __main__
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
from pydantic import BaseModel, Field
from sklearn.base import BaseEstimator, TransformerMixin
# --- 1. CLASSE PERSONNALISÉE ---
class DFToHashedTokens(BaseEstimator, TransformerMixin):
def __init__(self, columns=None):
self.columns = columns
def fit(self, X, y=None):
return self
def transform(self, X):
if not isinstance(X, pd.DataFrame):
X = pd.DataFrame(X)
X = X.copy()
cols = getattr(self, 'columns', None)
if cols is not None:
return X[cols].astype(str).values.tolist()
return X.astype(str).values.tolist()
__main__.DFToHashedTokens = DFToHashedTokens
# --- 2. CHARGEMENT DU MODÈLE ---
try:
model = joblib.load('fraud_model_hashing.pkl')
except Exception as e:
model = None
# --- 3. CONFIGURATION API ---
app = FastAPI(title="Fraud Detection API")
class Transaction(BaseModel):
amt: float = Field(..., example=85.20)
trans_date_trans_time: str = Field(..., example="2024-02-18 14:30:00")
dob: str = Field(..., example="1985-05-20")
lat: float = Field(..., example=48.8566)
long: float = Field(..., example=2.3522)
merch_lat: float = Field(..., example=48.8584)
merch_long: float = Field(..., example=2.2945)
city_pop: float = Field(..., example=2000000)
category: str = Field(..., example="shopping_net")
gender: str = Field(..., example="F")
state: str = Field(..., example="NY")
merchant: str = Field(..., example="Amazon")
job: str = Field(..., example="Data Scientist")
cc_num: int = Field(..., example=1234567890123456)
@app.get("/", include_in_schema=False)
def root():
return RedirectResponse(url="/docs")
# --- 4. LOGIQUE DE PRÉPARATION ---
def prepare_input(data: dict):
df = pd.DataFrame([data])
dt = pd.to_datetime(df["trans_date_trans_time"], errors='coerce')
dob = pd.to_datetime(df["dob"], errors='coerce')
if dt.isna().any() or dob.isna().any():
raise ValueError("Format de date invalide.")
df["hour"] = dt.dt.hour
df["day_of_week"] = dt.dt.dayofweek
df["day"] = dt.dt.day
df["month"] = dt.dt.month
df["age"] = ((dt - dob).dt.days / 365.25).astype("float32")
lat1, lon1 = np.radians(df["lat"]), np.radians(df["long"])
lat2, lon2 = np.radians(df["merch_lat"]), np.radians(df["merch_long"])
d = np.sin((lat2-lat1)/2)**2 + np.cos(lat1)*np.cos(lat2)*np.sin((lon2-lon1)/2)**2
df["distance"] = (6371 * 2 * np.arcsin(np.sqrt(d))).astype("float32")
df["avg_amt"] = df["amt"]
df["std_amt"] = 0.0
df["nb_trans"] = 1.0
expected_cols = [
'amt', 'hour', 'day_of_week', 'day', 'month', 'age', 'lat', 'long',
'city_pop', 'distance', 'avg_amt', 'std_amt', 'nb_trans',
'category', 'gender', 'state', 'merchant', 'job'
]
return df[expected_cols]
# --- 5. ENDPOINT NETTOYÉ ---
@app.post("/predict")
def predict(data: Transaction):
if model is None:
return {"error": "Modèle non chargé"}
try:
X_processed = prepare_input(data.dict())
prediction = model.predict(X_processed)
# On ne renvoie que la valeur brute
return int(prediction[0])
except Exception as e:
return {"error": str(e)}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=7860)