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