Spaces:
Sleeping
Sleeping
Deploy KidneyDL CT Scan Classifier
Browse files- app.py +24 -6
- src/cnnClassifier/pipeline/prediction.py +11 -11
app.py
CHANGED
|
@@ -10,7 +10,21 @@ CORS(app)
|
|
| 10 |
UPLOAD_FOLDER = "uploads"
|
| 11 |
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
|
| 16 |
@app.route("/", methods=["GET"])
|
|
@@ -20,12 +34,13 @@ def home():
|
|
| 20 |
|
| 21 |
@app.route("/health", methods=["GET"])
|
| 22 |
def health():
|
| 23 |
-
|
| 24 |
return jsonify({
|
| 25 |
-
"status": "ok" if
|
| 26 |
-
"
|
| 27 |
"model_path": os.path.abspath(MODEL_PATH),
|
| 28 |
-
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
@app.route("/train", methods=["GET", "POST"])
|
|
@@ -36,6 +51,9 @@ def train():
|
|
| 36 |
|
| 37 |
@app.route("/predict", methods=["POST"])
|
| 38 |
def predict():
|
|
|
|
|
|
|
|
|
|
| 39 |
if "file" not in request.files:
|
| 40 |
return jsonify({"error": "No file uploaded"}), 400
|
| 41 |
|
|
@@ -46,7 +64,7 @@ def predict():
|
|
| 46 |
filepath = os.path.join(UPLOAD_FOLDER, file.filename)
|
| 47 |
try:
|
| 48 |
file.save(filepath)
|
| 49 |
-
pipeline = PredictionPipeline(filepath)
|
| 50 |
result = pipeline.predict()
|
| 51 |
return jsonify(result)
|
| 52 |
except Exception as e:
|
|
|
|
| 10 |
UPLOAD_FOLDER = "uploads"
|
| 11 |
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
| 12 |
|
| 13 |
+
# Resolve model path once — prefer .keras (Keras 3 native), fall back to .h5
|
| 14 |
+
_keras_path = os.path.join("artifacts", "training", "model.keras")
|
| 15 |
+
_h5_path = os.path.join("artifacts", "training", "model.h5")
|
| 16 |
+
MODEL_PATH = _keras_path if os.path.isfile(_keras_path) else _h5_path
|
| 17 |
+
|
| 18 |
+
# Load the model once at startup so every request reuses the same in-memory model
|
| 19 |
+
_MODEL = None
|
| 20 |
+
_MODEL_ERROR = None
|
| 21 |
+
try:
|
| 22 |
+
from tensorflow.keras.models import load_model
|
| 23 |
+
_MODEL = load_model(MODEL_PATH)
|
| 24 |
+
print(f"[startup] Model loaded from {MODEL_PATH}")
|
| 25 |
+
except Exception as _e:
|
| 26 |
+
_MODEL_ERROR = str(_e)
|
| 27 |
+
print(f"[startup] WARNING: model failed to load — {_MODEL_ERROR}")
|
| 28 |
|
| 29 |
|
| 30 |
@app.route("/", methods=["GET"])
|
|
|
|
| 34 |
|
| 35 |
@app.route("/health", methods=["GET"])
|
| 36 |
def health():
|
| 37 |
+
ok = _MODEL is not None
|
| 38 |
return jsonify({
|
| 39 |
+
"status": "ok" if ok else "degraded",
|
| 40 |
+
"model_loaded": ok,
|
| 41 |
"model_path": os.path.abspath(MODEL_PATH),
|
| 42 |
+
"error": _MODEL_ERROR,
|
| 43 |
+
}), 200 if ok else 503
|
| 44 |
|
| 45 |
|
| 46 |
@app.route("/train", methods=["GET", "POST"])
|
|
|
|
| 51 |
|
| 52 |
@app.route("/predict", methods=["POST"])
|
| 53 |
def predict():
|
| 54 |
+
if _MODEL is None:
|
| 55 |
+
return jsonify({"error": f"Model not loaded: {_MODEL_ERROR}"}), 503
|
| 56 |
+
|
| 57 |
if "file" not in request.files:
|
| 58 |
return jsonify({"error": "No file uploaded"}), 400
|
| 59 |
|
|
|
|
| 64 |
filepath = os.path.join(UPLOAD_FOLDER, file.filename)
|
| 65 |
try:
|
| 66 |
file.save(filepath)
|
| 67 |
+
pipeline = PredictionPipeline(filepath, model=_MODEL)
|
| 68 |
result = pipeline.predict()
|
| 69 |
return jsonify(result)
|
| 70 |
except Exception as e:
|
src/cnnClassifier/pipeline/prediction.py
CHANGED
|
@@ -5,14 +5,19 @@ import os
|
|
| 5 |
|
| 6 |
|
| 7 |
class PredictionPipeline:
|
| 8 |
-
def __init__(self, filename):
|
| 9 |
self.filename = filename
|
|
|
|
| 10 |
|
| 11 |
def predict(self):
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
|
| 17 |
img = image.load_img(self.filename, target_size=(224, 224))
|
| 18 |
img_array = image.img_to_array(img)
|
|
@@ -20,9 +25,4 @@ class PredictionPipeline:
|
|
| 20 |
|
| 21 |
result = np.argmax(model.predict(img_array), axis=1)
|
| 22 |
|
| 23 |
-
if result[0] == 1
|
| 24 |
-
prediction = "Tumor"
|
| 25 |
-
else:
|
| 26 |
-
prediction = "Normal"
|
| 27 |
-
|
| 28 |
-
return [{"image": prediction}]
|
|
|
|
| 5 |
|
| 6 |
|
| 7 |
class PredictionPipeline:
|
| 8 |
+
def __init__(self, filename, model=None):
|
| 9 |
self.filename = filename
|
| 10 |
+
self._model = model
|
| 11 |
|
| 12 |
def predict(self):
|
| 13 |
+
# Use pre-loaded model if provided, otherwise load from disk
|
| 14 |
+
if self._model is not None:
|
| 15 |
+
model = self._model
|
| 16 |
+
else:
|
| 17 |
+
keras_path = os.path.join("artifacts", "training", "model.keras")
|
| 18 |
+
h5_path = os.path.join("artifacts", "training", "model.h5")
|
| 19 |
+
model_path = keras_path if os.path.isfile(keras_path) else h5_path
|
| 20 |
+
model = load_model(model_path)
|
| 21 |
|
| 22 |
img = image.load_img(self.filename, target_size=(224, 224))
|
| 23 |
img_array = image.img_to_array(img)
|
|
|
|
| 25 |
|
| 26 |
result = np.argmax(model.predict(img_array), axis=1)
|
| 27 |
|
| 28 |
+
return [{"image": "Tumor" if result[0] == 1 else "Normal"}]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|