ChatGPT Text File Scaler

ChatGPT utility to cut and transfer text files

目前为 2023-03-20 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name ChatGPT Text File Scaler
  3. // @version 1.3
  4. // @author refracta
  5. // @description ChatGPT utility to cut and transfer text files
  6. // @match https://chat.openai.com/*
  7. // @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com
  8. // @license MIT
  9. // @namespace https://greasyfork.org/users/467840
  10. // ==/UserScript==
  11.  
  12. (async function () {
  13. 'use strict';
  14. function createElement(html) {
  15. var div = document.createElement('div');
  16. div.innerHTML = html.trim();
  17. return div.firstChild;
  18. }
  19.  
  20. function insertAfter(referenceNode, newNode) {
  21. if (!!referenceNode.nextSibling) {
  22. referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
  23. } else {
  24. referenceNode.parentNode.appendChild(newNode);
  25. }
  26. }
  27.  
  28. function waitFor(valueFunction, inspectPeriod = 100) {
  29. return new Promise(resolve => {
  30. let interval = setInterval(async _ => {
  31. try {
  32. let value = valueFunction();
  33. value = value instanceof Promise ? await value : value;
  34. if (value) {
  35. clearInterval(interval);
  36. resolve(value);
  37. }
  38. } catch (e) {}
  39. }, inspectPeriod);
  40. });
  41. }
  42.  
  43. function writeMessage(text) {
  44. document.querySelector('textarea').value = text;
  45. }
  46.  
  47. function clickSendButton() {
  48. document.querySelector('button.absolute').click();
  49. }
  50.  
  51. async function waitResponse() {
  52. await waitFor(_ => document.querySelector('button.absolute.p-1 > svg'));
  53. }
  54.  
  55. async function sendMessage(text) {
  56. writeMessage(text);
  57. clickSendButton();
  58. await waitResponse();
  59. }
  60.  
  61. function clearMessages(messageLimit) {
  62. let messages = Array.from(document.querySelectorAll('.flex-1.overflow-hidden > div > div > div > div:nth-child(1) > div'));
  63. while (messages.length > messageLimit) {
  64. messages.shift().remove();
  65. }
  66. }
  67.  
  68. function updateLoadTextFileSpan() {
  69. let loadTextFileSpan = document.querySelector('#load-text-file');
  70. if (loadTextFileSpan) {
  71. loadTextFileSpan.textContent = `Load text file (${localStorage.buffer.length})`;
  72. }
  73. }
  74.  
  75. async function sendTextFile() {
  76. const firstMessage = 'I am going to provide you a book in multiple messages.';
  77. const insertMessage = 'Here is the next page, please do not respond aside from confirmation:\n\n';
  78. const splitLength = 2000;
  79. const messageLimit = 30;
  80.  
  81. await sendMessage(firstMessage);
  82. while (localStorage.buffer.length > 0) {
  83. let length = splitLength - insertMessage.length;
  84. let text = localStorage.buffer.slice(0, length);
  85. await sendMessage(insertMessage + text);
  86. localStorage.buffer = localStorage.buffer.slice(length);
  87. updateLoadTextFileSpan();
  88. clearMessages(messageLimit);
  89. }
  90. }
  91.  
  92. function getText() {
  93. return new Promise(resolve => {
  94. let input = document.createElement("input");
  95. input.type = "file";
  96. input.accept = "text/plain";
  97. input.onchange = (event) => {
  98. let file = event.target.files[0];
  99. let reader = new FileReader();
  100. reader.onload = () => {
  101. resolve(reader.result);
  102. };
  103. reader.readAsText(file);
  104. };
  105. input.click();
  106. });
  107. }
  108.  
  109. localStorage.buffer = localStorage.buffer ? localStorage.buffer : '';
  110.  
  111. let isUIProcessing = false;
  112. setInterval(async _ => {
  113. if (!document.querySelector('#load-text-file') && !isUIProcessing) {
  114. try {
  115. isUIProcessing = true;
  116.  
  117. let historyDiv = document.querySelector('.scrollbar-trigger > nav > div');
  118.  
  119. let sendTextFileButton = createElement(`<a href="#" class="flex py-3 px-3 items-center gap-3 rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white cursor-pointer text-sm"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>Send text file</a>`);
  120. sendTextFileButton.addEventListener('click', sendTextFile);
  121. insertAfter(historyDiv, sendTextFileButton);
  122.  
  123. let loadTextFileButton = createElement(`<a href="#" class="flex py-3 px-3 items-center gap-3 rounded-md hover:bg-gray-500/10 transition-colors duration-200 text-white cursor-pointer text-sm"><svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-4" height="1em" width="1em" xmlns="http://www.w3.org/2000/svg"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg><span id="load-text-file">Load text file (${localStorage.buffer.length})</span></a>`);
  124. loadTextFileButton.addEventListener('click', async() => {
  125. localStorage.buffer = await getText();
  126. updateLoadTextFileSpan();
  127. });
  128. insertAfter(historyDiv, loadTextFileButton);
  129. } finally {
  130. isUIProcessing = false;
  131. }
  132. }
  133. }, 100);
  134.  
  135. })();