Subi003 commited on
Commit
256a301
·
verified ·
1 Parent(s): aa02bc1

Upload folder using huggingface_hub

Browse files
.dockerignore ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Ignore Python cache
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.so
5
+
6
+ # Ignore Jupyter notebooks (if not used)
7
+ *.ipynb
8
+ .ipynb_checkpoints/
9
+
10
+ # Ignore logs and temp files
11
+ *.log
12
+ *.tmp
13
+ *.DS_Store
14
+
15
+ # Ignore version control and dev files
16
+ .git/
17
+ .github/
18
+ .vscode/
19
+ *.env
20
+ .env*
21
+ .gitignore
22
+
23
+ # MLflow & DVC metadata (keep only if you need them at runtime)
24
+ .mlflow/
25
+ .dvc/
26
+ .dvcignore
27
+
28
+ # CI/CD config files
29
+ tox.ini
30
+ pytest.ini
31
+ setup.cfg
32
+ setup.py
33
+ requirements-dev.txt
34
+
35
+ # Ignore Docker build context bloat
36
+ *.tar
37
+ *.zip
38
+ *.gz
39
+ *.egg-info/
40
+
41
+ # Ignore Hugging Face cache
42
+ ~/.cache/huggingface/
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ model/
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11.11-slim-bookworm
2
+
3
+ RUN apt-get update && apt-get upgrade -y
4
+
5
+ COPY . /app
6
+
7
+ WORKDIR /app
8
+
9
+ RUN pip install -r requirements.txt
10
+
11
+ EXPOSE 7860
12
+
13
+ CMD ["uvicorn", "main:model_inference:inference_api", "--host", "0.0.0.0", "--port", "7860"]
main/__init__.py ADDED
File without changes
main/helper.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Helper functions for the model inference api
2
+ import yaml
3
+ import joblib
4
+ from pathlib import Path
5
+
6
+ # load yaml files to get model meta data.
7
+ try:
8
+ with open(Path("model/registered_model_meta.yaml"), 'r') as f:
9
+ model_metadata = yaml.safe_load(f)
10
+ except:
11
+ raise FileNotFoundError("Failed to load file having model metadata")
12
+
13
+
14
+ def load_model():
15
+ """ Loads ML model from location path and returns the model. """
16
+ try:
17
+ with open(Path("serve_api/model/python_model.pkl"), "rb") as f:
18
+ model = joblib.load(f)
19
+ return model
20
+
21
+ except:
22
+ raise FileNotFoundError("Failed to load model")
23
+
24
+
25
+ def get_model_registry():
26
+ """ Fetches the model registry name and returns it. """
27
+ model_registry = model_metadata['model_name']
28
+ return model_registry
29
+
30
+
31
+ def get_model_version():
32
+ """ Fetches the model version and returns it. """
33
+ model_version = model_metadata['model_version']
34
+ return model_version
main/model_inference.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.responses import JSONResponse
3
+ from main.validate_schema import UserInput, APIResponse
4
+ from datetime import datetime
5
+ from main.helper import *
6
+ import uuid, time
7
+
8
+ model = load_model()
9
+
10
+ # Initializing fastapi
11
+ inference_api = FastAPI()
12
+
13
+ @inference_api.post('/api', response_model=APIResponse)
14
+ def api(payload: UserInput):
15
+ timestamp = datetime.now().astimezone().isoformat()
16
+ request_id = str(uuid.uuid4())
17
+
18
+ start_time = time.perf_counter()
19
+ tweet = payload.comment
20
+ model_response = model.predict(tweet)
21
+
22
+ label = int(model_response["class_label"][0])
23
+ probability_scores = model_response["class_probability_scores"]
24
+ proba_class0 = float(probability_scores[0][0])
25
+ proba_class1 = float(probability_scores[0][1])
26
+
27
+ end_time = time.perf_counter()
28
+
29
+ if proba_class1 > 0.70:
30
+ toxic_level = "strong"
31
+ elif proba_class1 > 0.54:
32
+ toxic_level = "high"
33
+ elif proba_class1 > 0.46:
34
+ toxic_level = "light"
35
+ else:
36
+ toxic_level = "none"
37
+
38
+
39
+ response = {
40
+ "response": {
41
+ "class_label": label,
42
+ "confidence": round(abs(proba_class0 - proba_class1), 4),
43
+ "toxic_level": toxic_level,
44
+ "pred_scores": {
45
+ "0": round(proba_class0, 4),
46
+ "1": round(proba_class1, 4)
47
+ },
48
+ },
49
+ "metadata": {
50
+ "request_id": request_id,
51
+ "timestamp": timestamp,
52
+ "response_time": f"{round((end_time - start_time), 4)} sec",
53
+ "input": {
54
+ "num_tokens": int(len(tweet.split())),
55
+ "num_characters": int(len([i for i in tweet])),
56
+ "language": "en (iso 639-1code)",
57
+ },
58
+ "model": type(model.model).__name__,
59
+ "model_version": get_model_version(),
60
+ "vectorizer": type(model.vectorizer).__name__,
61
+ "model_registry": f"Mlflow {get_model_registry()}",
62
+ "type": "production",
63
+ "streamable": False,
64
+ "api_version": "v-1.0",
65
+ "developer": "Subinoy Bera"
66
+ }
67
+ }
68
+
69
+ return JSONResponse(status_code=200, content=response)
main/validate_schema.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from typing import Annotated, Dict
3
+
4
+
5
+ class UserInput(BaseModel):
6
+ comment: Annotated[str, Field(..., description="User tweet or comment to be classified")]
7
+
8
+
9
+ class ResponseData(BaseModel):
10
+ class_label: int
11
+ confidence: float
12
+ toxic_level: str
13
+ pred_scores: Dict[int, float]
14
+
15
+ class MetaData(BaseModel):
16
+ request_id: str
17
+ timestamp: str
18
+ response_time: str
19
+ input: Dict[str, int]
20
+ model: str
21
+ version: int
22
+ vectorizer: str
23
+ type: str
24
+ loader_module: str
25
+ streamable: bool
26
+ api_version: str
27
+ developer: str
28
+
29
+
30
+ class APIResponse(BaseModel):
31
+ response: ResponseData
32
+ metadata: MetaData
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ fastapi==0.116.1
2
+ uvicorn==0.35.0
3
+ joblib==1.5.1
4
+ PyYAML==6.0.2