ak0601 commited on
Commit
b1bbe6b
·
verified ·
1 Parent(s): e1a381b

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +76 -0
  2. requirements.txt +10 -0
app.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, HTTPException
2
+ from pydantic import BaseModel, Field
3
+ import numpy as np
4
+ import tensorflow as tf
5
+ import joblib
6
+ import os
7
+ from typing import List, Dict
8
+
9
+ app = FastAPI(title="Multimodal T5 Classification API")
10
+
11
+ # Define paths (use defaults set in training script)
12
+ MODEL_PATH = "./output/T5_best_multimodel.keras"
13
+ SCALER_PATH = "./output/scaler.pkl"
14
+
15
+ # Global variables for model and scaler
16
+ model = None
17
+ scaler = None
18
+
19
+ @app.on_event("startup")
20
+ def load_artifacts():
21
+ global model, scaler
22
+ if not os.path.exists(MODEL_PATH):
23
+ raise RuntimeError(f"Model file not found at {MODEL_PATH}. Please run training first.")
24
+ if not os.path.exists(SCALER_PATH):
25
+ raise RuntimeError(f"Scaler file not found at {SCALER_PATH}. Please run training first.")
26
+
27
+ model = tf.keras.models.load_model(MODEL_PATH)
28
+ scaler = joblib.load(SCALER_PATH)
29
+ print("Model and scaler loaded successfully.")
30
+
31
+ class FeaturesInput(BaseModel):
32
+ # Total 17 features as used in standard scaler + normalization
33
+ # Column indices based on notebook: X.iloc[:,3:]
34
+ # Original columns in Excel were 17 (3:20 range)
35
+ features: List[float] = Field(..., min_items=17, max_items=17,
36
+ description="List of 17 numeric features in original scale")
37
+
38
+ @app.post("/predict")
39
+ async def predict(input_data: FeaturesInput):
40
+ if model is None or scaler is None:
41
+ raise HTTPException(status_code=500, detail="Model artifacts not loaded.")
42
+
43
+ try:
44
+ # 1. Scaling
45
+ raw_features = np.array(input_data.features).reshape(1, -1)
46
+ scaled_features = scaler.transform(raw_features)
47
+
48
+ # 2. Modality Splitting
49
+ # Visual features: columns 1-6 + column 0 (of relative subset)
50
+ # In our case, the 17 features correspond to X.iloc[:,3:]
51
+ # visual_features = np.concatenate((X.iloc[:,1:7].to_numpy(), X.iloc[:,0].to_numpy().reshape(-1,1)), axis=1)
52
+ # speech_features = np.concatenate((X.iloc[:,7:11].to_numpy(), X.iloc[:,0].to_numpy().reshape(-1,1)), axis=1)
53
+ # pupl_features = np.concatenate((X.iloc[:,11:17].to_numpy(), X.iloc[:,0].to_numpy().reshape(-1,1)), axis=1)
54
+
55
+ f = scaled_features[0]
56
+ visual = np.concatenate([f[1:7], [f[0]]]).reshape(1, -1)
57
+ speech = np.concatenate([f[7:11], [f[0]]]).reshape(1, -1)
58
+ pupl = np.concatenate([f[11:17], [f[0]]]).reshape(1, -1)
59
+
60
+ # 3. Inference
61
+ prediction = model.predict([visual, speech, pupl], verbose=0)
62
+ predicted_class = int(np.argmax(prediction, axis=1)[0])
63
+ probabilities = prediction[0].tolist()
64
+
65
+ return {
66
+ "predicted_class": predicted_class,
67
+ "confidence": probabilities[predicted_class],
68
+ "probabilities": {str(i): prob for i, prob in enumerate(probabilities)}
69
+ }
70
+
71
+ except Exception as e:
72
+ raise HTTPException(status_code=400, detail=str(e))
73
+
74
+ @app.get("/health")
75
+ def health():
76
+ return {"status": "ok", "model_loaded": model is not None}
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ numpy
2
+ pandas
3
+ scikit-learn
4
+ joblib
5
+ keras
6
+ matplotlib
7
+ seaborn
8
+ tensorflow
9
+ uvicorn[standard]
10
+ fastapi