""" predict.py - tiny client for the feature-input fraud model. Depends only on pandas, numpy, joblib (+ huggingface_hub if you use from_hub). model = FraudModel.from_hub("user/repo") # or FraudModel.load("fraud_model") model.predict({"amount": 650, "hour": 3.2, ... all 15 features ...}) """ import json import os import joblib import pandas as pd RISK_LABELS = {0: "low", 1: "elevated", 2: "high", 3: "critical"} class FraudModel: def __init__(self, model, config): self.model = model self.feature_names = config["feature_names"] self.thresholds = config["thresholds"] @classmethod def load(cls, folder="."): with open(os.path.join(folder, "config.json")) as f: config = json.load(f) return cls(joblib.load(os.path.join(folder, "model.joblib")), config) @classmethod def from_hub(cls, repo_id): from huggingface_hub import snapshot_download return cls.load(snapshot_download(repo_id)) def predict(self, features): """features: dict | list of dicts | DataFrame -> dict (or list of dicts for several rows)""" single = isinstance(features, dict) df = pd.DataFrame([features] if single else features) missing = [c for c in self.feature_names if c not in df.columns] if missing: raise ValueError(f"Missing features: {missing}") X = df[self.feature_names].astype(float) if X.isna().any().any(): raise ValueError("Feature values must not be empty/NaN (use the 'no history' defaults).") probs = self.model.predict_proba(X)[:, 1] out = [] for p in probs: level = int(sum(p >= t for t in self.thresholds)) out.append({"fraud_probability": round(float(p), 4), "risk_level": level, "risk_label": RISK_LABELS[level]}) return out[0] if single else out