ChatGPT Text Splitter

Automatically split long messages into parts for ChatGPT, inspired by jjdiaz.dev, created with ❤️.

As of 19. 02. 2025. See the latest version.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         ChatGPT Text Splitter
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Automatically split long messages into parts for ChatGPT, inspired by jjdiaz.dev, created with ❤️.
// @author       JOHNNYDAN
// @match        https://chatgpt.com/*
// @icon         https://chatgpt-prompt-splitter.jjdiaz.dev/favicon.ico
// @grant        none
// @license      GNU GENERAL PUBLIC LICENSE
// ==/UserScript==

(function() {
    'use strict';

    // Constants
    const MAX_CHUNK_SIZE = 15000;
    const SCISSOR_EMOJI = '✂️';
    const PAPER_EMOJI = '📄';
    let longContent = '';
    let splitParts = [];
    let currentPartIndex = 0;

    // Function to create styled buttons
    function createButton(text, left, top, bgColor) {
        const button = document.createElement('button');
        button.innerHTML = text;
        Object.assign(button.style, {
            position: 'fixed',
            left: `${left}px`,
            top: `${top}px`,
            padding: '8px 12px',
            fontSize: '14px',
            fontWeight: 'bold',
            backgroundColor: bgColor,
            color: 'white',
            border: 'none',
            borderRadius: '8px',
            cursor: 'pointer',
            zIndex: '1000',
            transition: '0.2s ease-in-out',
            boxShadow: '0px 2px 5px rgba(0,0,0,0.2)'
        });

        button.addEventListener('mouseenter', () => button.style.opacity = '0.8');
        button.addEventListener('mouseleave', () => button.style.opacity = '1');

        document.body.appendChild(button);
        return button;
    }

    // Create UI Buttons
    const scissorButton = createButton(SCISSOR_EMOJI + " Split", 1600, 10, '#f39c12'); // Orange
    const paperButton = createButton(PAPER_EMOJI + " Paste", 1600, 50, '#3498db'); // Blue

    // Function to show notifications (extended to 5s)
    function showNotification(message) {
        const notification = document.createElement('div');
        notification.textContent = message;
        Object.assign(notification.style, {
            position: 'fixed',
            top: '50px',
            left: '50%',
            transform: 'translateX(-50%)',
            backgroundColor: '#2f2f2f',
            color: 'white',
            padding: '10px 15px',
            borderRadius: '6px',
            fontSize: '14px',
            fontWeight: 'bold',
            zIndex: '999',
            boxShadow: '0px 2px 5px rgba(0,0,0,0.2)'
        });
        document.body.appendChild(notification);
        setTimeout(() => notification.remove(), 5000); // Extended to 5 seconds
    }

    // Function to split text into chunks
    function splitText(content) {
        let parts = [];
        let numParts = Math.ceil(content.length / MAX_CHUNK_SIZE);
        for (let i = 0; i < numParts; i++) {
            let start = i * MAX_CHUNK_SIZE;
            let end = start + MAX_CHUNK_SIZE;
            parts.push(content.slice(start, end));
        }
        return parts;
    }

    // Event listener for the scissors button (Step 1)
    scissorButton.addEventListener('click', () => {
        const editableDiv = document.querySelector('#prompt-textarea');
        if (!editableDiv) {
            alert('Unable to find the input field!');
            return;
        }

        longContent = editableDiv.innerText.trim();
        splitParts = splitText(longContent);
        currentPartIndex = 0;

        const instructionText = `
The total length of the content I want to send you is too large to send in one piece.

For sending this content, I will follow this rule:

[START PART 1/${splitParts.length}]
I will divide the text into parts, each with a strict format.
Do not process the content yet. Simply acknowledge each part as "Part X/Y received" and wait for the next.
[END PART 1/${splitParts.length}]

Once all parts are sent, I will write "ALL PARTS SENT" to signal you to process them.
        `.trim();

        editableDiv.innerText = instructionText;
        editableDiv.focus();
        showNotification("Press Enter to send instructions. Then use the Paste button for parts.");
    });

    // Event listener for the paper button (Step 2)
    paperButton.addEventListener('click', () => {
        if (splitParts.length === 0) {
            showNotification("Click the Split button first to prepare the content.");
            return;
        }

        const editableDiv = document.querySelector('#prompt-textarea');
        if (!editableDiv) return;

        // If all parts are sent, send "ALL PARTS SENT" and reset
        if (currentPartIndex >= splitParts.length) {
            editableDiv.innerText = "ALL PARTS SENT";
            showNotification("All parts sent! ChatGPT can now process the data.");
            currentPartIndex = 0;
            return;
        }

        let partText = splitParts[currentPartIndex];
        let totalParts = splitParts.length;
        let partNumber = currentPartIndex + 1;

        let message = `
Do not answer yet. This is just another part of the text I want to send you.
Just receive and acknowledge as "Part ${partNumber}/${totalParts} received" and wait for the next part.

[START PART ${partNumber}/${totalParts}]
${partText}
[END PART ${partNumber}/${totalParts}]
        `.trim();

        if (partNumber < totalParts) {
            message += `\nRemember not answering yet. Just acknowledge you received this part with the message "Part ${partNumber}/${totalParts} received" and wait for the next part."`;
        }

        editableDiv.innerText = message;
        editableDiv.focus();

        showNotification(`Sent Part ${partNumber}/${totalParts}. Press Enter.`);

        currentPartIndex++;
    });
})();