Web application for Digit Recognition with CNN not working. Canvas isn’t showing

I’m currently trying to implement my trained CNN for Digit Recognition in a web application, where I can draw a number on a canvas and let my network predict which number it is. Therefore I trained a CNN with TensorFlow and converted it with Tensorflow JS. I now wrote a html and a JavaScript file for the web application. But it doesn’t work. I’m not even getting the canvas displayed and although I included Tensorflow in the html tag it complains in the JS script.

Here is all my code:
The network:

import os
import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow import keras
from tensorflow.python.keras.callbacks import TensorBoard
from keras.utils import to_categorical
from keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from keras.models import Sequential
from sklearn.model_selection import train_test_split
import datetime

# Load the dataset and preprocess the images
df = pd.read_csv("mnist_dataset.csv")
X = df.iloc[:, 1:].values.reshape(-1, 28, 28, 1)
X = X.astype("float32") / 255.0
y = to_categorical(df.iloc[:, 0])

# Split the dataset into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)

# Build the CNN model
model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3), activation="relu", input_shape=(28, 28, 1)))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Conv2D(64, kernel_size=(3, 3), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(128, activation="relu"))
model.add(Dense(10, activation="softmax"))

# Compile and train the model
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])

# Tensorboard
log_dir = "logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)

# Save model for later
checkpoint_path = "training_1/cp.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

# Create a callback that saves the model's weights
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_path,
                                                 save_weights_only=True,
                                                 verbose=1)


model.fit(X_train, y_train, epochs=10, batch_size=32, callbacks=[tensorboard_callback, cp_callback])

# Evaluate the model on the test set
print('n')
loss, accuracy = model.evaluate(X_test, y_test)
print("Loss:", loss)
print("Accuracy:", accuracy)

model.summary()

# Save the entire model as a SavedModel.
model.save('saved_model/my_model')

The html-File:

<!-- HTML for the web page -->
<html>
  <head>
    <title>Handwritten Digit Recognition</title>
  </head>
  <body>
    <h1>Handwritten Digit Recognition</h1>
    <p>Draw a digit in the box below:</p>
    <canvas id="canvas" width="280" height="280"></canvas>
    <br />
    <button id="predict-button">Predict</button>
    <button id="clear-button">Clear</button>
    <br />
    <p>Prediction: <span id="prediction"></span></p>
  </body>
  <script src="https://cdn.jsdelivr.net/npm/@tensorflow/[email protected]/dist/tf.min.js"></script>
  <script src="app.js"></script>
</html>

And the .js file:

// JavaScript for the web page

// Load the trained CNN model
const modelUrl =
  "https://tfhub.dev/google/tfjs-model/imagenet/mobilenet_v1_100_224/classification/2";
const model = await tf.loadLayersModel(modelUrl);

// Preprocess the user's drawing
const preprocess = (image) => {
  // Convert to grayscale
  const gray = tf.image.rgbToGrayscale(image);

  // Resize to match model input size
  const resized = tf.image.resizeBilinear(gray, [28, 28]);

  // Normalize pixel values
  const normalized = resized.div(255.0);

  // Add a batch dimension
  const batched = normalized.expandDims(0);

  return batched;
};

// Handle the user's prediction request
const handlePredictClick = async () => {
  // Get the user's drawing from the canvas
  const image = getImageFromCanvas();

  // Preprocess the image
  const input = preprocess(image);

  // Use the CNN to make a prediction
  const prediction = model.predict(input);

  // Display the prediction in the web page
  const element = document.getElementById("prediction");
  element.innerHTML = prediction;
};

// Clear the canvas
const handleClearClick = () => {
  clearCanvas();
};

// Attach event listeners to the canvas and buttons
const canvas = document.getElementById("canvas");
canvas.addEventListener("mousedown", startDrawing);
canvas.addEventListener("mousemove", continueDrawing);
canvas.addEventListener("mouseup", stopDrawing);

const predictButton = document.getElementById("predict-button");
predictButton.addEventListener("click", handlePredictClick);

const clearButton = document.getElementById("clear-button");
clearButton.addEventListener("click", handleClearClick);

// Function to get the image data for the canvas
const getImageFromCanvas = () => {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
  const data = imageData.data;
  const tensor = tf.tensor3d(data, [canvas.height, canvas.width, 4]);
  return tensor;
};

let isDrawing = false;
let currentX = 0;
let currentY = 0;

const startDrawing = (event) => {
  isDrawing = true;
  currentX = event.offsetX;
  currentY = event.offsetY;
};

const continueDrawing = (event) => {
  if (isDrawing) {
    const canvas = document.getElementById("canvas");
    const context = canvas.getContext("2d");
    context.moveTo(currentX, currentY);
    context.lineTo(event.offsetX, event.offsetY);
    context.stroke();
    currentX = event.offsetX;
    currentY = event.offsetY;
  }
};

const stopDrawing = () => {
  isDrawing = false;
};

const clearCanvas = () => {
  const canvas = document.getElementById("canvas");
  const context = canvas.getContext("2d");
  context.clearRect(0, 0, canvas.width, canvas.height);
};

Right now the model url is not my network. I still have to upload it to a Webserver, but it should also work with the dummy network I inserted.

The current page looks like this:

Current state of the web application

And the development environment shows this error:

Development environment

I checked the Tensorflow tag in the html file for spelling mistakes, but it corresponds with the documentation on Tensorflow.
I asked ChatGPT for a possible error, but it said the code looked fine and should work. So something has to be wrong here.

Help is very much appreciated.
Thank you all in advance and have a nice day.