dilexsan commited on
Commit
76c2660
·
verified ·
1 Parent(s): 80d1638

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -0
app.py CHANGED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, UploadFile, File
2
+ from fastapi.responses import JSONResponse
3
+ import numpy as np
4
+ import joblib
5
+ import cv2
6
+ from PIL import Image
7
+ import mediapipe as mp
8
+ import os
9
+ import io
10
+
11
+ app = FastAPI()
12
+
13
+ # ---------------- LOAD MODEL ----------------
14
+ MODEL_DIR = "model2"
15
+ model = joblib.load(os.path.join(MODEL_DIR, "emotion_model.joblib"))
16
+ label_encoder = joblib.load(os.path.join(MODEL_DIR, "label_encoder.joblib"))
17
+
18
+ face_mesh = mp.solutions.face_mesh.FaceMesh(
19
+ static_image_mode=True,
20
+ max_num_faces=1,
21
+ min_detection_confidence=0.5
22
+ )
23
+
24
+ # Same feature order you used during training
25
+ FEATURE_ORDER = [
26
+ # add your full list here exactly as in training
27
+ ]
28
+
29
+
30
+ # ---------------- FEATURE EXTRACTION ----------------
31
+ def compute_basic_features(landmarks, w, h):
32
+ # paste the exact function from your project here
33
+ raise NotImplementedError("Add your compute_basic_features() here")
34
+
35
+
36
+ def extract_features(image):
37
+ img_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
38
+ results = face_mesh.process(img_rgb)
39
+
40
+ if not results.multi_face_landmarks:
41
+ return None, ["No face detected"]
42
+
43
+ landmarks = np.array([(lm.x, lm.y, lm.z) for lm in results.multi_face_landmarks[0].landmark])
44
+ h, w, _ = image.shape
45
+
46
+ features = compute_basic_features(landmarks, w, h)
47
+
48
+ ordered_features = [features.get(f, 0) for f in FEATURE_ORDER]
49
+ return np.array(ordered_features).reshape(1, -1), None
50
+
51
+
52
+ def predict_emotion(image):
53
+ X, error = extract_features(image)
54
+ if error:
55
+ return {"error": error}
56
+
57
+ pred = model.predict(X)[0]
58
+ confidence = np.max(model.predict_proba(X))
59
+
60
+ emotion_label = label_encoder.inverse_transform([pred])[0]
61
+
62
+ return {
63
+ "emotion": emotion_label,
64
+ "confidence": float(confidence),
65
+ }
66
+
67
+
68
+ # ---------------- API ENDPOINT ----------------
69
+ @app.post("/predict")
70
+ async def predict(image: UploadFile = File(...)):
71
+ try:
72
+ img_bytes = await image.read()
73
+ img = Image.open(io.BytesIO(img_bytes))
74
+ img = np.array(img)
75
+
76
+ # Normalize the format
77
+ if img.ndim == 2:
78
+ img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
79
+ elif img.shape[2] == 4:
80
+ img = cv2.cvtColor(img, cv2.COLOR_RGBA2BGR)
81
+ else:
82
+ img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
83
+
84
+ output = predict_emotion(img)
85
+ return JSONResponse(output)
86
+
87
+ except Exception as e:
88
+ return JSONResponse({"error": str(e)}, status_code=500)
89
+
90
+
91
+ @app.get("/")
92
+ def root():
93
+ return {"status": "API is running", "endpoint": "/predict"}