I am doing character level cnn on phishing url dataset.There is 50% phishing and 50% non phishing links in the dataset. Help me make this model better, and also include metrics such as f1 scores and others. Include visualizations like graphs to be inputted in my journal regarding this model. Give me the entire code.
Current implementation:
# Import necessary packages
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.metrics import classification_report, confusion_matrix
from imblearn.over_sampling import SMOTE  # Install using `pip install imblearn`
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense, Dropout
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint

# Read data
data = pd.read_csv('dataset_phishing.csv')

# Define features and target
features = ['shortest_word_path', 'ratio_intMedia', 'links_in_tags', 'nb_hyphens', 'page_rank',
            'avg_word_path', 'ratio_extHyperlinks', 'longest_words_raw', 'google_index',
            'length_hostname', 'longest_word_host', 'domain_registration_length', 'nb_www',
            'nb_underscore', 'nb_dots', 'ratio_extMedia', 'phish_hints', 'domain_in_title',
            'web_traffic', 'safe_anchor', 'nb_space', 'shortening_service', 'ip',
            'domain_age', 'nb_qm', 'nb_hyperlinks', 'nb_slash']

X = data[features]
y = data['status']  # 'status' column: 1 for phishing, 0 for legitimate

# Handle missing values
X.fillna(0, inplace=True)

# Encode labels
label_encoder = LabelEncoder()
y_encoded = label_encoder.fit_transform(y)

# Handle class imbalance using SMOTE
smote = SMOTE(random_state=42)
X_resampled, y_resampled = smote.fit_resample(X, y_encoded)

# Scale features
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_resampled)

# Reshape data for Conv1D
X_reshaped = np.expand_dims(X_scaled, axis=2)

# Split data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(
    X_reshaped, y_resampled, test_size=0.2, random_state=42)

# Define CNN model with improved architecture
model = Sequential([
    Conv1D(filters=64, kernel_size=3, activation='relu', input_shape=(X_reshaped.shape[1], 1)),
    MaxPooling1D(pool_size=2),
    Dropout(0.3),
    Conv1D(filters=128, kernel_size=3, activation='relu'),
    MaxPooling1D(pool_size=2),
    Dropout(0.3),
    Flatten(),
    Dense(128, activation='relu'),
    Dropout(0.4),
    Dense(1, activation='sigmoid')  # Binary classification
])

# Compile the model
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

# Define callbacks
early_stopping = EarlyStopping(monitor='val_loss', patience=5, verbose=1)
model_checkpoint = ModelCheckpoint('best_model_improved.keras', monitor='val_accuracy',
                                   save_best_only=True, verbose=1)

# Train the model
history = model.fit(
    X_train, y_train,
    epochs=50,
    batch_size=64,
    validation_data=(X_test, y_test),
    callbacks=[early_stopping, model_checkpoint]
)

# Load the best saved model weights
model.load_weights('best_model_improved.keras')

# Evaluate the model
loss, accuracy = model.evaluate(X_test, y_test)
print(f"Test Accuracy: {accuracy:.4f}")

# Predict on test data
y_pred_prob = model.predict(X_test)
y_pred = (y_pred_prob > 0.5).astype(int).flatten()

# Classification report
print(classification_report(y_test, y_pred))

# Confusion matrix
conf_matrix = confusion_matrix(y_test, y_pred)
print("Confusion Matrix:")
print(conf_matrix)