UdaraChamidu commited on
Commit
be1ba61
·
verified ·
1 Parent(s): 235f236

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +170 -173
app.py CHANGED
@@ -1,173 +1,170 @@
1
- import os
2
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" # reduce TF logs
3
-
4
- import matplotlib
5
- matplotlib.use('Agg') # headless backend
6
-
7
- import cv2
8
- import numpy as np
9
- import pandas as pd
10
- from datetime import datetime
11
- from flask import Flask, render_template, request, redirect, send_file
12
- from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
13
- from tensorflow.keras.models import load_model
14
- from fpdf import FPDF
15
- import matplotlib.pyplot as plt
16
-
17
- # Optional: ability to download model from Hugging Face Hub if not present
18
- # Uncomment if you want runtime download (requires huggingface_hub in requirements)
19
- # from huggingface_hub import hf_hub_download
20
-
21
- # -----------------------------
22
- # Flask Config
23
- # -----------------------------
24
- app = Flask(__name__)
25
- app.config["UPLOAD_FOLDER"] = "static/uploads"
26
- os.makedirs(app.config["UPLOAD_FOLDER"], exist_ok=True)
27
-
28
- # -----------------------------
29
- # Model path
30
- MODEL_DIR = "model"
31
- os.makedirs(MODEL_DIR, exist_ok=True)
32
- MODEL_PATH = os.path.join(MODEL_DIR, "efficientnet_b0_best.keras")
33
-
34
- # If you want to download the model from HF Hub at runtime (optional)
35
- # Replace "username/repo" and "efficientnet_b0_best.keras" below with your model repo
36
- # try:
37
- # if not os.path.exists(MODEL_PATH):
38
- # hf_hub_download(repo_id="your-username/your-model-repo", filename="efficientnet_b0_best.keras", local_dir=MODEL_DIR)
39
- # except Exception as e:
40
- # print("Could not download model from HF Hub:", e)
41
-
42
- # Load Keras model (ensure the .keras file exists in model/)
43
- if not os.path.exists(MODEL_PATH):
44
- raise FileNotFoundError(f"Model file not found at {MODEL_PATH}. Place your .keras model in the /model folder.")
45
-
46
- best_model = load_model(MODEL_PATH)
47
-
48
- IMG_SIZE = 128
49
-
50
- # Class labels (no label encoder needed)
51
- CLASS_LABELS = ['biological', 'brown-glass', 'cardboard', 'green-glass',
52
- 'metal', 'paper', 'plastic', 'shoes', 'trash', 'white-glass']
53
-
54
- # Waste categories
55
- RECYCLABLE = ["brown-glass", "green-glass", "white-glass", "metal", "plastic", "paper", "cardboard"]
56
- NON_RECYCLABLE = ["trash", "biological", "shoes"]
57
-
58
- # Initialize statistics
59
- stats = {}
60
-
61
- # -----------------------------
62
- # Preprocess image
63
- def preprocess_image(file_path):
64
- img = cv2.imread(file_path)
65
- img_rgb = cv2.cvtColor(cv2.resize(img, (IMG_SIZE, IMG_SIZE)), cv2.COLOR_BGR2RGB)
66
- img_input = preprocess_input(img_rgb.astype("float32"))
67
- img_input = np.expand_dims(img_input, axis=0)
68
- return img_rgb, img_input
69
-
70
- # -----------------------------
71
- # Log predictions
72
- def log_prediction(class_label):
73
- log_df = pd.DataFrame([[datetime.now(), class_label]], columns=["Timestamp", "Class"])
74
- try:
75
- old_df = pd.read_csv("waste_log.csv")
76
- new_df = pd.concat([old_df, log_df], ignore_index=True)
77
- except FileNotFoundError:
78
- new_df = log_df
79
- new_df.to_csv("waste_log.csv", index=False)
80
-
81
- # -----------------------------
82
- # PDF Report
83
- def generate_pdf_report():
84
- pdf = FPDF()
85
- pdf.add_page()
86
- pdf.set_font("Arial", size=14)
87
- pdf.cell(200, 10, txt="Waste Classification Report", ln=True, align="C")
88
- pdf.ln(10)
89
-
90
- total_items = sum(stats.values()) if stats else 0
91
- pdf.set_font("Arial", size=12)
92
- pdf.cell(0, 10, txt=f"Total Items Processed: {total_items}", ln=True)
93
-
94
- for category, count in stats.items():
95
- pdf.cell(0, 10, txt=f"{category}: {count}", ln=True)
96
-
97
- pdf_file = "waste_report.pdf"
98
- pdf.output(pdf_file)
99
- return pdf_file
100
-
101
- # -----------------------------
102
- # Routes
103
- @app.route("/", methods=["GET", "POST"])
104
- def index():
105
- if request.method == "POST":
106
- file = request.files.get("file")
107
- if file is None or file.filename == "":
108
- return redirect(request.url)
109
-
110
- file_path = os.path.join(app.config["UPLOAD_FOLDER"], file.filename)
111
- file.save(file_path)
112
-
113
- # Preprocess & predict
114
- img_rgb, img_input = preprocess_image(file_path)
115
- preds = best_model.predict(img_input)
116
- class_idx = np.argmax(preds, axis=1)[0]
117
- class_label = CLASS_LABELS[class_idx]
118
- confidence = preds[0][class_idx]
119
-
120
- # Update stats & log
121
- stats[class_label] = stats.get(class_label, 0) + 1
122
- log_prediction(class_label)
123
-
124
- # Determine bin type
125
- if class_label in RECYCLABLE:
126
- bin_type = "Recyclable ♻️"
127
- elif class_label in NON_RECYCLABLE:
128
- bin_type = "Non-Recyclable 🗑️"
129
- else:
130
- bin_type = "Unknown ⚠️"
131
-
132
- return render_template(
133
- "result.html",
134
- image=file.filename,
135
- label=class_label,
136
- confidence=f"{confidence*100:.2f}%",
137
- bin_type=bin_type
138
- )
139
-
140
- return render_template("index.html")
141
-
142
-
143
- @app.route("/stats")
144
- def show_stats():
145
- if stats:
146
- categories = list(stats.keys())
147
- counts = list(stats.values())
148
- plt.figure(figsize=(6, 4))
149
- plt.bar(categories, counts)
150
- plt.xlabel("Category")
151
- plt.ylabel("Count")
152
- plt.title("Waste Classification Statistics")
153
- plt.tight_layout()
154
- plt.savefig("static/stats_chart.png") # Safe with Agg backend
155
- plt.close()
156
- return render_template("report.html", stats=stats)
157
-
158
-
159
- @app.route("/download_pdf")
160
- def download_pdf():
161
- pdf_path = generate_pdf_report()
162
- return send_file(pdf_path, as_attachment=True)
163
-
164
-
165
- @app.route("/download_csv")
166
- def download_csv():
167
- return send_file("waste_log.csv", as_attachment=True)
168
-
169
- # -----------------------------
170
- # Run Flask (useful locally)
171
- if __name__ == "__main__":
172
- port = int(os.environ.get("PORT", 8080))
173
- app.run(host="0.0.0.0", port=port, debug=True)
 
1
+ import os, tempfile
2
+ import cv2
3
+ import numpy as np
4
+ import pandas as pd
5
+ from datetime import datetime
6
+ from flask import Flask, render_template, request, redirect, send_file
7
+ from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
8
+ from tensorflow.keras.models import load_model
9
+ from fpdf import FPDF
10
+ import matplotlib.pyplot as plt
11
+
12
+ # -----------------------------
13
+ # Environment fixes for Hugging Face
14
+ # -----------------------------
15
+ # Fix matplotlib cache dir
16
+ os.environ["MPLCONFIGDIR"] = "/tmp/matplotlib"
17
+ os.makedirs("/tmp/matplotlib", exist_ok=True)
18
+
19
+ # Uploads go into /tmp
20
+ UPLOAD_DIR = os.path.join(tempfile.gettempdir(), "uploads")
21
+ os.makedirs(UPLOAD_DIR, exist_ok=True)
22
+
23
+ # Logs and reports also in /tmp
24
+ LOG_PATH = os.path.join(tempfile.gettempdir(), "waste_log.csv")
25
+ REPORT_PDF = os.path.join(tempfile.gettempdir(), "waste_report.pdf")
26
+ CHART_PATH = os.path.join(tempfile.gettempdir(), "stats_chart.png")
27
+
28
+ # -----------------------------
29
+ # Flask App Config
30
+ # -----------------------------
31
+ app = Flask(__name__)
32
+ app.config["UPLOAD_FOLDER"] = UPLOAD_DIR
33
+
34
+ # -----------------------------
35
+ # Model path
36
+ # -----------------------------
37
+ MODEL_DIR = "model"
38
+ os.makedirs(MODEL_DIR, exist_ok=True)
39
+ MODEL_PATH = os.path.join(MODEL_DIR, "efficientnet_b0_best.keras")
40
+
41
+ if not os.path.exists(MODEL_PATH):
42
+ raise FileNotFoundError(f"Model file not found at {MODEL_PATH}. Place your .keras model in /model.")
43
+
44
+ best_model = load_model(MODEL_PATH)
45
+
46
+ IMG_SIZE = 128
47
+
48
+ # Class labels
49
+ CLASS_LABELS = ['biological', 'brown-glass', 'cardboard', 'green-glass',
50
+ 'metal', 'paper', 'plastic', 'shoes', 'trash', 'white-glass']
51
+
52
+ # Waste categories
53
+ RECYCLABLE = ["brown-glass", "green-glass", "white-glass", "metal", "plastic", "paper", "cardboard"]
54
+ NON_RECYCLABLE = ["trash", "biological", "shoes"]
55
+
56
+ # Initialize statistics
57
+ stats = {}
58
+
59
+ # -----------------------------
60
+ # Preprocess image
61
+ def preprocess_image(file_path):
62
+ img = cv2.imread(file_path)
63
+ img_rgb = cv2.cvtColor(cv2.resize(img, (IMG_SIZE, IMG_SIZE)), cv2.COLOR_BGR2RGB)
64
+ img_input = preprocess_input(img_rgb.astype("float32"))
65
+ img_input = np.expand_dims(img_input, axis=0)
66
+ return img_rgb, img_input
67
+
68
+ # -----------------------------
69
+ # Log predictions
70
+ def log_prediction(class_label):
71
+ log_df = pd.DataFrame([[datetime.now(), class_label]], columns=["Timestamp", "Class"])
72
+ try:
73
+ old_df = pd.read_csv(LOG_PATH)
74
+ new_df = pd.concat([old_df, log_df], ignore_index=True)
75
+ except FileNotFoundError:
76
+ new_df = log_df
77
+ new_df.to_csv(LOG_PATH, index=False)
78
+
79
+ # -----------------------------
80
+ # PDF Report
81
+ def generate_pdf_report():
82
+ pdf = FPDF()
83
+ pdf.add_page()
84
+ pdf.set_font("Arial", size=14)
85
+ pdf.cell(200, 10, txt="Waste Classification Report", ln=True, align="C")
86
+ pdf.ln(10)
87
+
88
+ total_items = sum(stats.values()) if stats else 0
89
+ pdf.set_font("Arial", size=12)
90
+ pdf.cell(0, 10, txt=f"Total Items Processed: {total_items}", ln=True)
91
+
92
+ for category, count in stats.items():
93
+ pdf.cell(0, 10, txt=f"{category}: {count}", ln=True)
94
+
95
+ pdf.output(REPORT_PDF)
96
+ return REPORT_PDF
97
+
98
+ # -----------------------------
99
+ # Routes
100
+ @app.route("/", methods=["GET", "POST"])
101
+ def index():
102
+ if request.method == "POST":
103
+ file = request.files.get("file")
104
+ if file is None or file.filename == "":
105
+ return redirect(request.url)
106
+
107
+ file_path = os.path.join(app.config["UPLOAD_FOLDER"], file.filename)
108
+ file.save(file_path)
109
+
110
+ # Preprocess & predict
111
+ img_rgb, img_input = preprocess_image(file_path)
112
+ preds = best_model.predict(img_input)
113
+ class_idx = np.argmax(preds, axis=1)[0]
114
+ class_label = CLASS_LABELS[class_idx]
115
+ confidence = preds[0][class_idx]
116
+
117
+ # Update stats & log
118
+ stats[class_label] = stats.get(class_label, 0) + 1
119
+ log_prediction(class_label)
120
+
121
+ # Determine bin type
122
+ if class_label in RECYCLABLE:
123
+ bin_type = "Recyclable ♻️"
124
+ elif class_label in NON_RECYCLABLE:
125
+ bin_type = "Non-Recyclable 🗑️"
126
+ else:
127
+ bin_type = "Unknown ⚠️"
128
+
129
+ return render_template(
130
+ "result.html",
131
+ image=file.filename,
132
+ label=class_label,
133
+ confidence=f"{confidence*100:.2f}%",
134
+ bin_type=bin_type
135
+ )
136
+
137
+ return render_template("index.html")
138
+
139
+
140
+ @app.route("/stats")
141
+ def show_stats():
142
+ if stats:
143
+ categories = list(stats.keys())
144
+ counts = list(stats.values())
145
+ plt.figure(figsize=(6, 4))
146
+ plt.bar(categories, counts)
147
+ plt.xlabel("Category")
148
+ plt.ylabel("Count")
149
+ plt.title("Waste Classification Statistics")
150
+ plt.tight_layout()
151
+ plt.savefig(CHART_PATH)
152
+ plt.close()
153
+ return render_template("report.html", stats=stats, chart_path=CHART_PATH)
154
+
155
+
156
+ @app.route("/download_pdf")
157
+ def download_pdf():
158
+ pdf_path = generate_pdf_report()
159
+ return send_file(pdf_path, as_attachment=True)
160
+
161
+
162
+ @app.route("/download_csv")
163
+ def download_csv():
164
+ return send_file(LOG_PATH, as_attachment=True)
165
+
166
+ # -----------------------------
167
+ # Run Flask (useful locally)
168
+ if __name__ == "__main__":
169
+ port = int(os.environ.get("PORT", 8080))
170
+ app.run(host="0.0.0.0", port=port, debug=True)