Sameer-Handsome173 commited on
Commit
145d05a
·
verified ·
1 Parent(s): 1b8db3f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +149 -0
app.py ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException, Header
2
+ from contextlib import asynccontextmanager
3
+ import pandas as pd
4
+ import os
5
+ import joblib
6
+ import time
7
+ import requests
8
+ from huggingface_hub import hf_hub_download
9
+ from prometheus_client import Counter, Histogram, Gauge, generate_latest
10
+
11
+ # Global variables
12
+ model = None
13
+ encoders = {}
14
+ scaler = None
15
+ feature_columns = []
16
+ categorical_columns = []
17
+ boolean_columns = []
18
+ loaded = False
19
+
20
+ # Environment variables
21
+ API_KEY = os.getenv("API_KEY", "test-key-123")
22
+ HF_MODEL_REPO = os.getenv("HF_MODEL_REPO")
23
+ PROM_PUSHGATEWAY = os.getenv("PROM_PUSHGATEWAY")
24
+
25
+ # Prometheus metrics
26
+ REQS = Counter("pred_requests_total", "Total prediction requests")
27
+ LAT = Histogram("pred_request_latency_seconds", "Request latency")
28
+ LATEST = Gauge("latest_prediction", "Last predicted value")
29
+
30
+
31
+ @asynccontextmanager
32
+ async def lifespan(app: FastAPI):
33
+ # Startup
34
+ global model, encoders, scaler, feature_columns, categorical_columns, boolean_columns, loaded
35
+
36
+ print("🚀 Starting FastAPI application...")
37
+ print(f"API_KEY: {'Set' if API_KEY else 'Not set'}")
38
+ print(f"HF_MODEL_REPO: {HF_MODEL_REPO}")
39
+
40
+ if not HF_MODEL_REPO:
41
+ print("⚠️ WARNING: HF_MODEL_REPO not set. Using mock mode.")
42
+ loaded = False
43
+ else:
44
+ try:
45
+ print(f" Downloading model from {HF_MODEL_REPO}...")
46
+
47
+ m = hf_hub_download(repo_id=HF_MODEL_REPO, filename="best_model.joblib")
48
+ e = hf_hub_download(repo_id=HF_MODEL_REPO, filename="models/encoders.joblib")
49
+ s = hf_hub_download(repo_id=HF_MODEL_REPO, filename="models/scaler.joblib")
50
+ f = hf_hub_download(repo_id=HF_MODEL_REPO, filename="models/feature_columns.joblib")
51
+ c = hf_hub_download(repo_id=HF_MODEL_REPO, filename="models/categorical_columns.joblib")
52
+ b = hf_hub_download(repo_id=HF_MODEL_REPO, filename="models/boolean_columns.joblib")
53
+
54
+ print(" Loading artifacts...")
55
+ model = joblib.load(m)
56
+ encoders = joblib.load(e)
57
+ scaler = joblib.load(s)
58
+ feature_columns = joblib.load(f)
59
+ categorical_columns = joblib.load(c)
60
+ boolean_columns = joblib.load(b)
61
+ loaded = True
62
+
63
+ print(" Model loaded successfully!")
64
+ print(f" Features: {len(feature_columns)}")
65
+ except Exception as ex:
66
+ print(f" Model load error: {ex}")
67
+ loaded = False
68
+
69
+ print(" FastAPI app initialized and ready!")
70
+
71
+ yield # Server runs here
72
+
73
+ # Shutdown (cleanup if needed)
74
+ print("🛑 Shutting down...")
75
+
76
+
77
+ app = FastAPI(title="Loan Approval API", version="1.0", lifespan=lifespan)
78
+
79
+
80
+ @app.get("/")
81
+ def health():
82
+ return {
83
+ "status": "ok",
84
+ "model_loaded": loaded,
85
+ "features": feature_columns if loaded else []
86
+ }
87
+
88
+
89
+ @app.post("/predict")
90
+ def predict(payload: dict, x_api_key: str = Header(None)):
91
+ if x_api_key != API_KEY:
92
+ raise HTTPException(status_code=401, detail="Invalid API key")
93
+
94
+ if not loaded:
95
+ raise HTTPException(status_code=503, detail="Model not loaded")
96
+
97
+ try:
98
+ df = pd.DataFrame([payload])
99
+
100
+ for col in feature_columns:
101
+ if col not in df.columns:
102
+ df[col] = 0
103
+
104
+ for col in boolean_columns:
105
+ if col in df.columns:
106
+ if df[col].dtype == bool:
107
+ df[col] = df[col].astype(int)
108
+ elif df[col].dtype == 'object':
109
+ df[col] = df[col].map({
110
+ 'True': 1, 'true': 1, True: 1, 1: 1,
111
+ 'False': 0, 'false': 0, False: 0, 0: 0
112
+ }).fillna(0).astype(int)
113
+
114
+ for col in categorical_columns:
115
+ if col in df.columns and col in encoders:
116
+ try:
117
+ df[col] = encoders[col].transform(df[col])
118
+ except:
119
+ df[col] = 0
120
+
121
+ df = df[feature_columns]
122
+ df_scaled = scaler.transform(df)
123
+
124
+ start = time.time()
125
+ pred = model.predict(df_scaled)[0]
126
+ latency = time.time() - start
127
+
128
+ LAT.observe(latency)
129
+ REQS.inc()
130
+ LATEST.set(pred)
131
+
132
+ if PROM_PUSHGATEWAY:
133
+ try:
134
+ requests.post(f"{PROM_PUSHGATEWAY}/metrics/job/loan_model", data=generate_latest(), timeout=2)
135
+ except:
136
+ pass
137
+
138
+ return {
139
+ "prediction": int(pred),
140
+ "prediction_label": "Approved" if pred == 1 else "Rejected",
141
+ "latency_seconds": round(latency, 4)
142
+ }
143
+ except Exception as e:
144
+ raise HTTPException(status_code=500, detail=str(e))
145
+
146
+
147
+ @app.get("/metrics")
148
+ def metrics():
149
+ return generate_latest()