UdaraChamidu commited on
Commit
ec30e75
·
verified ·
1 Parent(s): c5409ee

Upload 6 files

Browse files
Files changed (7) hide show
  1. .dockerignore +13 -0
  2. .gitattributes +1 -0
  3. Dockerfile +42 -0
  4. app.py +173 -0
  5. efficientnet_b0_best.keras +3 -0
  6. mobilenet_trash.pkl +3 -0
  7. requirement.txt +10 -0
.dockerignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__
2
+ *.pyc
3
+ *.pyo
4
+ *.pyd
5
+ .env
6
+ .git
7
+ .gitignore
8
+ *.keras
9
+ *.h5
10
+ *.ckpt
11
+ *.ckpt.index
12
+ .vscode
13
+ .idea
.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
+ efficientnet_b0_best.keras filter=lfs diff=lfs merge=lfs -text
Dockerfile ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use official Python slim image
2
+ FROM python:3.11-slim
3
+
4
+ # Prevent Python from writing .pyc files and buffer stdout/stderr
5
+ ENV PYTHONDONTWRITEBYTECODE=1
6
+ ENV PYTHONUNBUFFERED=1
7
+
8
+ # Set working dir
9
+ WORKDIR /app
10
+
11
+ # Install system dependencies required for OpenCV and fonts, etc.
12
+ RUN apt-get update && apt-get install -y --no-install-recommends \
13
+ build-essential \
14
+ wget \
15
+ ca-certificates \
16
+ ffmpeg \
17
+ libsm6 \
18
+ libxext6 \
19
+ libxrender1 \
20
+ libglib2.0-0 \
21
+ && apt-get clean && rm -rf /var/lib/apt/lists/*
22
+
23
+ # Copy requirements first for better caching
24
+ COPY requirements.txt /app/requirements.txt
25
+
26
+ # Upgrade pip, install dependencies
27
+ RUN pip install --upgrade pip
28
+ RUN pip install --no-cache-dir -r /app/requirements.txt
29
+
30
+ # Copy app source code
31
+ COPY . /app
32
+
33
+ # Create model directory (if you will mount model at runtime)
34
+ RUN mkdir -p /app/model && chmod -R 755 /app/model
35
+
36
+ # Expose port that HF Spaces expects
37
+ EXPOSE 8080
38
+
39
+ # Use gunicorn to run the Flask app
40
+ # --bind 0.0.0.0:8080 to listen on all interfaces
41
+ # Adjust workers/threads according to memory (lower for HF free spaces)
42
+ CMD ["gunicorn", "--bind", "0.0.0.0:8080", "app:app", "--workers", "2", "--threads", "2", "--timeout", "120"]
app.py ADDED
@@ -0,0 +1,173 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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)
efficientnet_b0_best.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b32878e752dc023742c2622159c2df364490e26db97d36b61c5d12d6fe281c1e
3
+ size 29783632
mobilenet_trash.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:83be04a781b14ae307e6144c8a6371301e897938c4680681eaacb02588a5877b
3
+ size 9244779
requirement.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ Flask==2.3.3
2
+ numpy
3
+ opencv-python-headless
4
+ tensorflow-cpu==2.12.0
5
+ pandas
6
+ matplotlib
7
+ fpdf
8
+ scikit-learn
9
+ gunicorn
10
+ huggingface-hub # optional, only if you plan to download model at runtime from HF Hub