Brian Mabunda commited on
Commit
66f960f
·
1 Parent(s): 00c492e

Added project files

Browse files
Files changed (4) hide show
  1. DOCKERFILE +25 -0
  2. main.py +98 -0
  3. model.p +3 -0
  4. requirements.txt +20 -0
DOCKERFILE ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use the specific official Python 3.10.19 slim image
2
+ FROM python:3.10.19-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /code
6
+
7
+ # Copy requirements and install them
8
+ COPY requirements.txt .
9
+ RUN pip install --no-cache-dir --upgrade -r requirements.txt
10
+
11
+ # Create a non-root user (Mandatory for Hugging Face Spaces)
12
+ RUN useradd -m -u 1000 user
13
+ USER user
14
+ ENV HOME=/home/user \
15
+ PATH=/home/user/.local/bin:$PATH
16
+
17
+ # Move to the app directory and copy your code
18
+ WORKDIR $HOME/app
19
+ COPY --chown=user . .
20
+
21
+ # Expose the default Hugging Face port
22
+ EXPOSE 7860
23
+
24
+ # Run FastAPI using uvicorn
25
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
main.py ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel
3
+ from typing import List
4
+ import uvicorn
5
+ from fastapi.middleware.cors import CORSMiddleware
6
+ import pickle
7
+ import numpy as np
8
+
9
+ with open('model.p', 'rb') as f:
10
+ model_dict = pickle.load(f)
11
+
12
+ model = model_dict['model']
13
+ label_encoder = model_dict['label_encoder']
14
+
15
+ app = FastAPI(title="Sign Language Detection API")
16
+
17
+ # Enable CORS so your React frontend (localhost:3000) can communicate with this API
18
+ origins = [
19
+ # Your Vercel production URL (No trailing slash)
20
+ "https://sign-language-speller-43v971lbk-brians-projects-154a47fb.vercel.app",
21
+
22
+ # Your local development URL
23
+ "http://localhost:3000",
24
+ "http://127.0.0.1:3000",
25
+ ]
26
+ app.add_middleware(
27
+ CORSMiddleware,
28
+ allow_origins=origins,
29
+ allow_credentials=True,
30
+ allow_methods=["*"],
31
+ allow_headers=["*"],
32
+ )
33
+
34
+ # Define the structure for the landmark data
35
+ class Landmark(BaseModel):
36
+ x: float
37
+ y: float
38
+ z: float
39
+
40
+ class PredictionRequest(BaseModel):
41
+ landmarks: List[Landmark]
42
+ def normalize_landmarks(landmarks):
43
+ """
44
+ Normalize landmarks by translating and scaling.
45
+ """
46
+ # Translate landmarks so that the wrist (landmark 0) is at the origin
47
+ wrist = landmarks[0]
48
+ normalized=[]
49
+ for landmark in landmarks:
50
+ normalized.append(landmark.x -wrist.x)
51
+ normalized.append(landmark.y -wrist.y)
52
+
53
+ return normalized
54
+
55
+ @app.get("/")
56
+ async def root():
57
+ return {"message": "Sign Language API is running"}
58
+
59
+ @app.post("/predict")
60
+ async def predict(request: PredictionRequest):
61
+ """
62
+ Receives 21 landmarks and returns the predicted alphabet.
63
+ """
64
+ try:
65
+ landmarks = request.landmarks
66
+
67
+ # Ensure we have exactly 21 landmarks
68
+ if len(landmarks) != 21:
69
+ raise HTTPException(status_code=400, detail="Exactly 21 landmarks are required")
70
+
71
+ # --- MACHINE LEARNING INTEGRATION POINT ---
72
+ # This is where you would load your .joblib or .h5 model
73
+ # and transform the landmarks into a feature vector.
74
+ # Example:
75
+ # data_point = []
76
+ # for lm in landmarks:
77
+ # data_point.extend([lm.x, lm.y, lm.z])
78
+ model_input=np.array(normalize_landmarks(landmarks)).reshape(1,-1)
79
+ # print(model_input)
80
+ prediction = model.predict(model_input)
81
+
82
+ detected_char = label_encoder.inverse_transform(prediction)[0]
83
+
84
+ # Mock logic for demonstration:
85
+ # Just returning 'A' to confirm the connection works
86
+ # detected_char = "A"
87
+
88
+ return {
89
+ "alphabet": detected_char,
90
+ "status": "success"
91
+ }
92
+
93
+ except Exception as e:
94
+ raise HTTPException(status_code=500, detail=str(e))
95
+
96
+ if __name__ == "__main__":
97
+ # Run the server on port 5000 to match your React fetch call
98
+ uvicorn.run(app, host="0.0.0.0", port=5000)
model.p ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2b41714cda0da454de806071ce01c0c7aae1018258bfe87ef943e170c7b2ae1b
3
+ size 204763
requirements.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ annotated-doc==0.0.4
2
+ annotated-types==0.7.0
3
+ anyio==4.12.0
4
+ click==8.3.1
5
+ colorama==0.4.6
6
+ exceptiongroup==1.3.1
7
+ fastapi==0.128.0
8
+ h11==0.16.0
9
+ idna==3.11
10
+ joblib==1.5.3
11
+ numpy==2.2.6
12
+ pydantic==2.12.5
13
+ pydantic_core==2.41.5
14
+ scikit-learn==1.7.2
15
+ scipy==1.15.3
16
+ starlette==0.50.0
17
+ threadpoolctl==3.6.0
18
+ typing-inspection==0.4.2
19
+ typing_extensions==4.15.0
20
+ uvicorn==0.40.0