Atomik31 commited on
Commit
5edbdc5
ยท
1 Parent(s): c3214b6

init commit

Browse files
Files changed (4) hide show
  1. Dockerfile +16 -0
  2. README.md +4 -4
  3. app.py +121 -0
  4. requirements.txt +15 -0
Dockerfile ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10
2
+
3
+ WORKDIR /home/app
4
+
5
+ RUN apt-get update -y
6
+ RUN apt-get install nano unzip -y
7
+ RUN apt install curl -y
8
+
9
+ RUN curl -fsSL https://get.deta.dev/cli.sh | sh
10
+
11
+ COPY requirements.txt /dependencies/requirements.txt
12
+ RUN pip install -r /dependencies/requirements.txt
13
+
14
+ COPY . /home/app
15
+
16
+ CMD gunicorn app:app --bind 0.0.0.0:$PORT --worker-class uvicorn.workers.UvicornWorker
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: Model Serv Api
3
- emoji: ๐ŸŒ–
4
- colorFrom: yellow
5
- colorTo: green
6
  sdk: docker
7
  pinned: false
8
  ---
 
1
  ---
2
+ title: Apimodelibm
3
+ emoji: ๐Ÿ“š
4
+ colorFrom: blue
5
+ colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
  ---
app.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import mlflow
3
+ import pandas as pd
4
+ import uvicorn
5
+ import json
6
+ from fastapi import FastAPI, File, UploadFile, HTTPException
7
+ from pydantic import BaseModel
8
+ from typing import Literal, List, Union
9
+
10
+ # -----------------------------------------------------------------------------
11
+ # ENV + MLflow setup
12
+ # -----------------------------------------------------------------------------
13
+ # Sur Hugging Face, ces variables sont lues depuis les "Secrets"
14
+ MLFLOW_TRACKING_URI = os.getenv("MLFLOW_TRACKING_URI")
15
+ REGISTERED_MODEL_NAME = os.getenv("MLFLOW_REGISTERED_MODEL_NAME")
16
+ MODEL_STAGE = os.getenv("MLFLOW_MODEL_STAGE")
17
+ MODEL_ALIAS = os.getenv("MLFLOW_MODEL_ALIAS")
18
+
19
+ # On force l'URI pour mlflow
20
+ if MLFLOW_TRACKING_URI:
21
+ mlflow.set_tracking_uri(MLFLOW_TRACKING_URI)
22
+
23
+
24
+ def build_model_uri() -> str:
25
+ if MODEL_ALIAS:
26
+ return f"models:/{REGISTERED_MODEL_NAME}@{MODEL_ALIAS}"
27
+ return f"models:/{REGISTERED_MODEL_NAME}/{MODEL_STAGE or 'Production'}"
28
+ # models:/ibm_attrition_detector@production
29
+
30
+
31
+ MODEL_URI = build_model_uri()
32
+ MODEL = None
33
+
34
+ # -----------------------------------------------------------------------------
35
+ # FastAPI Setup
36
+ # -----------------------------------------------------------------------------
37
+ app = FastAPI(title="๐Ÿ‘จโ€๐Ÿ’ผ HR Prediction API")
38
+
39
+
40
+ class PredictionFeatures(BaseModel):
41
+ Age: Union[int, float]
42
+ BusinessTravel: str
43
+ DailyRate: Union[int, float]
44
+ Department: str
45
+ DistanceFromHome: Union[int, float]
46
+ Education: Union[int, float]
47
+ EducationField: str
48
+ EmployeeCount: Union[int, float]
49
+ EmployeeNumber: Union[int, float]
50
+ EnvironmentSatisfaction: Union[int, float]
51
+ Gender: str
52
+ HourlyRate: Union[int, float]
53
+ JobInvolvement: Union[int, float]
54
+ JobLevel: Union[int, float]
55
+ JobRole: str
56
+ JobSatisfaction: Union[int, float]
57
+ MaritalStatus: str
58
+ MonthlyIncome: Union[int, float]
59
+ MonthlyRate: Union[int, float]
60
+ NumCompaniesWorked: Union[int, float]
61
+ Over18: str
62
+ OverTime: str
63
+ PercentSalaryHike: Union[int, float]
64
+ PerformanceRating: Union[int, float]
65
+ RelationshipSatisfaction: Union[int, float]
66
+ StandardHours: Union[int, float]
67
+ StockOptionLevel: Union[int, float]
68
+ TotalWorkingYears: Union[int, float]
69
+ TrainingTimesLastYear: Union[int, float]
70
+ WorkLifeBalance: Union[int, float]
71
+ YearsAtCompany: Union[int, float]
72
+ YearsInCurrentRole: Union[int, float]
73
+ YearsSinceLastPromotion: Union[int, float]
74
+ YearsWithCurrManager: Union[int, float]
75
+
76
+
77
+ # -----------------------------------------------------------------------------
78
+ # Startup: CHARGEMENT BLOQUANT (Solution au bug 500)
79
+ # -----------------------------------------------------------------------------
80
+ @app.on_event("startup")
81
+ def load_model_sync():
82
+ global MODEL
83
+ print(f"๐Ÿš€ [INFO] Attempting to load model: {MODEL_URI}")
84
+ try:
85
+ # On attend que le chargement soit fini avant de rendre l'API disponible
86
+ MODEL = mlflow.sklearn.load_model(MODEL_URI)
87
+ # models:/ibm_attrition_detector@production
88
+ print("โœ… [INFO] Model loaded successfully!")
89
+ except Exception as e:
90
+ print(f"โŒ [ERROR] Failed to load model: {e}")
91
+ # En cas d'รฉchec, on laisse MODEL ร  None pour que /health le signale
92
+
93
+
94
+ # -----------------------------------------------------------------------------
95
+ # Endpoints
96
+ # -----------------------------------------------------------------------------
97
+ @app.get("/health")
98
+ def health():
99
+ return {
100
+ "status": "ok",
101
+ "model_uri": MODEL_URI,
102
+ "model_loaded": MODEL is not None,
103
+ }
104
+
105
+
106
+ @app.post("/predict")
107
+ async def predict(payload: PredictionFeatures):
108
+ if MODEL is None:
109
+ raise HTTPException(
110
+ status_code=503, detail="Model is still loading or failed to load."
111
+ )
112
+
113
+ # Conversion pydantic -> dict -> DataFrame
114
+ df = pd.DataFrame([payload.dict()])
115
+ pred = MODEL.predict(df)
116
+ return {"prediction": int(pred[0])}
117
+
118
+
119
+ if __name__ == "__main__":
120
+ # Port 7860 est le standard pour Hugging Face Spaces
121
+ uvicorn.run(app, host="0.0.0.0", port=int(os.getenv("PORT", 7860)))
requirements.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ mlflow==2.21.3
2
+ scikit-learn==1.4.2
3
+ requests>=2.31.0,<3
4
+ fastapi
5
+ uvicorn[standard]
6
+ pydantic>=2.0
7
+ email-validator>=2.0
8
+ typing
9
+ pandas
10
+ gunicorn
11
+ openpyxl
12
+ boto3
13
+ python-multipart
14
+ dotenv
15
+ python-dotenv