ChatGPT 增强

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

当前为 2023-05-06 提交的版本,查看 最新版本

  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.25.17
  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 hide = function (tryOne) {
  127. $(NewChatHistoryElement).parents('nav').find('ol').eq(0).find('li[class]').hide();
  128. if (tryOne) {
  129. setTimeout(() => {
  130. hide(false);
  131. }, 1000);
  132. }
  133. };
  134. hide(true);
  135. conversationsToTrashCan();
  136. setTimeout(() => {
  137. hide(true);
  138. }, 1000);
  139. global_module.clickElement(globalVariable.get('NewChatElement')[0]);
  140. hookRequest.globalVariable.get('Fetch')(url, { method, headers, body: JSON.stringify(body) });
  141. })();
  142. }
  143.  
  144. function createButtonOrShow(id = null, Show = null) {
  145. if (!id) {
  146. return;
  147. }
  148. if (document.getElementById(id) != null) {
  149. if (Show != null) document.getElementById(id).style.display = Show;
  150. return;
  151. }
  152. let border = document.querySelectorAll('div[class^="border-"]');
  153. border = border[border.length - 1];
  154. let div = document.createElement('div');
  155. div.id = id;
  156. let className = border.childNodes[0].className;
  157. div.className = className;
  158. border.insertBefore(div, border.childNodes[0]);
  159. return div;
  160. }
  161.  
  162. async function getbrowserLanguageStr(text) {
  163. return new Promise(async (resolve) => {
  164. resolve((await globalVariable.get('TranslateMachine').Translate(text, 'auto', browserLanguage, true)).result);
  165. });
  166. }
  167.  
  168. function conversationsToTrashCan() {
  169. let conversations = globalVariable.get('cacheConversations');
  170. conversations.forEach((value, key) => {
  171. globalVariable.get('trashCanConversations').set(key, '');
  172. });
  173. globalVariable.set('cacheConversations', new Map());
  174. }
  175.  
  176. function createOrShowClearButton(Show = null) {
  177. let div = createButtonOrShow('_clearButton_', Show);
  178. if (!div) {
  179. return;
  180. }
  181. (async () => {
  182. div.innerHTML = globalVariable.get('clearSvg')[0] + (await getbrowserLanguageStr('Clear Conversations'));
  183. })();
  184. div.name = 0;
  185. div.addEventListener('click', function () {
  186. let title = 'Clear Conversations';
  187. if (div.name === 0) {
  188. title = 'Confirm ' + title;
  189. div.name = 1;
  190. } else {
  191. div.name = 0;
  192. clearChats();
  193. }
  194. (async () => {
  195. div.innerHTML = globalVariable.get('clearSvg')[div.name] + (await getbrowserLanguageStr(title));
  196. })();
  197. });
  198. }
  199.  
  200. function addTextBase() {
  201. let style = $('body').find('style[id="text-base"]').eq(0);
  202. if (style.length != 0) {
  203. return;
  204. }
  205. style = document.createElement('style');
  206. style.id = 'text-base';
  207. let css = `.text-base {
  208. max-width: 92%;
  209. }`;
  210. style.innerHTML = css;
  211. document.body.appendChild(style);
  212. }
  213.  
  214. async function initUseElement() {
  215. let ChatHistoryElement = $('div[class*="items-center"][class*="text"]').eq(0);
  216. globalVariable.set('NewChatHistoryElement', ChatHistoryElement);
  217. let newChat = ChatHistoryElement.parents('nav').eq(0).find('a').eq(0);
  218. if (newChat.length === 0) {
  219. setTimeout(() => {
  220. initUseElement();
  221. }, 1000);
  222. return;
  223. }
  224. newChat = newChat.eq(0);
  225. globalVariable.set('NewChatElement', newChat);
  226. await InitSvg();
  227. createOrShowClearButton();
  228. }
  229.  
  230. function getContentMainBodyHistoricalDialogue(_object, period) {
  231. if (period !== 'done') {
  232. return;
  233. }
  234. setTimeout(() => {
  235. initUseElement();
  236. }, 1000);
  237. }
  238.  
  239. globalVariable.set('cacheConversations', new Map());
  240. globalVariable.set('trashCanConversations', new Map());
  241.  
  242. (async () => {
  243. // eslint-disable-next-line no-undef
  244. globalVariable.set('TranslateMachine', new TranslateMachine());
  245. hookRequest.FetchCallback.add('/api/auth/session', (_object, period) => {
  246. if (period !== 'done') {
  247. return;
  248. }
  249. addTextBase();
  250. let json = JSON.parse(_object.text);
  251. let accessToken = json.accessToken;
  252. localStorage.setItem('ChatGPT.accessToken', accessToken);
  253. globalVariable.set('accessToken', accessToken);
  254. });
  255. hookRequest.FetchCallback.add('/backend-api/conversation', (_object, period) => {
  256. if ('done' === period) {
  257. return;
  258. }
  259. if ('doing' === period) {
  260. return;
  261. }
  262. let method = _object.args[1].method;
  263. if (method != 'POST') {
  264. return;
  265. }
  266. let additional = 'Please reply me with ';
  267. let additionals = additional + browserLanguage;
  268. let body = JSON.parse(_object.args[1].body);
  269. let messages = body.messages;
  270. if (messages instanceof Array) {
  271. for (let i = 0; i < messages.length; i++) {
  272. let parts = messages[i].content.parts;
  273. if (parts instanceof Array) {
  274. for (let j = 0; j < parts.length; j++) {
  275. if (parts[j].indexOf(additional) != -1) {
  276. continue;
  277. }
  278. parts[j] = parts[j] + '\n' + additionals;
  279. }
  280. }
  281. }
  282. }
  283. _object.args[1].body = JSON.stringify(body);
  284. setTimeout(() => {
  285. addTextBase();
  286. }, 100);
  287. });
  288. hookRequest.FetchCallback.add('/backend-api/conversations', (_object, period) => {
  289. if (period !== 'done') {
  290. return;
  291. }
  292. addTextBase();
  293. let url = _object.args[0];
  294. if (url.indexOf('?') == -1) {
  295. return;
  296. }
  297. let json = JSON.parse(_object.text);
  298. if (json.items.length !== 0) {
  299. let i = 0;
  300. while (i != json.items.length) {
  301. let id = json.items[i].id;
  302. if (globalVariable.get('trashCanConversations').has(id)) {
  303. json.items.splice(i, 1);
  304. json.total--;
  305. continue;
  306. }
  307. if (globalVariable.get('cacheConversations').has(id)) {
  308. i++;
  309. continue;
  310. }
  311. hookRequest.FetchCallback.add('/backend-api/conversation/' + id, getContentMainBodyHistoricalDialogue);
  312. globalVariable.get('cacheConversations').set(id, json.items[i]);
  313. i++;
  314. }
  315. }
  316. if (json.items.length === 0) {
  317. let title = '{_reserveHistory_}';
  318. json.total = 0;
  319. let time = new Date().toISOString();
  320. json.items = [{ id: '', title, create_time: time, update_time: time }];
  321. (async () => {
  322. let rH = await global_module.waitForElement('div:contains("' + title + '")[class*="text-ellipsis"]', null, null, 10, -1);
  323. rH = rH.eq(0);
  324. rH.parent().hide();
  325. globalVariable.set('rH', rH);
  326. })();
  327. }
  328. initUseElement();
  329. _object.text = JSON.stringify(json);
  330. return _object;
  331. });
  332. })();