ChatGPT Text Splitter

Automatically split long messages into parts for ChatGPT, with responsive buttons that instantly reappear!

目前为 2025-02-20 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name ChatGPT Text Splitter
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.2
  5. // @description Automatically split long messages into parts for ChatGPT, with responsive buttons that instantly reappear!
  6. // @author JOHNNYDAN
  7. // @match https://chatgpt.com/*
  8. // @icon https://chatgpt-prompt-splitter.jjdiaz.dev/static/chatgpt_prompt_splitter.png
  9. // @grant none
  10. // @license GNU GENERAL PUBLIC LICENSE
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. const MAX_CHUNK_SIZE = 15000;
  17. const SCISSOR_EMOJI = '✂️';
  18. const PAPER_EMOJI = '📄';
  19. let longContent = '';
  20. let splitParts = [];
  21. let currentPartIndex = 0;
  22.  
  23. function createButton(text, bgColor) {
  24. const button = document.createElement('button');
  25. button.innerHTML = text;
  26. Object.assign(button.style, {
  27. padding: '8px 12px',
  28. fontSize: '14px',
  29. fontWeight: 'bold',
  30. backgroundColor: bgColor,
  31. color: 'white',
  32. border: '1px solid hsl(0deg 0% 100% / 15%)',
  33. borderRadius: '20px',
  34. cursor: 'pointer',
  35. zIndex: '1000',
  36. transition: '0.2s ease-in-out',
  37. boxShadow: '0px 2px 5px rgba(0,0,0,0.2)',
  38. width: '100px',
  39. textAlign: 'center'
  40. });
  41. button.addEventListener('mouseenter', () => button.style.opacity = '0.8');
  42. button.addEventListener('mouseleave', () => button.style.opacity = '1');
  43. return button;
  44. }
  45.  
  46. const container = document.createElement('div');
  47. Object.assign(container.style, {
  48. position: 'fixed',
  49. top: '50px',
  50. right: '10px',
  51. display: 'flex',
  52. gap: '10px',
  53. zIndex: '1000',
  54. flexWrap: 'wrap'
  55. });
  56.  
  57. const scissorButton = createButton(SCISSOR_EMOJI + ' Split', '#212121');
  58. const paperButton = createButton(PAPER_EMOJI + ' Paste', '#212121');
  59.  
  60. container.appendChild(scissorButton);
  61. container.appendChild(paperButton);
  62. document.body.appendChild(container);
  63.  
  64. function showNotification(message) {
  65. const notification = document.createElement('div');
  66. notification.textContent = message;
  67. Object.assign(notification.style, {
  68. position: 'fixed',
  69. top: '70px',
  70. left: '50%',
  71. transform: 'translateX(-50%)',
  72. backgroundColor: '#2f2f2f',
  73. color: 'white',
  74. padding: '10px 15px',
  75. borderRadius: '6px',
  76. fontSize: '14px',
  77. fontWeight: 'bold',
  78. zIndex: '999',
  79. boxShadow: '0px 2px 5px rgba(0,0,0,0.2)'
  80. });
  81. document.body.appendChild(notification);
  82. setTimeout(() => notification.remove(), 3000);
  83. }
  84.  
  85. function splitText(content) {
  86. let parts = [];
  87. let numParts = Math.ceil(content.length / MAX_CHUNK_SIZE);
  88. for (let i = 0; i < numParts; i++) {
  89. let start = i * MAX_CHUNK_SIZE;
  90. let end = start + MAX_CHUNK_SIZE;
  91. parts.push(content.slice(start, end));
  92. }
  93. return parts;
  94. }
  95.  
  96. scissorButton.addEventListener('click', () => {
  97. const editableDiv = document.querySelector('#prompt-textarea');
  98. if (!editableDiv) {
  99. alert('Unable to find the input field!');
  100. return;
  101. }
  102.  
  103. longContent = editableDiv.innerText.trim();
  104. splitParts = splitText(longContent);
  105. currentPartIndex = 0;
  106.  
  107. editableDiv.innerText = `The content is too large and will be sent in parts.\nWait for the final message: ALL PARTS SENT.`;
  108. editableDiv.focus();
  109. showNotification("Press Enter to send instructions. Then use Paste button for parts.");
  110. });
  111.  
  112. paperButton.addEventListener('click', () => {
  113. if (splitParts.length === 0) {
  114. showNotification("Click Split first to prepare the content.");
  115. return;
  116. }
  117.  
  118. const editableDiv = document.querySelector('#prompt-textarea');
  119. if (!editableDiv) return;
  120.  
  121. if (currentPartIndex >= splitParts.length) {
  122. editableDiv.innerText = "ALL PARTS SENT";
  123. showNotification("All parts sent! ChatGPT can now process the data.");
  124. currentPartIndex = 0;
  125. return;
  126. }
  127.  
  128. let partText = splitParts[currentPartIndex];
  129. let totalParts = splitParts.length;
  130. let partNumber = currentPartIndex + 1;
  131.  
  132. editableDiv.innerText = `[START PART ${partNumber}/${totalParts}]\n${partText}\n[END PART ${partNumber}/${totalParts}]`;
  133. editableDiv.focus();
  134.  
  135. showNotification(`Sent Part ${partNumber}/${totalParts}. Press Enter.`);
  136. currentPartIndex++;
  137. });
  138.  
  139. // Improved auto-hide: Instant reappear
  140. document.addEventListener('click', (event) => {
  141. const profileButton = document.querySelector('[aria-label="Open Profile Menu"]');
  142. const profileMenu = document.querySelector('[role="menu"]');
  143.  
  144. if (profileButton && profileButton.contains(event.target)) {
  145. container.style.display = 'none';
  146. } else if (!profileMenu || !profileMenu.contains(event.target)) {
  147. container.style.display = 'flex';
  148. }
  149. });
  150. })();