ChatGPT 增强

宽度对话框 & 一键清空聊天记录 & 向GPT声明指定语言回复

目前为 2023-05-04 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name ChatGPT Enhance
  3. // @name:en ChatGPT Enhance
  4. // @name:zh-CN ChatGPT 增强
  5. // @name:zh-TW ChatGPT 增強
  6. // @name:ja ChatGPT 拡張
  7. // @name:ko ChatGPT 향상
  8. // @name:de ChatGPT verbessern
  9. // @name:fr ChatGPT améliorer
  10. // @name:es ChatGPT mejorar
  11. // @name:pt ChatGPT melhorar
  12. // @name:ru ChatGPT улучшить
  13. // @name:it ChatGPT migliorare
  14. // @name:tr ChatGPT geliştirmek
  15. // @name:ar ChatGPT تحسين
  16. // @name:th ChatGPT ปรับปรุง
  17. // @name:vi ChatGPT cải thiện
  18. // @name:id ChatGPT meningkatkan
  19. // @namespace Violentmonkey Scripts
  20. // @match *://chat.openai.com/*
  21. // @grant none
  22. // @version XiaoYing_2023.05.22
  23. // @grant GM_info
  24. // @grant GM_getValue
  25. // @grant GM_setValue
  26. // @grant GM_addStyle
  27. // @grant GM_deleteValue
  28. // @grant GM_xmlhttpRequest
  29. // @grant GM_setClipboard
  30. // @grant GM_registerMenuCommand
  31. // @grant GM_unregisterMenuCommand
  32. // @grant GM_getResourceText
  33. // @grant GM_getResourceURL
  34. // @grant GM_openInTab
  35. // @grant unsafeWindow
  36. // @run-at document-start
  37. // @author github.com @XiaoYingYo
  38. // @require https://greasyfork.org/scripts/464929-module-jquery-xiaoying/code/module_jquery_XiaoYing.js
  39. // @require https://greasyfork.org/scripts/464780-global-module/code/global_module.js
  40. // @require https://greasyfork.org/scripts/465483-hookrequestandfetch/code/hookRequestAndFetch.js
  41. // @require https://greasyfork.org/scripts/465512-google-translate-engine/code/GoogleTranslateEngine.js
  42. // @description 宽度对话框 & 一键清空聊天记录 & 向GPT声明指定语言回复
  43. // @description:en Wide dialog & Clear chat history & Declare specified language reply to GPT
  44. // @description:zh-CN 宽度对话框 & 一键清空聊天记录 & 向GPT声明指定语言回复
  45. // @description:zh-TW 寬度對話框 & 一鍵清空聊天記錄 & 向GPT聲明指定語言回復
  46. // @description:ja 幅広いダイアログ & チャット履歴をクリア & 指定された言語でGPTに宣言する
  47. // @description:ko 넓은 대화 상자 & 채팅 기록 지우기 & 지정된 언어로 GPT에 선언
  48. // @description:de Breites Dialogfeld & Chatverlauf löschen & GPT in angegebener Sprache deklarieren
  49. // @description:fr Boîte de dialogue large & Effacer l'historique du chat & Déclarer la réponse dans la langue spécifiée à GPT
  50. // @description:es Cuadro de diálogo ancho & Borrar el historial del chat & Declarar respuesta en el idioma especificado a GPT
  51. // @description:pt Caixa de diálogo ampla & Limpar o histórico do bate-papo & Declarar resposta no idioma especificado ao GPT
  52. // @description:ru Широкий диалоговое окно & Очистить историю чата & Объявить ответ на указанном языке в GPT
  53. // @description:it Ampia finestra di dialogo & Cancella la cronologia della chat & Dichiarare la risposta nella lingua specificata a GPT
  54. // @description:tr Geniş diyalog & Sohbet geçmişini temizle & GPT'ye belirtilen dilde yanıt bildir
  55. // @description:ar مربع حوار واسع & مسح سجل المحادثة & إعلان الرد باللغة المحددة إلى GPT
  56. // @description:th กล่องโต้ตอบกว้าง & ล้างประวัติการแชท & ประกาศการตอบกลับในภาษาที่ระบุไว้กับ GPT
  57. // @description:vi Hộp thoại rộng & Xóa lịch sử trò chuyện & Khai báo trả lời bằng ngôn ngữ được chỉ định cho GPT
  58. // @description:id Kotak dialog lebar & Hapus riwayat obrolan & Nyatakan balasan dalam bahasa yang ditentukan ke GPT
  59. // ==/UserScript==
  60.  
  61. var global_module = window['global_module'];
  62. var globalVariable = new Map();
  63. var browserLanguage = navigator.language;
  64. var hookRequest = unsafeWindow['__hookRequest__'];
  65.  
  66. async function InitSvg() {
  67. return new Promise(async (resolve) => {
  68. let Svg = GM_getValue('clearSvg', []);
  69. if (Svg.length !== 0) {
  70. globalVariable.set('clearSvg', Svg);
  71. resolve(true);
  72. return;
  73. }
  74. let menuButton = document.querySelector('button[id^="headlessui-menu-button-"]');
  75. menuButton.click();
  76. let menuitems = [];
  77. await new Promise((resolve) => {
  78. let Timer = setInterval(() => {
  79. menuitems = document.querySelectorAll('a[role="menuitem"]');
  80. if (menuitems.length < 4) {
  81. return;
  82. }
  83. clearInterval(Timer);
  84. resolve();
  85. }, 100);
  86. });
  87. let menuitem = menuitems[1];
  88. if (menuitem.name === 1) {
  89. return;
  90. }
  91. let svg = menuitem.querySelector('svg');
  92. globalVariable.set('clearSvg', []);
  93. globalVariable.get('clearSvg').push(svg.outerHTML);
  94. menuitem.click();
  95. setTimeout(() => {
  96. svg = menuitem.querySelector('svg');
  97. globalVariable.get('clearSvg').push(svg.outerHTML);
  98. menuitem.name = 1;
  99. menuitem.remove();
  100. menuButton.click();
  101. GM_setValue('clearSvg', globalVariable.get('clearSvg'));
  102. resolve(true);
  103. }, 100);
  104. });
  105. }
  106.  
  107. function clearChats() {
  108. let url = '/backend-api/conversations';
  109. let method = 'PATCH';
  110. let Token = globalVariable.get('accessToken');
  111. if (Token == null) {
  112. alert('Token is null, please refresh the page and try again.Maybe the execution timing of the oil monkey script is set incorrectly.Please set to `document-start`!');
  113. return;
  114. }
  115. let headers = {
  116. Authorization: 'Bearer ' + Token,
  117. 'Content-Type': 'application/json'
  118. };
  119. let body = { is_visible: false };
  120. (async () => {
  121. let NewChatHistoryElement = globalVariable.get('NewChatHistoryElement');
  122. let rHElement = globalVariable.get('rH');
  123. if (rHElement && $(NewChatHistoryElement).find(rHElement).length > 0) {
  124. return;
  125. }
  126. let lis = $(NewChatHistoryElement).find('ol').eq(0).find('li');
  127. if (lis.length === 0) {
  128. return;
  129. }
  130. $(NewChatHistoryElement).find('ol').eq(0).find('li').hide();
  131. let f = await hookRequest.globalVariable.get('Fetch')(url, { method, headers, body: JSON.stringify(body) });
  132. await f.json();
  133. global_module.clickElement(globalVariable.get('NewChatElement')[0]);
  134. })();
  135. }
  136.  
  137. function createButtonOrShow(id = null, Show = null) {
  138. if (!id) {
  139. return;
  140. }
  141. if (document.getElementById(id) != null) {
  142. if (Show != null) document.getElementById(id).style.display = Show;
  143. return;
  144. }
  145. let border = document.querySelectorAll('div[class^="border-"]');
  146. border = border[border.length - 1];
  147. let div = document.createElement('div');
  148. div.id = id;
  149. let className = border.childNodes[0].className;
  150. div.className = className;
  151. border.insertBefore(div, border.childNodes[0]);
  152. return div;
  153. }
  154.  
  155. async function getbrowserLanguageStr(text) {
  156. return new Promise(async (resolve) => {
  157. let r = await globalVariable.get('TranslateMachine').Translate(text, 'auto', browserLanguage, true);
  158. resolve(r.result);
  159. });
  160. }
  161.  
  162. function createOrShowClearButton(Show = null) {
  163. let div = createButtonOrShow('_clearButton_', Show);
  164. (async () => {
  165. div.innerHTML = globalVariable.get('clearSvg')[0] + (await getbrowserLanguageStr('Clear Conversations'));
  166. })();
  167. div.name = 0;
  168. div.addEventListener('click', function () {
  169. let title = 'Clear Conversations';
  170. if (div.name === 0) {
  171. title = 'Confirm ' + title;
  172. div.name = 1;
  173. } else {
  174. div.name = 0;
  175. clearChats();
  176. }
  177. (async () => {
  178. div.innerHTML = globalVariable.get('clearSvg')[div.name] + (await getbrowserLanguageStr(title));
  179. })();
  180. });
  181. }
  182.  
  183. function addTextBase() {
  184. let style = $('body').find('style[id="text-base"]').eq(0);
  185. if (style.length != 0) {
  186. return;
  187. }
  188. style = document.createElement('style');
  189. style.id = 'text-base';
  190. let css = `.text-base {
  191. max-width: 92%;
  192. }`;
  193. style.innerHTML = css;
  194. document.body.appendChild(style);
  195. }
  196.  
  197. async function initUseElement() {
  198. if (globalVariable.get('NewChatHistoryElement') != null) {
  199. return;
  200. }
  201. let ChatHistoryElement = $('div[class*="items-center"][class*="text"]').eq(0);
  202. globalVariable.set('NewChatHistoryElement', ChatHistoryElement);
  203. let newChat = ChatHistoryElement.parent().prev().prev().eq(0);
  204. if (newChat[0].tagName !== 'A') {
  205. newChat = newChat.find('a').eq(0);
  206. }
  207. newChat = newChat.eq(0);
  208. globalVariable.set('NewChatElement', newChat);
  209. await InitSvg();
  210. createOrShowClearButton();
  211. // configButton();
  212. }
  213.  
  214. (async () => {
  215. // eslint-disable-next-line no-undef
  216. globalVariable.set('TranslateMachine', new TranslateMachine());
  217. hookRequest.FetchCallback.add('/api/auth/session', (_object, period) => {
  218. if (period !== 'done') {
  219. return;
  220. }
  221. addTextBase();
  222. let json = JSON.parse(_object.text);
  223. let accessToken = json.accessToken;
  224. localStorage.setItem('ChatGPT.accessToken', accessToken);
  225. globalVariable.set('accessToken', accessToken);
  226. });
  227. hookRequest.FetchCallback.add('/backend-api/conversation', (_object, period) => {
  228. if (period === 'done') {
  229. return;
  230. }
  231. let method = _object.args[1].method;
  232. if (method != 'POST') {
  233. return;
  234. }
  235. let additional = 'Please reply me with ' + browserLanguage;
  236. let body = JSON.parse(_object.args[1].body);
  237. let messages = body.messages;
  238. if (messages instanceof Array) {
  239. for (let i = 0; i < messages.length; i++) {
  240. let parts = messages[i].content.parts;
  241. if (parts instanceof Array) {
  242. for (let j = 0; j < parts.length; j++) {
  243. if (parts[j].indexOf('additional') != -1) {
  244. continue;
  245. }
  246. parts[j] = parts[j] + '\n' + additional;
  247. }
  248. }
  249. }
  250. }
  251. _object.args[1].body = JSON.stringify(body);
  252. setTimeout(() => {
  253. addTextBase();
  254. }, 100);
  255. });
  256. hookRequest.FetchCallback.add('/backend-api/conversations', (_object, period) => {
  257. if (period !== 'done') {
  258. return;
  259. }
  260. addTextBase();
  261. let url = _object.args[0];
  262. if (url.indexOf('?') == -1) {
  263. return;
  264. }
  265. let json = JSON.parse(_object.text);
  266. if (json.total === 0) {
  267. let title = '{_reserveHistory_}';
  268. json.total = 0;
  269. let time = new Date().toISOString();
  270. json.items = [{ id: '', title, create_time: time, update_time: time }];
  271. (async () => {
  272. let rH = await global_module.waitForElement('div:contains("' + title + '")[class*="text-ellipsis"]', null, null, 10, -1);
  273. rH = rH.eq(0);
  274. rH.parent().hide();
  275. globalVariable.set('rH', rH);
  276. })();
  277. }
  278. initUseElement();
  279. _object.text = JSON.stringify(json);
  280. return _object;
  281. });
  282. })();