Sentoz commited on
Commit
54bcce5
·
verified ·
1 Parent(s): 6241d3b

Deploy KidneyDL CT Scan Classifier

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ artifacts/training/model.keras filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -1,4 +1,5 @@
1
  import os
 
2
  from flask import Flask, request, jsonify, render_template
3
  from flask_cors import CORS
4
  from cnnClassifier.pipeline.prediction import PredictionPipeline
@@ -9,12 +10,24 @@ CORS(app)
9
  UPLOAD_FOLDER = "uploads"
10
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
11
 
 
 
12
 
13
  @app.route("/", methods=["GET"])
14
  def home():
15
  return render_template("index.html")
16
 
17
 
 
 
 
 
 
 
 
 
 
 
18
  @app.route("/train", methods=["GET", "POST"])
19
  def train():
20
  os.system("python main.py")
@@ -31,12 +44,17 @@ def predict():
31
  return jsonify({"error": "No file selected"}), 400
32
 
33
  filepath = os.path.join(UPLOAD_FOLDER, file.filename)
34
- file.save(filepath)
35
-
36
- pipeline = PredictionPipeline(filepath)
37
- result = pipeline.predict()
38
-
39
- return jsonify(result)
 
 
 
 
 
40
 
41
 
42
  if __name__ == "__main__":
 
1
  import os
2
+ import traceback
3
  from flask import Flask, request, jsonify, render_template
4
  from flask_cors import CORS
5
  from cnnClassifier.pipeline.prediction import PredictionPipeline
 
10
  UPLOAD_FOLDER = "uploads"
11
  os.makedirs(UPLOAD_FOLDER, exist_ok=True)
12
 
13
+ MODEL_PATH = os.path.join("artifacts", "training", "model.h5")
14
+
15
 
16
  @app.route("/", methods=["GET"])
17
  def home():
18
  return render_template("index.html")
19
 
20
 
21
+ @app.route("/health", methods=["GET"])
22
+ def health():
23
+ model_exists = os.path.isfile(MODEL_PATH)
24
+ return jsonify({
25
+ "status": "ok" if model_exists else "degraded",
26
+ "model_found": model_exists,
27
+ "model_path": os.path.abspath(MODEL_PATH),
28
+ }), 200 if model_exists else 503
29
+
30
+
31
  @app.route("/train", methods=["GET", "POST"])
32
  def train():
33
  os.system("python main.py")
 
44
  return jsonify({"error": "No file selected"}), 400
45
 
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:
53
+ traceback.print_exc()
54
+ return jsonify({"error": str(e)}), 500
55
+ finally:
56
+ if os.path.exists(filepath):
57
+ os.remove(filepath)
58
 
59
 
60
  if __name__ == "__main__":
artifacts/training/model.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e92b2657c65573f928f9f5f20f63db4001cc93d8ae1ed58f5f396918b0a2ebda
3
+ size 59141294
requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- tensorflow
2
- keras
3
  dvc
4
  numpy
5
  pandas
 
1
+ tensorflow==2.20.0
2
+ keras==3.13.2
3
  dvc
4
  numpy
5
  pandas
resave_model.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ One-time script: resave model.h5 as model.keras (Keras 3 native format).
3
+ This ensures the deployed model loads correctly regardless of minor Keras version
4
+ differences between training and serving environments.
5
+
6
+ Run once:
7
+ python resave_model.py
8
+ """
9
+
10
+ from tensorflow.keras.models import load_model
11
+
12
+ h5_path = "artifacts/training/model.h5"
13
+ keras_path = "artifacts/training/model.keras"
14
+
15
+ print(f"Loading {h5_path} ...")
16
+ model = load_model(h5_path)
17
+
18
+ print(f"Saving {keras_path} ...")
19
+ model.save(keras_path)
20
+
21
+ print("Done. Deploy with: python deploy_to_hf.py")
src/cnnClassifier/pipeline/prediction.py CHANGED
@@ -9,7 +9,10 @@ class PredictionPipeline:
9
  self.filename = filename
10
 
11
  def predict(self):
12
- model = load_model(os.path.join("artifacts", "training", "model.h5"))
 
 
 
13
 
14
  img = image.load_img(self.filename, target_size=(224, 224))
15
  img_array = image.img_to_array(img)
 
9
  self.filename = filename
10
 
11
  def predict(self):
12
+ keras_path = os.path.join("artifacts", "training", "model.keras")
13
+ h5_path = os.path.join("artifacts", "training", "model.h5")
14
+ model_path = keras_path if os.path.isfile(keras_path) else h5_path
15
+ model = load_model(model_path)
16
 
17
  img = image.load_img(self.filename, target_size=(224, 224))
18
  img_array = image.img_to_array(img)
templates/index.html CHANGED
@@ -670,6 +670,7 @@
670
  try {
671
  const res = await fetch('/predict', { method: 'POST', body: fd });
672
  const data = await res.json();
 
673
  const pred = data[0]?.image || 'Unknown';
674
 
675
  const resultEl = document.getElementById('result');
@@ -695,8 +696,8 @@
695
  document.getElementById('confPct').textContent = conf + '%';
696
  resultEl.style.display = 'block';
697
 
698
- } catch {
699
- alert('Something went wrong during analysis. Please try again.');
700
  } finally {
701
  document.getElementById('loading').style.display = 'none';
702
  document.getElementById('predictBtn').disabled = false;
 
670
  try {
671
  const res = await fetch('/predict', { method: 'POST', body: fd });
672
  const data = await res.json();
673
+ if (!res.ok) throw new Error(data.error || `Server error ${res.status}`);
674
  const pred = data[0]?.image || 'Unknown';
675
 
676
  const resultEl = document.getElementById('result');
 
696
  document.getElementById('confPct').textContent = conf + '%';
697
  resultEl.style.display = 'block';
698
 
699
+ } catch (err) {
700
+ alert('Something went wrong during analysis.\n\n' + (err?.message || err));
701
  } finally {
702
  document.getElementById('loading').style.display = 'none';
703
  document.getElementById('predictBtn').disabled = false;