DavidJyes commited on
Commit
ca1611c
·
verified ·
1 Parent(s): 4751b0f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +53 -16
app.py CHANGED
@@ -4,19 +4,41 @@ import joblib
4
  import pandas as pd
5
  import numpy as np
6
  from pydantic import BaseModel
 
7
 
8
- # 1. Configuration de l'API
9
- app = FastAPI(title="Fraud Detection API")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
- # 2. Chargement du modèle (assure-toi que le nom correspond)
12
- model = joblib.load('fraud_model_hashing.pkl')
 
 
 
 
 
 
 
 
13
 
14
- # 3. Redirection automatique vers /docs
15
  @app.get("/", include_in_schema=False)
16
  def root():
17
  return RedirectResponse(url="/docs")
18
 
19
- # 4. Schéma des données d'entrée
20
  class Transaction(BaseModel):
21
  amt: float
22
  trans_date_trans_time: str
@@ -33,36 +55,51 @@ class Transaction(BaseModel):
33
  job: str
34
  cc_num: int
35
 
36
- # 5. Ta fonction de préparation (adaptée pour une seule ligne)
37
  def prepare_input(data: dict):
38
  df = pd.DataFrame([data])
39
- # Calculs rapides (similaires à ton make_features)
 
40
  dt = pd.to_datetime(df["trans_date_trans_time"])
41
- df["hour"], df["day_of_week"] = dt.dt.hour, dt.dt.dayofweek
42
- df["day"], df["month"] = dt.dt.day, dt.dt.month
 
 
43
 
 
44
  dob = pd.to_datetime(df["dob"])
45
  df["age"] = ((dt - dob).dt.days / 365.25).astype("float32")
46
 
47
- # Distance Haversine
48
  lat1, lon1 = np.radians(df["lat"]), np.radians(df["long"])
49
  lat2, lon2 = np.radians(df["merch_lat"]), np.radians(df["merch_long"])
50
  d = np.sin((lat2-lat1)/2)**2 + np.cos(lat1)*np.cos(lat2)*np.sin((lon2-lon1)/2)**2
51
  df["distance"] = (6371 * 2 * np.arcsin(np.sqrt(d))).astype("float32")
52
 
53
- # Valeurs par défaut pour les agrégats (car une API reçoit souvent 1 seule transaction)
54
- df["avg_amt"] = df["amt"]
55
  df["std_amt"] = 0.0
56
  df["nb_trans"] = 1.0
57
 
 
58
  cols = ['amt', 'hour', 'day_of_week', 'day', 'month', 'age', 'lat', 'long',
59
  'city_pop', 'distance', 'avg_amt', 'std_amt', 'nb_trans',
60
  'category', 'gender', 'state', 'merchant', 'job']
61
  return df[cols]
62
 
 
63
  @app.post("/predict")
64
  def predict(data: Transaction):
65
- X = prepare_input(data.dict())
66
- prediction = model.predict(X)
67
- return {"is_fraud": int(prediction[0])}
 
 
 
 
 
 
68
 
 
 
 
 
4
  import pandas as pd
5
  import numpy as np
6
  from pydantic import BaseModel
7
+ from sklearn.base import BaseEstimator, TransformerMixin
8
 
9
+ # --- 1. DEFINITION DES CLASSES PERSONNALISÉES (CRUCIAL) ---
10
+ # Cette classe doit être définie AVANT le chargement du modèle pour que joblib la reconnaisse
11
+ class DFToHashedTokens(BaseEstimator, TransformerMixin):
12
+ def __init__(self, columns=None):
13
+ self.columns = columns
14
+
15
+ def fit(self, X, y=None):
16
+ return self
17
+
18
+ def transform(self, X):
19
+ X = X.copy()
20
+ # Ici, remets la logique exacte que tu avais dans ton notebook
21
+ # Par exemple, si tu transformais des colonnes en chaînes de caractères :
22
+ for col in self.columns:
23
+ X[col] = X[col].astype(str)
24
+ return X
25
 
26
+ # --- 2. CHARGEMENT DU MODÈLE ---
27
+ # Maintenant que la classe est définie, joblib ne plantera plus
28
+ try:
29
+ model = joblib.load('fraud_model_hashing.pkl')
30
+ print("✅ Modèle chargé avec succès")
31
+ except Exception as e:
32
+ print(f"❌ Erreur lors du chargement du modèle : {e}")
33
+
34
+ # --- 3. CONFIGURATION API ---
35
+ app = FastAPI(title="Fraud Detection API")
36
 
 
37
  @app.get("/", include_in_schema=False)
38
  def root():
39
  return RedirectResponse(url="/docs")
40
 
41
+ # --- 4. SCHÉMA DES DONNÉES ---
42
  class Transaction(BaseModel):
43
  amt: float
44
  trans_date_trans_time: str
 
55
  job: str
56
  cc_num: int
57
 
58
+ # --- 5. LOGIQUE DE PRÉPARATION ---
59
  def prepare_input(data: dict):
60
  df = pd.DataFrame([data])
61
+
62
+ # Dates
63
  dt = pd.to_datetime(df["trans_date_trans_time"])
64
+ df["hour"] = dt.dt.hour
65
+ df["day_of_week"] = dt.dt.dayofweek
66
+ df["day"] = dt.dt.day
67
+ df["month"] = dt.dt.month
68
 
69
+ # Âge
70
  dob = pd.to_datetime(df["dob"])
71
  df["age"] = ((dt - dob).dt.days / 365.25).astype("float32")
72
 
73
+ # Distance
74
  lat1, lon1 = np.radians(df["lat"]), np.radians(df["long"])
75
  lat2, lon2 = np.radians(df["merch_lat"]), np.radians(df["merch_long"])
76
  d = np.sin((lat2-lat1)/2)**2 + np.cos(lat1)*np.cos(lat2)*np.sin((lon2-lon1)/2)**2
77
  df["distance"] = (6371 * 2 * np.arcsin(np.sqrt(d))).astype("float32")
78
 
79
+ # Agrégats par défaut (pour une transaction isolée via API)
80
+ df["avg_amt"] = df["amt"]
81
  df["std_amt"] = 0.0
82
  df["nb_trans"] = 1.0
83
 
84
+ # Ordre strict des colonnes
85
  cols = ['amt', 'hour', 'day_of_week', 'day', 'month', 'age', 'lat', 'long',
86
  'city_pop', 'distance', 'avg_amt', 'std_amt', 'nb_trans',
87
  'category', 'gender', 'state', 'merchant', 'job']
88
  return df[cols]
89
 
90
+ # --- 6. ENDPOINT DE PRÉDICTION ---
91
  @app.post("/predict")
92
  def predict(data: Transaction):
93
+ try:
94
+ X = prepare_input(data.dict())
95
+ prediction = model.predict(X)
96
+ return {
97
+ "is_fraud": int(prediction[0]),
98
+ "status": "success"
99
+ }
100
+ except Exception as e:
101
+ return {"status": "error", "message": str(e)}
102
 
103
+ if __name__ == "__main__":
104
+ import uvicorn
105
+ uvicorn.run(app, host="0.0.0.0", port=7860) # Port par défaut Hugging Face