Spaces:
Sleeping
Sleeping
ibraheem15
commited on
Commit
·
a1099ee
1
Parent(s):
3fa282f
Refactor Dockerfile for multi-stage builds and enhance main.py with CORS middleware and updated model
Browse files- Dockerfile +28 -16
- main.py +12 -2
Dockerfile
CHANGED
|
@@ -1,24 +1,36 @@
|
|
| 1 |
-
#
|
| 2 |
-
|
| 3 |
-
# Use a lean official Python image
|
| 4 |
-
FROM python:3.10-slim
|
| 5 |
-
|
| 6 |
-
# Set working directory
|
| 7 |
WORKDIR /app
|
|
|
|
|
|
|
| 8 |
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
RUN pip install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cpu
|
| 13 |
-
|
| 14 |
RUN pip install --no-cache-dir -r requirements.txt
|
| 15 |
|
| 16 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
COPY main.py /app/
|
|
|
|
|
|
|
| 18 |
COPY tests/ /app/tests/
|
| 19 |
-
# The port is often fixed by the cloud host (e.g., 7860 for HF Spaces)
|
| 20 |
-
# We use 8000 as a standard, and the cloud host will map its port to this one.
|
| 21 |
-
EXPOSE 8000
|
| 22 |
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# STAGE 1: Base (Heavy Dependencies)
|
| 2 |
+
FROM python:3.10-slim as base
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
WORKDIR /app
|
| 4 |
+
# Install system deps if needed (e.g., usually needed for cv2 or weird numpy versions)
|
| 5 |
+
# RUN apt-get update && apt-get install -y --no-install-recommends gcc libgomp1
|
| 6 |
|
| 7 |
+
COPY requirements.txt .
|
| 8 |
+
# 1. Install Torch (Heavy - Cached in this layer)
|
|
|
|
| 9 |
RUN pip install --no-cache-dir torch --index-url https://download.pytorch.org/whl/cpu
|
| 10 |
+
# 2. Install other Prod deps
|
| 11 |
RUN pip install --no-cache-dir -r requirements.txt
|
| 12 |
|
| 13 |
+
# STAGE 2: Test (Needs App Code + Tests)
|
| 14 |
+
FROM base as test
|
| 15 |
+
# 1. Install Test Tools
|
| 16 |
+
RUN pip install pytest flake8 httpx
|
| 17 |
+
|
| 18 |
+
# 2. COPY THE APP CODE (Crucial Step!)
|
| 19 |
+
# The tests need to import 'main', so main.py must be here.
|
| 20 |
COPY main.py /app/
|
| 21 |
+
|
| 22 |
+
# 3. Copy Tests
|
| 23 |
COPY tests/ /app/tests/
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
+
ENV PYTHONPATH=/app
|
| 26 |
+
# 4. Run Linting and Tests
|
| 27 |
+
RUN flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
| 28 |
+
RUN pytest tests/
|
| 29 |
+
|
| 30 |
+
# STAGE 3: Production (Final Image)
|
| 31 |
+
FROM base as prod
|
| 32 |
+
# We start fresh from 'base'. The junk from 'test' stage is gone.
|
| 33 |
+
COPY main.py /app/
|
| 34 |
+
# Note: We do NOT copy tests/ here to keep prod image smaller
|
| 35 |
+
EXPOSE 8000
|
| 36 |
+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
main.py
CHANGED
|
@@ -1,12 +1,13 @@
|
|
| 1 |
# main.py
|
| 2 |
from fastapi import FastAPI, HTTPException
|
|
|
|
| 3 |
from pydantic import BaseModel
|
| 4 |
from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline
|
| 5 |
from contextlib import asynccontextmanager
|
| 6 |
import torch
|
| 7 |
|
| 8 |
# --- MLOps Configuration ---
|
| 9 |
-
HF_MODEL_NAME = "
|
| 10 |
CLASSIFIER_PIPELINE = None
|
| 11 |
|
| 12 |
# Pydantic model for request body
|
|
@@ -45,6 +46,14 @@ app = FastAPI(
|
|
| 45 |
lifespan=lifespan
|
| 46 |
)
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
@app.get("/")
|
| 49 |
def health_check():
|
| 50 |
return {"status": "ok", "model_loaded": CLASSIFIER_PIPELINE is not None}
|
|
@@ -55,7 +64,8 @@ def predict_spam(item: Message):
|
|
| 55 |
raise HTTPException(status_code=503, detail="Model is not ready.")
|
| 56 |
|
| 57 |
try:
|
| 58 |
-
|
|
|
|
| 59 |
label = results[0]['label']
|
| 60 |
score = results[0]['score']
|
| 61 |
output_label = "spam" if label == 'LABEL_1' else "ham"
|
|
|
|
| 1 |
# main.py
|
| 2 |
from fastapi import FastAPI, HTTPException
|
| 3 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
from pydantic import BaseModel
|
| 5 |
from transformers import AutoTokenizer, AutoModelForSequenceClassification, pipeline
|
| 6 |
from contextlib import asynccontextmanager
|
| 7 |
import torch
|
| 8 |
|
| 9 |
# --- MLOps Configuration ---
|
| 10 |
+
HF_MODEL_NAME = "mrm8488/bert-tiny-finetuned-sms-spam-detection"
|
| 11 |
CLASSIFIER_PIPELINE = None
|
| 12 |
|
| 13 |
# Pydantic model for request body
|
|
|
|
| 46 |
lifespan=lifespan
|
| 47 |
)
|
| 48 |
|
| 49 |
+
app.add_middleware(
|
| 50 |
+
CORSMiddleware,
|
| 51 |
+
allow_origins=["*"],
|
| 52 |
+
allow_credentials=True,
|
| 53 |
+
allow_methods=["*"],
|
| 54 |
+
allow_headers=["*"],
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
@app.get("/")
|
| 58 |
def health_check():
|
| 59 |
return {"status": "ok", "model_loaded": CLASSIFIER_PIPELINE is not None}
|
|
|
|
| 64 |
raise HTTPException(status_code=503, detail="Model is not ready.")
|
| 65 |
|
| 66 |
try:
|
| 67 |
+
print(f"Received text for prediction: {item.text}")
|
| 68 |
+
results = CLASSIFIER_PIPELINE(item.text, truncation=True, max_length=512)
|
| 69 |
label = results[0]['label']
|
| 70 |
score = results[0]['score']
|
| 71 |
output_label = "spam" if label == 'LABEL_1' else "ham"
|