c.ai Neo Panel

A toggleable panel with information about the character and other stuff

// ==UserScript==
    // @name         c.ai Neo Panel
    // @namespace    c.ai Neo Panel
    // @version      3.2
    // @description  A toggleable panel with information about the character and other stuff
    // @author       vishanka
    // @license      MIT
    // @match        https://*.character.ai/chat*
    // @icon         https://i.imgur.com/iH2r80g.png
    // @grant        none
    // ==/UserScript==


(function() {
    'use strict';

    var original_prototype_open = XMLHttpRequest.prototype.open;
    const intercepted_data_object = {};

    XMLHttpRequest.prototype.open = function(method, url, async) {
        if (
            url.startsWith('https://plus.character.ai/chat/history/continue/') ||
            url.startsWith('https://plus.character.ai/chat/character/info') ||
            url.startsWith('https://beta.character.ai/chat/history/continue/') ||
            url.startsWith('https://beta.character.ai/chat/character/info')
        ) {
            this.addEventListener('load', function() {
                let info1 = JSON.parse(this.responseText);
                intercepted_data_object.external_id = info1.character.external_id;
                console.log("character_id:",intercepted_data_object.external_id);

                let info2 = JSON.parse(this.responseText);
                intercepted_data_object.tgt = info2.character.participant__user__username;
                intercepted_data_object.name = info2.character.name;
                intercepted_data_object.participant__num_interactions = info2.character.participant__num_interactions;
                intercepted_data_object.greeting = info2.character.greeting;
                intercepted_data_object.title = info2.character.title;
                intercepted_data_object.description = info2.character.description;
                intercepted_data_object.avatar_file_name = info2.character.avatar_file_name;
                intercepted_data_object.base_img_prompt = info2.character.base_img_prompt;
                intercepted_data_object.visibility = info2.character.visibility;
                intercepted_data_object.username = info2.character.user__username;

                // Only create the toggle button and the panel once
                if (!document.getElementById('descriptionPanel')) {
                    createToggleButton();
                    createPermanentPanel();
                    createNeoPanelDelete();
                }
            });

        } else if (url.startsWith(`https://neo.character.ai/chats/recent/${intercepted_data_object.external_id}`)) {
            this.addEventListener('load', function() {
                let info3 = JSON.parse(this.responseText);
                intercepted_data_object.chat_id = info3.chats[0].chat_id;
                console.log("chat_id:",intercepted_data_object.chat_id);
            });
        } else if (url.startsWith('https://beta.character.ai/chat/user/') ||
            url.startsWith('https://plus.character.ai/chat/user/')
          ) {
            this.addEventListener('load', function() {
                let info_user = JSON.parse(this.responseText);
                intercepted_data_object.info_username = info_user.user.name;
                console.log("Username You:",intercepted_data_object.info_username);
            });
        } else if (url.startsWith(`https://neo.character.ai/turns/${intercepted_data_object.chat_id}`)) {
            this.addEventListener('load', function() {
                let info4 = JSON.parse(this.responseText);
                intercepted_data_object.turn_id = info4.turns[0].turn_key.turn_id;
                intercepted_data_object.total_turns = info4.turns.length;
                intercepted_data_object.turns_name = info4.turns[0].author.name;
                console.log("turn_id:",intercepted_data_object.turn_id);
                console.log("total_turns:", intercepted_data_object.total_turns);
                console.log("turns_name:", intercepted_data_object.turns_name);
                // Extract data from the last turn_id if there are turns
                if (intercepted_data_object.total_turns > 0) {
                  const lastTurnIndex = intercepted_data_object.total_turns - 1;
                  const lastTurnData = info4.turns[lastTurnIndex];
                  intercepted_data_object.lastTurnId = lastTurnData.turn_key.turn_id; // Store lastTurnId in intercepted_data_object
                  console.log("Last turn_id:", intercepted_data_object.lastTurnId);
                }
                // Extract candidates for "turn 0", used for fetching limit
                if (intercepted_data_object.total_turns > 0) {
                  const firstTurnData = info4.turns[0];
                  intercepted_data_object.candidatesForTurn0 = firstTurnData.candidates;
                  intercepted_data_object.numberOfCandidatesForTurn0 = intercepted_data_object.candidatesForTurn0.length;
                  console.log("Number of candidates for turn 0:", intercepted_data_object.numberOfCandidatesForTurn0);
                if (intercepted_data_object.numberOfCandidatesForTurn0 > 0) {
                  intercepted_data_object.first_raw = intercepted_data_object.candidatesForTurn0[0].raw_content;
                  console.log("Raw content of the first candidate for turn 0:", intercepted_data_object.first_raw);




                }
}

                XHR_interception_resolve(intercepted_data_object);
            });
        }
        original_prototype_open.apply(this, [method, url, async]);
    };

    let XHR_interception_resolve;
    const XHR_interception_promise = new Promise(function(resolve, reject) {
        XHR_interception_resolve = resolve;
    });

    XHR_interception_promise.then(function() {
        console.log("Intercepted Data:", intercepted_data_object);


// Fetch Command
const fetch10_commandJson = `{
    "command": "generate_turn_candidate",
    "payload": {
        "character_id": "${intercepted_data_object.external_id}",
        "turn_key": {
            "turn_id": "${intercepted_data_object.turn_id}",
            "chat_id": "${intercepted_data_object.chat_id}"
        }
    },
    "origin_id": ""
}`;

// Delete First Message
const delete_first_commandJson = `{
    "command": "remove_turns",
    "request_id": "",
    "payload": {
        "chat_id": "${intercepted_data_object.chat_id}",
        "turn_ids": ["${intercepted_data_object.lastTurnId}"]
    },
    "origin_id": ""
}`;

const delete_last_commandJson = `{
    "command": "remove_turns",
    "request_id": "",
    "payload": {
        "chat_id": "${intercepted_data_object.chat_id}",
        "turn_ids": ["${intercepted_data_object.turn_id}"]
    },
    "origin_id": ""
}`;


// Rest of the WebSocket logic (same as in your original script)
// Create Fetch Button
let disableMouseOut = false;
const fetch_button = document.createElement('button');
fetch_button.textContent = 'Fetch 10 Replies';
fetch_button.style.padding = '5px 10px';
fetch_button.style.backgroundColor = '#007bff';
fetch_button.style.borderRadius = '5px';
fetch_button.style.color = 'white';
fetch_button.style.border = 'none';
fetch_button.style.cursor = 'pointer';
fetch_button.style.transition = 'background-color 0.2s, transform 0.1s';
fetch_button.style.display = 'block';
fetch_button.style.width = '100%';
fetch_button.style.marginTop = '10px';

// Mouseover animation
fetch_button.addEventListener('mouseover', () => {
    fetch_button.style.backgroundColor = '#0056b3';
    fetch_button.style.transform = 'scale(1.0)';
});

// Mouseout animation
fetch_button.addEventListener('mouseout', () => {
    if (!disableMouseOut) {
        fetch_button.style.backgroundColor = '#007bff';
        fetch_button.style.transform = 'scale(1)';
    }
});

// Click animation and logic
fetch_button.addEventListener('click', () => {
    // Change button text and background color
    fetch_button.textContent = 'Please wait...';
    fetch_button.style.backgroundColor = 'darkgray';
    fetch_button.disabled = true; // Disable the button during fetching

    disableMouseOut = true; // Disable mouseout behavior

    fetch10();

});

// Create Delete First Button
const delete_first_message_button = createStyledButton('Delete First Message', showDeleteConfirmation);
delete_first_message_button.style.marginTop = '10px';


// Create Delete Last Button
const delete_last_message_button = createStyledButton('Delete Last Message', showDeleteLastConfirmation);
delete_last_message_button.style.marginTop = '10px';


//----------------------------------------- BUTTON FOR DELETE PANEL ----------------------------------------
// Triggert Panel aus Neo Panel Delete script
const delete_panel_button = createStyledButton('Toggle Delete Panel', toggleNeoPanelDelete);
delete_panel_button.style.marginTop = '10px';


// Append Buttons to Panel
const panel = document.getElementById('descriptionPanel');
panel.appendChild(fetch_button);
panel.appendChild(delete_first_message_button);
panel.appendChild(delete_last_message_button);
panel.appendChild(delete_panel_button);
//panel.appendChild(delete_last_message_button);


// Add reload_information to the panel
const general_information = document.createElement('p');
general_information.textContent = 'Version 3.1';
general_information.style.textAlign = 'center';
general_information.style.marginBottom = '5px';
general_information.style.setProperty('font-size', '12px', 'important'); // Set style with !important

panel.appendChild(general_information);

// Add home button to the panel
/*    const home_button = document.createElement('img');
    home_button.style.maxWidth = '15%';
    home_button.style.display = 'block'; // Ensures that the image occupies full width
    home_button.style.margin = '0 auto'; // Centers the image horizontally
    home_button.style.marginBottom = '10px';
    home_button.src = 'https://i.imgur.com/79IBd1P.png';

    panel.appendChild(home_button);
*/



// Function to create styled buttons
function createStyledButton(text, clickFunction) {
    const button = document.createElement('button');
    button.textContent = text;
    button.style.padding = '5px 10px';
    button.style.backgroundColor = '#007bff';
    button.style.borderRadius = '5px';
    button.style.color = 'white';
    button.style.border = 'none';
    button.style.cursor = 'pointer';
    button.style.transition = 'background-color 0.2s, transform 0.1s';
    button.style.display = 'block';
    button.style.width = '100%';

    // Mouseover animation
    button.addEventListener('mouseover', () => {
        button.style.backgroundColor = '#0056b3';
    });

    // Mouseout animation
    button.addEventListener('mouseout', () => {
        button.style.backgroundColor = '#007bff';
    });

    // Click animation and logic
    button.addEventListener('click', () => {
        clickFunction();
        button.style.backgroundColor = 'darkgray';
    });

    return button;
}



//--------------------------Here begins the fetching craze -------------------------------
// Initialize WebSocket
const socket = new WebSocket('wss://neo.character.ai/ws/');

socket.addEventListener('open', () => {
    console.log('Socket connection opened.');
});

socket.addEventListener('error', (error) => {
    console.error('Socket error:', error);
});

socket.addEventListener('close', () => {
    console.log('Socket connection closed.');
});


let lastWebSocketMessageTime = 0;
let fetchAlertTimeout;

// Function to handle WebSocket messages
function handleWebSocketMessage() {
    lastWebSocketMessageTime = Date.now();

    if (fetchAlertTimeout) {
        clearTimeout(fetchAlertTimeout);
    }

    fetchAlertTimeout = setTimeout(() => {
        if (shouldShowFetchAlert()) {
            const maxCandidates = 31;
            const remainingCandidates = maxCandidates - intercepted_data_object.numberOfCandidatesForTurn0;
            const candidatesToFetch = Math.min(remainingCandidates, 10);

if (candidatesToFetch > 0) {
    // Create a custom modal_fetched_messages
    const modal_fetched_messages = document.createElement('div');
    modal_fetched_messages.style.position = 'fixed';
    modal_fetched_messages.style.top = '0';
    modal_fetched_messages.style.left = '0';
    modal_fetched_messages.style.width = '100%';
    modal_fetched_messages.style.height = '100%';
    modal_fetched_messages.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
    modal_fetched_messages.style.display = 'flex';
    modal_fetched_messages.style.justifyContent = 'center';
    modal_fetched_messages.style.alignItems = 'center';
    modal_fetched_messages.style.zIndex = '9999'; // Set a higher z-index

    // Create modal_fetched_messages content
    const modal_fetched_messagesContent = document.createElement('div');
    modal_fetched_messagesContent.style.backgroundColor = '#fff';
    modal_fetched_messagesContent.style.padding = '20px';
    modal_fetched_messagesContent.style.borderRadius = '5px';
    modal_fetched_messagesContent.style.textAlign = 'center';

    // Add content to modal_fetched_messages
    const modal_fetched_messagesText = document.createElement('div');
    modal_fetched_messagesText.textContent = `${candidatesToFetch} messages fetched. Click below to reload the page.`;
    modal_fetched_messagesText.style.marginBottom = '20px';
    modal_fetched_messagesContent.appendChild(modal_fetched_messagesText);

    // Create a button within the modal_fetched_messages
    const reloadButton = document.createElement('button');
    reloadButton.textContent = 'Reload Page';
    reloadButton.style.backgroundColor = '#3E4040'; // Example button color
    reloadButton.style.color = 'white'; // Example text color
    reloadButton.style.border = 'none';
    reloadButton.style.borderRadius = '3px';
    reloadButton.style.padding = '5px 15px';

    // Add an event listener to the reload button
    reloadButton.addEventListener('click', () => {
        window.location.reload(); // Reload the page
    });

    // Add button to modal_fetched_messages content
    modal_fetched_messagesContent.appendChild(reloadButton);

    // Add modal_fetched_messages content to modal_fetched_messages
    modal_fetched_messages.appendChild(modal_fetched_messagesContent);

    // Add modal_fetched_messages to the document
    document.body.appendChild(modal_fetched_messages);
}

        }
    }, 10000);
}

// Function to determine if the fetch alert should be shown
function shouldShowFetchAlert() {
    const currentTime = Date.now();
    const timeSinceLastMessage = currentTime - lastWebSocketMessageTime;
    return timeSinceLastMessage >= 10000;
}



// Function to determine if the fetch alert should be shown
function fetch10() {
    const maxCandidates = 31;
    const command = JSON.parse(fetch10_commandJson);

if (intercepted_data_object.info_username === intercepted_data_object.turns_name) {
// ------------------- Create an extra Style for the User Message Popup
const modal_user_message = document.createElement('div');
modal_user_message.style.position = 'fixed';
modal_user_message.style.top = '0';
modal_user_message.style.left = '0';
modal_user_message.style.width = '100%';
modal_user_message.style.height = '100%';
modal_user_message.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
modal_user_message.style.display = 'flex';
modal_user_message.style.justifyContent = 'center';
modal_user_message.style.alignItems = 'center';
modal_user_message.style.zIndex = '9999'; // Set a higher z-index

// Create modal_user_message content
const modal_user_messageContent = document.createElement('div');
modal_user_messageContent.style.backgroundColor = '#fff';
modal_user_messageContent.style.padding = '20px';
modal_user_messageContent.style.borderRadius = '5px';
modal_user_messageContent.style.textAlign = 'center';

// Add content to modal_user_message
const modal_user_messageText = document.createElement('div');
modal_user_messageText.textContent = `You tried to fetch on a user message. Reload or generate a reply.`;
modal_user_messageText.style.marginBottom = '20px';
modal_user_messageContent.appendChild(modal_user_messageText);

// Create reload button
const reloadButton = document.createElement('button');
reloadButton.textContent = 'Reload Page';
reloadButton.style.marginRight = '10px';
reloadButton.style.backgroundColor = 'red'; // Example button color
reloadButton.style.color = 'white'; // Example text color
reloadButton.style.border = 'none';
reloadButton.style.borderRadius = '3px';
reloadButton.style.padding = '5px 15px';

// Add event listener to reload button
reloadButton.addEventListener('click', () => {
    window.location.reload(); // Reload the page
});

// Create cancel button
const cancelButton = document.createElement('button');
cancelButton.textContent = 'Cancel';
cancelButton.style.backgroundColor = '#DDDDDD'; // Example button color
cancelButton.style.border = 'none';
cancelButton.style.borderRadius = '3px';
cancelButton.style.padding = '5px 15px';

// Add event listener to cancel button
cancelButton.addEventListener('click', () => {
    modal_user_message.remove(); // Remove the modal
    fetch_button.textContent = 'Fetch 10 Replies';
    fetch_button.style.backgroundColor = '#007bff';
});

// Add buttons to modal_user_message content
modal_user_messageContent.appendChild(reloadButton);
modal_user_messageContent.appendChild(cancelButton);

// Add modal_user_message content to modal_user_message
modal_user_message.appendChild(modal_user_messageContent);

// Add modal_user_message to the document
document.body.appendChild(modal_user_message);

// ------------------- END Create an extra Style for the User Message Popup
    fetch_button.textContent = 'Reload Page Please';
    fetch_button.disabled = false; // Disable the button during fetching
    disableMouseOut = true; // Disable mouseout behavior
}
 else {

        proceedWithFetch();
        observer.disconnect(); // Disconnect the observer after finding the text



        const observer = new MutationObserver(performTextSearch);
        observer.observe(document, { subtree: true, childList: true });


    }
}


// Function to proceed with the fetch logic
function proceedWithFetch() {
    const maxCandidates = 31;
    const command = JSON.parse(fetch10_commandJson);

    if (intercepted_data_object.numberOfCandidatesForTurn0 < maxCandidates) {
        const remainingCandidates = maxCandidates - intercepted_data_object.numberOfCandidatesForTurn0;
        const candidatesToFetch = Math.min(remainingCandidates, 10);
        for (let i = 0; i < candidatesToFetch; i++) {
            sendSocketMessage(socket, command, false);
        }
    } else {
    clearTimeout(fetchAlertTimeout); // Clear the timeout here

    // Create a custom modal
        const modal = document.createElement('div');
        modal.style.position = 'fixed';
        modal.style.top = '0';
        modal.style.left = '0';
        modal.style.width = '100%';
        modal.style.height = '100%';
        modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
        modal.style.display = 'flex';
        modal.style.justifyContent = 'center';
        modal.style.alignItems = 'center';
        modal.style.zIndex = '9999';

        const modalContent = document.createElement('div');
        modalContent.style.backgroundColor = '#fff';
        modalContent.style.padding = '20px';
        modalContent.style.borderRadius = '5px';
        modalContent.style.textAlign = 'center';

        const modalText = document.createElement('div');
        modalText.innerHTML = 'Max swipes reached.<br>Messages fetched beyond this point will be unavailable.<br><br>Proceed?';
        modalContent.appendChild(modalText);

        const yesButton = document.createElement('button');
        yesButton.textContent = 'Confirm';
        yesButton.style.marginRight = '10px';
        yesButton.style.backgroundColor = 'red'; // Example button color
        yesButton.style.color = 'white'; // Example text color
        yesButton.style.border = 'none';
        yesButton.style.borderRadius = '3px';
        yesButton.style.padding = '5px 15px';
        yesButton.style.marginTop = '10px';

let activityTimeout;
let candidatesToFetch = 10; // You need to set this value

const modal_yes_fetch = createModal();

function createModal() {
    const modal = document.createElement('div');
    modal.style.position = 'fixed';
    modal.style.top = '0';
    modal.style.left = '0';
    modal.style.width = '100%';
    modal.style.height = '100%';
    modal.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
    modal.style.display = 'flex';
    modal.style.justifyContent = 'center';
    modal.style.alignItems = 'center';
    modal.style.zIndex = '9999';

    const modalContent = document.createElement('div');
    modalContent.style.backgroundColor = '#fff';
    modalContent.style.padding = '20px';
    modalContent.style.borderRadius = '5px';
    modalContent.style.textAlign = 'center';

    const modalText = document.createElement('div');
    modalText.textContent = `${candidatesToFetch} messages fetched. Click below to reload the page.`;
    modalText.style.marginBottom = '20px';
    modalContent.appendChild(modalText);

    const reloadButton = document.createElement('button');
    reloadButton.textContent = 'Reload Page';
    reloadButton.style.marginRight = '10px';
    reloadButton.style.backgroundColor = '#3E4040'; // Example button color
    reloadButton.style.color = 'white'; // Example text color
    reloadButton.style.border = 'none';
    reloadButton.style.borderRadius = '3px';
    reloadButton.style.padding = '5px 15px';
    reloadButton.addEventListener('click', () => {
        window.location.reload();
    });
    modalContent.appendChild(reloadButton);

    modal.appendChild(modalContent);

    return modal;
}

yesButton.addEventListener('click', () => {
    document.body.removeChild(modal);
    fetch_button.textContent = 'Please wait...';
    fetch_button.style.backgroundColor = 'darkgray';
    fetch_button.disabled = true; // Disable the button during fetching
    disableMouseOut = true; // Disable mouseout behavior
    clearTimeout(activityTimeout);

    for (let i = 0; i < candidatesToFetch; i++) {
        sendSocketMessage(socket, command, false);
    }

    activityTimeout = setTimeout(() => {
        document.body.appendChild(modal_yes_fetch);
    }, 10000);
});

socket.addEventListener('message', () => {
    clearTimeout(activityTimeout);
    activityTimeout = setTimeout(() => {
        document.body.appendChild(modal_yes_fetch);
    }, 10000);
});


        const noButton = document.createElement('button');
        noButton.textContent = 'Cancel';
        noButton.style.backgroundColor = 'gray'; // Example button color
        noButton.style.color = 'white'; // Example text color
        noButton.style.border = 'none';
        noButton.style.borderRadius = '3px';
        noButton.style.padding = '5px 15px';

        noButton.addEventListener('click', () => {
            document.body.removeChild(modal);
        });

        modalContent.appendChild(yesButton);
        modalContent.appendChild(noButton);
        modal.appendChild(modalContent);
        document.body.appendChild(modal);

        fetch_button.textContent = 'Fetch 10 Replies';
        fetch_button.style.backgroundColor = '#007bff';
        fetch_button.disabled = false;
        disableMouseOut = false;
    }
}


// Attach message event listener to the WebSocket
socket.addEventListener('message', handleWebSocketMessage);

//------------------------------------ END OF FETCHING FUNCTION------------------------------------

//------------------------------------ START OF DELETE FIRST FUNCTION------------------------------------
// Delete first message command logic
// Delete first message command logic
function deleteFirstMessage() {
    const deleteCommand = JSON.parse(delete_first_commandJson);
    sendSocketMessage(socket, deleteCommand, true); // Pass `true` for reload argument
}

// Show confirmation modal
function showDeleteConfirmation() {
    const modal_delete_first = document.createElement('div');
    modal_delete_first.style.position = 'fixed';
    modal_delete_first.style.top = '0';
    modal_delete_first.style.left = '0';
    modal_delete_first.style.width = '100%';
    modal_delete_first.style.height = '100%';
    modal_delete_first.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
    modal_delete_first.style.display = 'flex';
    modal_delete_first.style.justifyContent = 'center';
    modal_delete_first.style.alignItems = 'center';
    modal_delete_first.style.zIndex = '9999';

    const modal_content = document.createElement('div');
    modal_content.style.backgroundColor = 'white';
    modal_content.style.padding = '20px';
    modal_content.style.borderRadius = '5px';
    modal_content.style.textAlign = 'center';

    const modal_text = document.createElement('p');
    modal_text.textContent = "The first message will be deleted. Proceed?";
    modal_text.style.marginBottom = '20px';

    const modal_buttons = document.createElement('div');
    modal_buttons.style.display = 'flex';
    modal_buttons.style.justifyContent = 'center';

    const modal_confirm_button = document.createElement('button');
    modal_confirm_button.textContent = 'Confirm';
    modal_confirm_button.style.marginRight = '10px';
    modal_confirm_button.style.backgroundColor = 'red'; // Example button color
    modal_confirm_button.style.color = 'white'; // Example text color
    modal_confirm_button.style.border = 'none';
    modal_confirm_button.style.borderRadius = '3px';
    modal_confirm_button.style.padding = '5px 15px';
    modal_confirm_button.addEventListener('click', () => {
        document.body.removeChild(modal_delete_first);
        deleteFirstMessage();
    });

    const modal_cancel_button = document.createElement('button');
    modal_cancel_button.textContent = 'Cancel';
    modal_cancel_button.style.backgroundColor = 'gray'; // Example button color
    modal_cancel_button.style.color = 'white'; // Example text color
    modal_cancel_button.style.border = 'none';
    modal_cancel_button.style.borderRadius = '3px';
    modal_cancel_button.style.padding = '5px 15px';
    modal_cancel_button.addEventListener('click', () => {
        document.body.removeChild(modal_delete_first);
    });

    modal_buttons.appendChild(modal_confirm_button);
    modal_buttons.appendChild(modal_cancel_button);

    modal_content.appendChild(modal_text);
    modal_content.appendChild(modal_buttons);

    modal_delete_first.appendChild(modal_content);
    document.body.appendChild(modal_delete_first);
}

//------------------------------------ END OF DELETE FIRST FUNCTION------------------------------------


//------------------------------------ START OF DELETE LAST FUNCTION------------------------------------


// Delete last message command logic
function deleteLastMessage() {
    const deleteCommand = JSON.parse(delete_last_commandJson);
    sendSocketMessage(socket, deleteCommand, true); // Pass `true` for the reload argument
}

// Show confirmation modal
function showDeleteLastConfirmation() {
    const modal_delete_last = document.createElement('div');
    modal_delete_last.style.position = 'fixed';
    modal_delete_last.style.top = '0';
    modal_delete_last.style.left = '0';
    modal_delete_last.style.width = '100%';
    modal_delete_last.style.height = '100%';
    modal_delete_last.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
    modal_delete_last.style.display = 'flex';
    modal_delete_last.style.justifyContent = 'center';
    modal_delete_last.style.alignItems = 'center';
    modal_delete_last.style.zIndex = '9999';

    const modal_content = document.createElement('div');
    modal_content.style.backgroundColor = 'white';
    modal_content.style.padding = '20px';
    modal_content.style.borderRadius = '5px';
    modal_content.style.textAlign = 'center';

    const modal_text = document.createElement('p');
    modal_text.textContent = "The first message will be deleted. Proceed?";
    modal_text.style.marginBottom = '20px';

    const modal_buttons = document.createElement('div');
    modal_buttons.style.display = 'flex';
    modal_buttons.style.justifyContent = 'center';

    const modal_confirm_button = document.createElement('button');
    modal_confirm_button.textContent = 'Confirm';
    modal_confirm_button.style.marginRight = '10px';
    modal_confirm_button.style.backgroundColor = 'red'; // Example button color
    modal_confirm_button.style.color = 'white'; // Example text color
    modal_confirm_button.style.border = 'none';
    modal_confirm_button.style.borderRadius = '3px';
    modal_confirm_button.style.padding = '5px 15px';
    modal_confirm_button.addEventListener('click', () => {
        document.body.removeChild(modal_delete_last);
        deleteLastMessage();
    });

    const modal_cancel_button = document.createElement('button');
    modal_cancel_button.textContent = 'Cancel';
    modal_cancel_button.style.backgroundColor = 'gray'; // Example button color
    modal_cancel_button.style.color = 'white'; // Example text color
    modal_cancel_button.style.border = 'none';
    modal_cancel_button.style.borderRadius = '3px';
    modal_cancel_button.style.padding = '5px 15px';
    modal_cancel_button.addEventListener('click', () => {
        document.body.removeChild(modal_delete_last);
    });

    modal_buttons.appendChild(modal_confirm_button);
    modal_buttons.appendChild(modal_cancel_button);

    modal_content.appendChild(modal_text);
    modal_content.appendChild(modal_buttons);

    modal_delete_last.appendChild(modal_content);
    document.body.appendChild(modal_delete_last);
}



//------------------------------------ END OF DELETE FUNCTION------------------------------------
// wenn ich den anderen button hier rein mache dann muss der promise erfüllt sein

// Function to send socket message
function sendSocketMessage(socket, command, shouldReload) {
    try {
        socket.send(JSON.stringify(command));
        console.log('Socket message sent:', command);
        if (shouldReload) {
            location.reload(); // Reload the page after sending the message
        }
    } catch (error) {
        console.error('Error sending socket message:', error);
    }
}


    }); //------------------------------------ END OF XHR INTERCEPTION PROMISE ------------------------------------



function createToggleButton() {
    const toggleButton = document.createElement('button');
    toggleButton.textContent = 'Details';
    toggleButton.style.position = 'fixed';
    toggleButton.style.bottom = '0px';
    toggleButton.style.left = '0%';
    toggleButton.style.backgroundColor = '#3E4040';
    toggleButton.style.color = 'white';
    toggleButton.style.fontWeight = 'bold';
    toggleButton.style.padding = '4px';
    toggleButton.style.margin = '0px';
    toggleButton.style.width = '15%';
    toggleButton.style.border = 'none';
    toggleButton.style.borderRadius = '0px';
    toggleButton.style.cursor = 'pointer';
    toggleButton.style.userSelect = 'none';
    toggleButton.style.zIndex = '101';
    toggleButton.addEventListener('click', togglePanel);

    document.body.appendChild(toggleButton);
}



//--------------------------------------------------------- PERMANENT PANEL -------------------------------------------------------

function createPermanentPanel() {
    const panel = document.createElement('div');
    panel.id = 'descriptionPanel';
    panel.style.position = 'fixed';
    panel.style.bottom = '32px';
    panel.style.left = '0%';
    panel.style.width = '15%';
    panel.style.height = '100%';
    panel.style.backgroundColor = 'white';
    panel.style.borderRight = '1px solid #ccc';
    panel.style.padding = '10px';
    panel.style.zIndex = '100';
    panel.style.resize = 'horizontal';
    panel.style.direction = 'ltr';
    panel.style.overflow = 'auto';
    // Set the initial display state to 'none'
    panel.style.display = 'block';


//--------------------------------------------------------- ALL ELEMENTS IN THE PANEL -------------------------------------------------------
// Add headline to the panel
const name_h = document.createElement('h4');
name_h.textContent = intercepted_data_object.name;
name_h.style.marginTop = '35px';
name_h.style.textAlign = 'center';  // Center-align the text
panel.appendChild(name_h);

// Create a container div for the name and the new div
const containerDiv = document.createElement('div');
containerDiv.style.display = 'flex'; // Use flexbox to arrange items in a row
containerDiv.style.alignItems = 'center'; // Vertically center items
containerDiv.style.justifyContent = 'center'; // Center items horizontally
containerDiv.style.textAlign = 'center';
panel.appendChild(containerDiv);

// Append the name_h to the container div
containerDiv.appendChild(name_h);

// Assuming you have access to the intercepted_data_object and containerDiv

if (
    intercepted_data_object.external_id === "EEI6sjnddRIJTVC59MODiYjL0-JyDIVI2IEGLkPx2Jk" ||
    intercepted_data_object.external_id === "qtEICpGfFS8f5Zr5kCHR1EsGsHlawNutYSZJq_IEZDY" ||
    intercepted_data_object.external_id === "0FGHpcylr6O0l46xHrTMzRGnqAU6beVz0k3i294wbUQ" ||
    intercepted_data_object.external_id === "iV5qb8ttzD7Ytl69U_-ONcW2tW_lrFrOVKExyKJHlJM" ||
    intercepted_data_object.external_id === "YntB_ZeqRq2l_aVf2gWDCZl4oBttQzDvhj9cXafWcF8"
) {
    const caitagDiv = document.createElement('div');
caitagDiv.innerHTML = '<div class="rounded py-0 px-1" style="vertical-align: middle; margin-top: 31px; margin-left: 5px; background-color: rgb(60, 133, 246); color: white; font-weight: 600; font-size: 12px;" aria-label="AI Character using new C1.2 Model. See Community Announcements to learn more." data-darkreader-inline-bgcolor="" data-darkreader-inline-color=""><div class="d-flex flex-row"><div class="d-flex flex-column">[email protected]</div></div></div>';
   containerDiv.appendChild(caitagDiv);
} else {
    const aiCharacterDiv = document.createElement('div');
    aiCharacterDiv.className = 'rounded py-0 px-1';
    aiCharacterDiv.style.marginLeft = '5px';
    aiCharacterDiv.style.backgroundColor = 'rgb(60, 133, 246)';
    aiCharacterDiv.style.color = 'white';
    aiCharacterDiv.style.fontWeight = '600';
    aiCharacterDiv.style.fontSize = '12px';
    aiCharacterDiv.textContent = 'c.ai';
    aiCharacterDiv.style.verticalAlign = 'middle'; // Adjust vertical alignment
    aiCharacterDiv.style.marginTop = '31px'; // Adjust margin-top

    containerDiv.appendChild(aiCharacterDiv);
}


// Function to map visibility strings to symbols or numbers
function mapVisibilityToContent(visibility) {
  switch (visibility) {
    case 'PRIVATE':
      return '<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" height="18" width="18" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle; margin-top: -3px;"><path fill="none" d="M0 0h24v24H0z"></path><path d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"></path></svg>';
    case 'UNLISTED':
      return '<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 24 24" class="mb-1" height="18" width="18" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle; margin-top: 5px;"><path fill="none" d="M0 0h24v24H0z"></path><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"></path></svg>';
    case 'PUBLIC':
      return '<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle; margin-top: -2px;"><path fill="none" stroke-linecap="round" stroke-miterlimit="10" stroke-width="32" d="M87.49 380c1.19-4.38-1.44-10.47-3.95-14.86a44.86 44.86 0 00-2.54-3.8 199.81 199.81 0 01-33-110C47.65 139.09 140.73 48 255.83 48 356.21 48 440 117.54 459.58 209.85a199 199 0 014.42 41.64c0 112.41-89.49 204.93-204.59 204.93-18.3 0-43-4.6-56.47-8.37s-26.92-8.77-30.39-10.11a31.09 31.09 0 00-11.12-2.07 30.71 30.71 0 00-12.09 2.43l-67.83 24.48a16 16 0 01-4.67 1.22 9.6 9.6 0 01-9.57-9.74 15.85 15.85 0 01.6-3.29z"></path></svg>';
    default:
      return 0; // Handle other cases, if needed
  }
}


  // Example visibility value from intercepted data
  const visibilityValue = intercepted_data_object.visibility;

  // Map visibility to an SVG icon or number
  const visibilityContent = mapVisibilityToContent(visibilityValue);

  // Create the visibility element and set its content
  const visibilityElement = document.createElement('div');
  visibilityElement.style.display = 'flex'; // Use flexbox
  visibilityElement.style.alignItems = 'center'; // Align items vertically
  visibilityElement.style.justifyContent = 'center'; // Center items horizontally
  visibilityElement.style.textAlign = 'center';
  visibilityElement.innerHTML = visibilityContent;
  panel.appendChild(visibilityElement);

    // Function to format the interaction count
    function formatInteractionCount(count) {
      if (count < 10000) {
        return count.toString(); // Display full number
      } else if (count < 100000) {
        return (count / 1000).toFixed(1) + 'k'; // Display as X.Xk
      } else if (count < 1000000) {
        return (count / 1000).toFixed(0) + 'k'; // Display as Xk
      } else {
        return (count / 1000000).toFixed(1) + 'm'; // Display as X.Xm
      }
    }

    // Interaction count from intercepted data
    const numInteractions = intercepted_data_object.participant__num_interactions;

    // Format the interaction count
    const formattedInteractions = formatInteractionCount(numInteractions);

    // Create a span for the interaction count
    const interactionCountSpan = document.createElement('span');
    interactionCountSpan.textContent = `${formattedInteractions}`;
    interactionCountSpan.style.marginLeft = '5px'; // Add margin to the left
    //interactionCountSpan.style.marginTop = '-6px'; // Add margin to the left

    // Add the interaction count span to the visibility element
    visibilityElement.appendChild(interactionCountSpan);


    // Add a horizontal line (divider)
    const divider = document.createElement('hr');
    panel.appendChild(divider);

    // Add longdescription header to the panel
    const longdescription_h = document.createElement('h5');
    longdescription_h.textContent = 'Long Description';
    longdescription_h.style.marginTop = '0';
    longdescription_h.style.textAlign = 'center';  // Center-align the text
    longdescription_h.style.display = 'block';
    panel.appendChild(longdescription_h);



    // Add longdescription to the panel
const longdescription = document.createElement('p');
longdescription.textContent = intercepted_data_object.description;
longdescription.style.textAlign = 'center'; // Center-align the text
longdescription.style.display = 'none'; // Initially hide the long description
longdescription.style.marginBottom = '7px';
longdescription.style.whiteSpace = 'normal';
longdescription.style.overflowWrap = 'break-word';

panel.appendChild(longdescription);

const expandButton = document.createElement('button');
//expandButton.style.margin = '10px auto'; // Center the button horizontally with top margin
expandButton.style.backgroundColor = 'transparent'; // Set background color to transparent
expandButton.style.border = 'none'; // Remove the button border
expandButton.style.width = '100%';

const buttonTextContainer = document.createElement('div');
buttonTextContainer.style.textAlign = 'center'; // Center-align the text inside the container

/*const line1Span = document.createElement('span');
line1Span.textContent = 'Long Description';
line1Span.style.fontSize = '20px'; // Set font size for the first line
line1Span.style.color = '#C8C5BE'; // Set the color for the first line
*/
const line2Span = document.createElement('span');
line2Span.textContent = 'click to expand';
line2Span.style.fontSize = '14px'; // Set smaller font size for the second line
line2Span.style.marginTop = '0px';


//buttonTextContainer.appendChild(line1Span);
//buttonTextContainer.appendChild(document.createElement('br')); // Add a line break
buttonTextContainer.appendChild(line2Span);

expandButton.appendChild(buttonTextContainer);

expandButton.addEventListener('click', () => {
    if (longdescription.style.display === 'none') {
//        longdescription_h.style.display = 'block';
        longdescription.style.display = 'block'; // Show the long description
//        line1Span.style.color = 'transparent'; // Hide the long description title
        line2Span.textContent = 'click to collapse'; // Change the second line text

    } else {
//        longdescription_h.style.display = 'none';
        longdescription.style.display = 'none';
//        line1Span.style.color = '#C8C5BE'; // Show the long description
        line2Span.textContent = 'click to expand'; // Change the second line text
    }
});

panel.appendChild(expandButton);


    // Add a horizontal line (divider)
    const divider1 = document.createElement('hr');
    panel.appendChild(divider1);


    // Add image to the panel
    const image = document.createElement('img');
    image.style.maxWidth = '100%';
    image.style.marginTop = '10px';
    image.style.display = 'block'; // Ensures that the image occupies full width
    image.style.margin = '0 auto'; // Centers the image horizontally
    // Set the original image source
    image.src = `https://characterai.io/i/400/static/avatars/${intercepted_data_object.avatar_file_name}`;

    // Add an event listener to handle image load error
    image.onerror = function() {
    // Load the fallback image if the original image fails to load
    image.src = 'https://i.imgur.com/G19HeCH.png';
    };

    panel.appendChild(image);


    // Add short description (title) to the panel
    const shortdescription = document.createElement('p');
    shortdescription.textContent = intercepted_data_object.title;
    shortdescription.style.textAlign = 'center';  // Center-align the text
    shortdescription.style.marginTop = '10px';
    panel.appendChild(shortdescription);


    // Add a horizontal line (divider)
    const divider2 = document.createElement('hr');
    divider2.style.marginTop = '-5px';
    panel.appendChild(divider2);



    // Create the username element and set its content using string interpolation
    const username = document.createElement('p');
    username.textContent = `${intercepted_data_object.name} and their greeting was authored by @${intercepted_data_object.username}`;
    username.style.textAlign = 'center';  // Center-align the text
    username.style.marginTop = '5px';
    username.style.setProperty('font-size', '14px', 'important'); // Set style with !important
    panel.appendChild(username);



//--------------------------------------------------------- QPR BUTTON -------------------------------------------------------
const qpr_button = document.createElement('button');
qpr_button.textContent = 'Send a QPR';
qpr_button.style.padding = '5px 10px';
qpr_button.style.backgroundColor = '#007bff';
qpr_button.style.borderRadius = '5px';
qpr_button.style.color = 'white';
qpr_button.style.border = 'none';
qpr_button.style.cursor = 'pointer';
qpr_button.style.transition = 'background-color 0.3s, transform 0.2s';
qpr_button.style.display = 'block';
qpr_button.style.width = '100%';

// Mouseover animation
qpr_button.addEventListener('mouseover', () => {
    qpr_button.style.backgroundColor = '#0056b3';
    qpr_button.style.transform = 'scale(1.0)';
});

// Mouseout animation
qpr_button.addEventListener('mouseout', () => {
    qpr_button.style.backgroundColor = '#007bff';
    qpr_button.style.transform = 'scale(1)';
});

// Click animation and open URL
qpr_button.addEventListener('click', () => {
    // Open the URL in a new tab
    window.open('https://docs.google.com/forms/d/e/1FAIpQLSe4I9TQAc32ghQLWBaVhzSjTp7mIADBVDxcrb-UmP4EqdM57w/viewform', '_blank');
});

// Append the QPR button to the panel
panel.appendChild(qpr_button);


//--------------------------------------------------------- AUTOSCROLL BUTTON -------------------------------------------------------


const autoscroll_button = document.createElement('button');
autoscroll_button.textContent = 'Autoscroll';
autoscroll_button.style.padding = '5px 10px';
    autoscroll_button.style.marginTop = '10px';
autoscroll_button.style.backgroundColor = '#007bff';
autoscroll_button.style.borderRadius = '5px';
autoscroll_button.style.color = 'white';
autoscroll_button.style.border = 'none';
autoscroll_button.style.cursor = 'pointer';
autoscroll_button.style.transition = 'background-color 0.3s, transform 0.2s';
autoscroll_button.style.display = 'block';
autoscroll_button.style.width = '100%';

// Mouseover animation
autoscroll_button.addEventListener('mouseover', () => {
    if (autoscroll_button.style.backgroundColor !== 'red') { // Check if background color is not red
        autoscroll_button.style.backgroundColor = '#0056b3';
        autoscroll_button.style.transform = 'scale(1.0)';
    }
});

// Mouseout animation
autoscroll_button.addEventListener('mouseout', () => {
    if (autoscroll_button.style.backgroundColor !== 'red') { // Check if background color is not red
        autoscroll_button.style.backgroundColor = '#007bff';
        autoscroll_button.style.transform = 'scale(1)';
    }
});

// Click animation and scroll
autoscroll_button.addEventListener('click', () => {
    event.stopPropagation();
    toggleAutoscroll(autoscroll_button);
    autoscroll_button.removeEventListener('mouseover', mouseoverHandler); // Remove the mouseover listener
    autoscroll_button.removeEventListener('mouseout', mouseoutHandler);   // Remove the mouseout listener
});

// Append the autoscroll button to the panel
panel.appendChild(autoscroll_button);

function mouseoverHandler() {
    autoscroll_button.style.backgroundColor = '#0056b3';
    autoscroll_button.style.transform = 'scale(1.0)';
}

function mouseoutHandler() {
    autoscroll_button.style.backgroundColor = '#007bff';
    autoscroll_button.style.transform = 'scale(1)';
}




    function ArrowRightKeyDown() {
        document.body.dispatchEvent(
            new KeyboardEvent('keydown', {
                bubbles: true,
                key: 'ArrowRight',
            })
        );
        console.log("Arrow right pressed");
    }

    function scroll_totheright() {
        if (document.querySelector('div[class="swiper-button-next"]')) {
            ArrowRightKeyDown();
            setTimeout(scroll_totheright, 100); // Add a delay between scrolls
        } else {
            scroll_totheright_observer.observe(document.querySelector('div[class*="swiper swiper-initialized swiper-horizontal"]'), { childList: true, subtree: true });
        }
    }

    const scroll_totheright_observer = new MutationObserver(scroll_totheright);

function toggleAutoscroll(autoscroll_button) {
    if (sessionStorage.getItem("RAs_Autoscroll") === "true") {
        sessionStorage.removeItem("RAs_Autoscroll");
        autoscroll_button.innerHTML = 'Autoscroll';
        autoscroll_button.style.backgroundColor = '';
        scroll_totheright_observer.disconnect();
    } else {
        sessionStorage.setItem("RAs_Autoscroll", "true");
        autoscroll_button.innerHTML = 'Autoscroll ⏭️';
        autoscroll_button.style.backgroundColor = 'red'; // Set background color to red
        scroll_totheright();
        scroll_totheright_observer.observe(document.querySelector('div[class*="swiper swiper-initialized swiper-horizontal"]'), { childList: true, subtree: true });
    }
}

    function createAutoscrollButton(panel) {
        const autoscroll_button = document.createElement('button');
        autoscroll_button.innerHTML = 'Autoscroll';
        autoscroll_button.addEventListener('click', function(event) {
            event.stopPropagation();
            toggleAutoscroll(autoscroll_button);
        });

        const buttonContainer = document.createElement('div');
        buttonContainer.style.marginTop = '10px'; // Adjust margin as needed
        buttonContainer.appendChild(autoscroll_button);

        panel.appendChild(buttonContainer);

        if (sessionStorage.getItem("RAs_Autoscroll") === "true") {
            toggleAutoscroll(autoscroll_button);
        }
    }
//--------------------------------------------------------- AUTOSCROLL BUTTON END -------------------------------------------------------


    document.body.appendChild(panel);
}


//--------------------------------------------------------- NEO PANEL DELETE -------------------------------------------------------


/*function createNeoPanelDelete() {
    const NeoPanelDelete = document.createElement('div');
    NeoPanelDelete.id = 'NeoPanelDelete';
    NeoPanelDelete.style.position = 'absolute';
    NeoPanelDelete.style.bottom = '32px';
    NeoPanelDelete.style.left = '15%';
    NeoPanelDelete.style.width = '15%';
    NeoPanelDelete.style.height = '100%';
    NeoPanelDelete.style.backgroundColor = 'white';
    NeoPanelDelete.style.borderLeft = '1px solid #ccc';
    NeoPanelDelete.style.padding = '10px';
    NeoPanelDelete.style.zIndex = '100';
    NeoPanelDelete.style.resize = 'horizontal';
    NeoPanelDelete.style.direction = 'rtl';
    NeoPanelDelete.style.overflow = 'auto';
    // Set the initial display state to 'none'
    NeoPanelDelete.style.display = 'block';




    // Add longdescription header to the panel
    const Delete_headline = document.createElement('h5');
    Delete_headline.textContent = 'Delete';
    Delete_headline.style.marginTop = '30px';
    Delete_headline.style.textAlign = 'center';  // Center-align the text
    NeoPanelDelete.appendChild(Delete_headline);

    // Add a horizontal line (divider)
    const divider_Delete1 = document.createElement('hr');
    NeoPanelDelete.appendChild(divider_Delete1);

    document.body.appendChild(NeoPanelDelete);
}
*/

 function toggleNeoPanelDelete() {
    const NeoPanelDelete = document.getElementById('NeoPanelDelete');
    if (NeoPanelDelete.style.display === 'block') {
        NeoPanelDelete.style.display = 'none';
    } else {
        NeoPanelDelete.style.display = 'block';
    }
}







//--------------------------------------------------------- ERROR 500 maybe -------------------------------------------------------



    waitForElement('div[id="root"]>div[class="Toastify"]', 60000).then(function() {
      //console.log("Toastify observer SUCCESS");
      const error500_observer = new MutationObserver (function () {
        //console.log("error500_observer observer fired");
        if (document.querySelector('div[class*="Toastify__toast--error"]')) {
          console.log("500 Internal Server Error detected");
          document.querySelector('textarea[id="user-input"]').style.setProperty("background-color", "lightpink", "important");
          document.querySelector('textarea[id="user-input"]').setAttribute("placeholder", "   “500 Internal Server Error” was fired! Refresh the page!");
        };
      });
      error500_observer.observe(document.querySelector('div[id="root"]>div[class="Toastify"]'), {childList: true, subtree: true});
    }).catch(function() {
      console.log("Toastify observer ERROR");
    });

//--------------------------------------------------------- ERROR 500 maybe END -------------------------------------------------------



 function togglePanel() {
    const panel = document.getElementById('descriptionPanel');
    if (panel.style.display === 'block') {
        panel.style.display = 'none';
    } else {
        panel.style.display = 'block';
    }
}


})();