Spaces:
Sleeping
Sleeping
File size: 6,638 Bytes
21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da 21c551e da622da |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
import os
import numpy as np
import tensorflow as tf
from flask import Flask, request, render_template, jsonify
from tensorflow.keras.utils import load_img, img_to_array
from werkzeug.utils import secure_filename
from datetime import datetime
from huggingface_hub import hf_hub_download # Crucial for downloading model from HF Hub
import time # Used for potential retry logic, though not explicitly in hf_hub_download here
app = Flask(__name__)
# --- Model Loading Configuration ---
MODEL_FILE_NAME = "model.keras"
# IMPORTANT: Replace "YOUR_USERNAME/garbage-detection-model" with the actual REPO ID of YOUR MODEL on Hugging Face Hub.
# This is the repository where your 'model.keras' file is stored.
# Example: "your_huggingface_username/your_model_repo_name"
MODEL_REPO_ID = "nonamelife/garbage-detection-model" # <--- MAKE SURE THIS IS YOUR CORRECT MODEL REPO ID!
model = None # Initialize model as None
# --- Model Loading Logic ---
try:
print(f"Attempting to download '{MODEL_FILE_NAME}' from Hugging Face Hub ({MODEL_REPO_ID})...")
# hf_hub_download returns the FULL PATH to the downloaded file in the cache.
# We specify local_dir within /app to ensure write permissions and consistency.
# local_dir_use_symlinks=False is important for Docker environments to avoid symlink issues.
downloaded_model_path = hf_hub_download(
repo_id=MODEL_REPO_ID,
filename=MODEL_FILE_NAME,
local_dir="/app/.cache/huggingface/models", # This directory will be created if it doesn't exist
local_dir_use_symlinks=False
)
print(f"'{MODEL_FILE_NAME}' downloaded successfully to: {downloaded_model_path}")
# Now, load the model directly from the downloaded path.
# This check is a safeguard, as hf_hub_download should ensure existence.
if os.path.exists(downloaded_model_path):
model = tf.keras.models.load_model(downloaded_model_path)
print("Model loaded successfully!")
else:
# This message indicates a very unusual state if download was reported successful.
print(f"ERROR: Download reported success, but file not found at expected path: {downloaded_model_path}")
except Exception as e:
# Catch any exceptions during download or loading and log them.
print(f"FATAL: Could not download or load model from Hugging Face Hub: {e}")
model = None # Ensure model remains None if there's an error
# --- End Model Loading Logic ---
# Configurations for Flask app
UPLOAD_FOLDER = os.path.join('static', 'uploads')
ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png'}
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
# Ensure the uploads directory exists within the container
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
def allowed_file(filename):
"""Checks if the uploaded file has an allowed extension."""
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
def preprocess_image(image_path):
"""Loads and preprocesses an image for model prediction."""
img = load_img(image_path, target_size=(224, 224)) # Load image, resize to 224x224
img_array = img_to_array(img) / 255.0 # Convert to array and normalize pixel values
return np.expand_dims(img_array, axis=0) # Add batch dimension for model input
# --- Flask Routes ---
@app.route('/')
def index():
"""Renders the home page."""
return render_template('home.html')
@app.route('/tool')
def tool():
"""Renders the image upload tool page."""
return render_template('tool.html')
@app.route('/about')
def about():
"""Renders the about page."""
return render_template('about.html')
@app.route('/contact')
def contact():
"""Renders the contact page."""
return render_template('contact.html')
@app.route('/predict', methods=['POST'])
def predict():
"""Handles image uploads and returns predictions."""
# Check if the model was loaded successfully at startup
if model is None:
return jsonify({'error': 'Model not loaded. Please check server logs.'}), 500
# Check if a file was part of the request
if 'file' not in request.files:
return jsonify({'error': 'No files uploaded'}), 400
files = request.files.getlist('file')
if not files or all(f.filename == '' for f in files):
return jsonify({'error': 'No files selected'}), 400
results = []
for file in files:
file_path = None
if file and allowed_file(file.filename):
# Secure filename and create a unique name to prevent collisions
filename = secure_filename(file.filename)
timestamp = datetime.now().strftime("%Y%m%d%H%M%S%f")
unique_filename = f"{timestamp}_{filename}"
file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
file.save(file_path) # Save the uploaded file temporarily
try:
img_array = preprocess_image(file_path) # Preprocess the image
prediction = model.predict(img_array)[0][0] # Get prediction from the model
# Determine label and confidence based on sigmoid output
label = "Dirty" if prediction > 0.5 else "Clean"
confidence = prediction if label == "Dirty" else 1 - prediction
results.append({
'label': label,
'confidence': f"{confidence:.2%}", # Format confidence as percentage
'image_url': f"/static/uploads/{unique_filename}" # URL for displaying the image
})
except Exception as e:
# Catch any errors during prediction or processing
results.append({
'label': 'Error',
'confidence': 'N/A',
'image_url': None,
'error': str(e)
})
else:
# Handle invalid file types
results.append({
'label': 'Error',
'confidence': 'N/A',
'image_url': None,
'error': f"Invalid file type: {file.filename}"
})
# Render the results page with predictions
return render_template('results.html', results=results)
# --- Main execution block ---
if __name__ == '__main__':
# Hugging Face Spaces sets the PORT environment variable for the app to listen on.
# We default to 7860 as it's common for HF Spaces apps.
# Debug mode should be OFF for production deployments (like Hugging Face Spaces) for security.
port = int(os.environ.get('PORT', 7860))
app.run(host='0.0.0.0', port=port, debug=False) |