Forums

app.py doenst run

hey all im trying to deploy my app.py i made with mobilenet a "model" that is trained on pictures of missing cats in or hometown. it works fine (on my pc ofcourse ) so i want to deploy it. i saw multiple tuts and dont use the app.run part , i read about it. i created a flask app etc etc use a env for the packages. now when i try to upload a picture to check if there is a match , it take a lot of time and then i get the message Error: unexpected server response

i wil show my (search in missing cats) code ;) i hope someone can help me. its the first time i try to deploy something so this is pretty new for me

from flask import Flask, request, jsonify, send_from_directory
import os
from torch import load, no_grad, device, max, topk  # Import only the required parts of torch
from torch.nn import Sequential, Linear, ReLU, Dropout  # Import specific layers
from torch.nn.functional import softmax  # Import softmax function
from torchvision.transforms import Compose, Resize, ToTensor, Normalize  # Import specific transforms
from torchvision.models import mobilenet_v2  # Import only the required model
from PIL import Image
import sqlite3

app = Flask(__name__)

# Directory configurations
UPLOAD_FOLDER = 'uploads'
MODEL_PATH = 'AppModel_with_classes_Epoch_150_Epoch_15.pt'
DB_PATH = 'missing_cats.db'
CAT_IMAGES_DIR = 'https://atelierhenger.nl/APP/cat_images/'
INDEX_HTML_PATH = '.'

# Ensure required directories exist
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
if not os.path.exists(CAT_IMAGES_DIR):
    print(f"Warning: {CAT_IMAGES_DIR} directory does not exist. Please create it and add the images.")

# Load the model
def load_model():
    model = mobilenet_v2(weights=None)

    # Extract the number of classes from the checkpoint
    checkpoint = load(MODEL_PATH, map_location=device('cpu'))  # Use torch.load
    num_cat_classes = len(checkpoint['class_to_idx'])
    num_ras_classes = checkpoint.get('num_ras_classes', 0)  # Default to 0 if missing
    num_color_classes = checkpoint.get('num_color_classes', 0)  # Default to 0 if missing
    total_output_classes = num_cat_classes + num_ras_classes + num_color_classes

    # Adjust the classifier layer dynamically
    model.classifier = Sequential(
        Linear(model.last_channel, 512),
        ReLU(),
        Dropout(0.5),
        Linear(512, total_output_classes)  # Dynamically set the output size
    )

    # Load the state_dict
    model.load_state_dict(checkpoint['model_state_dict'])
    model.eval()

    # Add readable idx_to_ras and idx_to_color mappings
    checkpoint['idx_to_ras'] = {
        0: 'Bengaal',
        1: 'Boskat X',
        2: 'Brits korthaar',
        3: 'Brits korthaar X',
        4: 'Europese korthaar of huiskat',
        5: 'Heilige Birmaan',
        6: 'Kruising',
        7: 'Langharig',
        8: 'Maine Coon',
        9: 'Maine Coon X',
        10: 'Overige rassen',
        11: 'Perzische',
        12: 'Perzische X',
        13: 'Ragdoll',
        14: 'Scottish Fold',
        15: 'Siamees',
        16: 'Somali',
        17: 'Turkse Angora X',
        18: 'Turkse Van'
    }

    checkpoint['idx_to_color'] = {
        0: 'Beige',
        1: 'Beige met wit',
        2: 'Bruin',
        3: 'Colourpoint blue point',
        4: 'Colourpoint lilac point',
        5: 'Colourpoint red point',
        6: 'Colourpoint seal point',
        7: 'Cypers bruin-zwart (gestreept)',
        8: 'Cypers bruin-zwart (gestreept) met wit',
        9: 'Cypers grijs (gestreept) met rood en wit',
        10: 'Cypers grijs-zwart (gestreept)',
        11: 'Cypers grijs-zwart (gestreept) met wit',
        12: 'Cypers rood (gestreept)',
        13: 'Cypers rood (gestreept) met wit',
        14: 'Grijs',
        15: 'Grijs met wit',
        16: 'Lapje',
        17: 'Rood',
        18: 'Rood met wit',
        19: 'Schildpad',
        20: 'Schildpad met wit',
        21: 'Sealpoint',
        22: 'Shaded silver',
        23: 'Wildkleur (met wit)',
        24: 'Wit',
        25: 'Wit met bruin',
        26: 'Wit met cypers bruin',
        27: 'Wit met cypers grijs',
        28: 'Wit met cypers rood',
        29: 'Wit met grijs',
        30: 'Wit met rood',
        31: 'Wit met zwart',
        32: 'Zwart',
        33: 'Zwart met wit'
    }

    return model, checkpoint

model, checkpoint = load_model()

# Define transformations
transform = Compose([
    Resize((224, 224)),
    ToTensor(),
    Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])

# Fetch metadata from the database
def get_cat_metadata(cat_number):
    try:
        conn = sqlite3.connect(DB_PATH)
        cursor = conn.cursor()
        query = "SELECT * FROM cats WHERE cat_number = ?"
        cursor.execute(query, (cat_number,))
        result = cursor.fetchone()
        column_names = [description[0] for description in cursor.description]
        conn.close()

        if result:
            metadata = dict(zip(column_names, result))
            # Check for images inside the folder for the cat_number
            supported_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
            base_url = f"https://atelierhenger.nl/APP/cat_images/{cat_number}/"

            # Dynamically check for the first valid image in the folder
            for ext in supported_extensions:
                potential_url = f"{base_url}1{ext}"  # Always use the first image (e.g., 1.jpg, 1.png)
                metadata['image_url'] = potential_url
                break  # Use the first valid image found

            return metadata
        else:
            return None
    except sqlite3.Error as e:
        return {"error": str(e)}

@app.route('/')
def home():
    return send_from_directory('.', 'index.html')

@app.route('/upload', methods=['POST', 'GET'])
def upload_file():
    if request.method == 'GET':
        return '''
        <h1>Upload Endpoint</h1>
        <p>Send a POST request with an image file to this endpoint to check for matches.</p>
        '''
    try:
        if 'image' not in request.files:
            return jsonify({'error': 'No file uploaded'}), 400

        file = request.files['image']
        if file.filename == '':
            return jsonify({'error': 'No selected file'}), 400

        file_path = os.path.join(UPLOAD_FOLDER, file.filename)
        file.save(file_path)

        image = Image.open(file_path).convert('RGB')
        input_tensor = transform(image).unsqueeze(0)

        with no_grad():
            output = model(input_tensor)
            num_cat_classes = len(checkpoint['class_to_idx'])
            num_ras_classes = checkpoint['num_ras_classes']
            num_color_classes = checkpoint['num_color_classes']

            outputs_cat = output[:, :num_cat_classes]
            outputs_ras = output[:, num_cat_classes:num_cat_classes + num_ras_classes]
            outputs_color = output[:, num_cat_classes + num_ras_classes:]

            ras_confidence, ras_class = max(softmax(outputs_ras, dim=1), dim=1)
            color_confidence, color_class = max(softmax(outputs_color, dim=1), dim=1)

            predicted_ras = checkpoint['idx_to_ras'][ras_class.item()]
            predicted_color = checkpoint['idx_to_color'][color_class.item()]

            matches = []
            softmax_cat = softmax(outputs_cat, dim=1)
            topk_values, topk_indices = topk(softmax_cat, k=15, dim=1)
            for idx, confidence in zip(topk_indices[0].tolist(), topk_values[0].tolist()):
                cat_number = list(checkpoint['class_to_idx'].keys())[list(checkpoint['class_to_idx'].values()).index(idx)]
                metadata = get_cat_metadata(cat_number)
                if metadata:
                    metadata['confidence'] = f"{confidence * 100:.2f}"
                    matches.append(metadata)

            filtered_matches = [match for match in matches if match['ras'] == predicted_ras]
            sorted_matches = sorted(filtered_matches, key=lambda x: float(x['confidence']), reverse=True)

        return jsonify({
            'predicted_ras': predicted_ras,
            'predicted_ras_confidence': f"{ras_confidence.item() * 100:.2f}",
            'predicted_color': predicted_color,
            'predicted_color_confidence': f"{color_confidence.item() * 100:.2f}",
            'matches': sorted_matches
        })

    except Exception as e:
        print(f"Error processing the request: {e}")
        return jsonify({'error': 'An error occurred while processing the image.', 'details': str(e)}), 500

[edit by admin: formatting]

The first thing to check for website errors is the website's error log. There's a link to it on the "Web" page inside PythonAnywhere, and the most recent error will be at the bottom of the file.

Thanks for answering. the log files show processing the image , but i get the message 502. after a lot of trying i change my script a littile and now its works!!

set_num_threads(1) from torch import load, no_grad, device, max, topk, set_num_threads # Import set_num_threads

this did the trick , and using : def add_security_headers(response): response.headers['Content-Security-Policy'] = ( "default-src 'self'; " "script-src 'self' 'unsafe-inline'; " "style-src 'self' 'unsafe-inline'; " "connect-src 'self'; " "frame-src 'none'; " "object-src 'none'; " "base-uri 'self'; " "form-action 'self';"

i hope maybe this will help people who have the same problem