mg643 commited on
Commit
76fbd01
·
verified ·
1 Parent(s): 7f3fb0c

initial commit

Browse files
Files changed (3) hide show
  1. Dockerfile +13 -0
  2. app.py +137 -0
  3. requirements.txt +7 -0
Dockerfile ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY app.py .
9
+
10
+ # HuggingFace Spaces uses port 7860
11
+ EXPOSE 7860
12
+
13
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from azure.storage.blob import BlobServiceClient
4
+ import torch
5
+ import torch.nn as nn
6
+ from PIL import Image
7
+ from torchvision import transforms
8
+ import torchvision.models as models
9
+ import io
10
+ import os
11
+
12
+ app = FastAPI()
13
+
14
+ # Allow your React app to call this API
15
+ app.add_middleware(
16
+ CORSMiddleware,
17
+ allow_origins=["*"],
18
+ allow_credentials=True,
19
+ allow_methods=["*"],
20
+ allow_headers=["*"],
21
+ )
22
+
23
+ # Global variables
24
+ model = None
25
+ transform = None
26
+ ASL_CLASSES = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
27
+ 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
28
+ 'U', 'V', 'W', 'X', 'Y', 'Z', 'del', 'nothing', 'space']
29
+
30
+ class ASLEfficientNet(nn.Module):
31
+ """EfficientNet-B3 - matches your uploaded model"""
32
+ def __init__(self, num_classes=29):
33
+ super(ASLEfficientNet, self).__init__()
34
+
35
+ self.model = models.efficientnet_b3(weights=None)
36
+
37
+ in_features = self.model.classifier[1].in_features
38
+ self.model.classifier = nn.Sequential(
39
+ nn.Dropout(0.3),
40
+ nn.Linear(in_features, 512),
41
+ nn.ReLU(),
42
+ nn.Dropout(0.2),
43
+ nn.Linear(512, num_classes)
44
+ )
45
+
46
+ def forward(self, x):
47
+ return self.model(x)
48
+
49
+
50
+ @app.on_event("startup")
51
+ async def load_model():
52
+ global model, transform
53
+
54
+ print("Downloading model from Azure...")
55
+
56
+ # Get connection string from environment variable
57
+ connection_string = os.getenv("AZURE_STORAGE_CONNECTION_STRING")
58
+
59
+ # Download model
60
+ blob_service_client = BlobServiceClient.from_connection_string(connection_string)
61
+ blob_client = blob_service_client.get_blob_client(
62
+ container="models",
63
+ blob="deep_model.pth"
64
+ )
65
+
66
+ # Save to temp file
67
+ with open("/tmp/model.pth", "wb") as f:
68
+ download_stream = blob_client.download_blob()
69
+ f.write(download_stream.readall())
70
+
71
+ print("Loading model...")
72
+
73
+ # Load checkpoint
74
+ checkpoint = torch.load("/tmp/model.pth", map_location="cpu")
75
+
76
+ # Initialize model
77
+ model = ASLEfficientNet(num_classes=29)
78
+ model.load_state_dict(checkpoint['model_state_dict'])
79
+ model.eval()
80
+
81
+ # Set up preprocessing
82
+ transform = transforms.Compose([
83
+ transforms.Resize((224, 224)),
84
+ transforms.ToTensor(),
85
+ transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
86
+ ])
87
+
88
+ print("Model loaded successfully!")
89
+
90
+
91
+ @app.get("/")
92
+ def root():
93
+ return {"message": "ASL API is running"}
94
+
95
+
96
+ @app.post("/predict")
97
+ async def predict(file: UploadFile = File(...)):
98
+ if model is None:
99
+ raise HTTPException(status_code=503, detail="Model not loaded")
100
+
101
+ try:
102
+ # Read image
103
+ image_bytes = await file.read()
104
+ image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
105
+
106
+ # Preprocess
107
+ input_tensor = transform(image).unsqueeze(0)
108
+
109
+ # Predict
110
+ with torch.no_grad():
111
+ output = model(input_tensor)
112
+ probabilities = torch.softmax(output, dim=1)
113
+ confidence, predicted_idx = probabilities.max(1)
114
+
115
+ # Top 5
116
+ top5_prob, top5_idx = probabilities.topk(5, dim=1)
117
+
118
+ # Convert to letter
119
+ predicted_class = predicted_idx.item()
120
+ predicted_letter = ASL_CLASSES[predicted_class]
121
+
122
+ return {
123
+ "predicted_class": predicted_class,
124
+ "predicted_letter": predicted_letter,
125
+ "confidence": confidence.item(),
126
+ "top5_predictions": [
127
+ {
128
+ "class": int(top5_idx[0][i]),
129
+ "letter": ASL_CLASSES[int(top5_idx[0][i])],
130
+ "confidence": float(top5_prob[0][i])
131
+ }
132
+ for i in range(5)
133
+ ]
134
+ }
135
+
136
+ except Exception as e:
137
+ raise HTTPException(status_code=500, detail=str(e))
requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn[standard]==0.24.0
3
+ python-multipart==0.0.6
4
+ azure-storage-blob==12.19.0
5
+ torch==2.1.0
6
+ torchvision==0.16.0
7
+ pillow==10.1.0