ChatGPT 增强

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

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

  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.24
  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://gf.qytechs.cn/scripts/464929-module-jquery-xiaoying/code/module_jquery_XiaoYing.js
  38. // @require https://gf.qytechs.cn/scripts/464780-global-module/code/global_module.js
  39. // @require https://gf.qytechs.cn/scripts/465643-ajaxhookerlatest/code/ajaxHookerLatest.js
  40. // @require https://gf.qytechs.cn/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. // eslint-disable-next-line no-undef
  61. ajaxHooker.protect();
  62.  
  63. var globalVariable = new Map();
  64. var browserLanguage = navigator.language;
  65. var ignoreHookStr = '&ignoreHookStr';
  66.  
  67. async function InitSvg() {
  68. return new Promise(async (resolve) => {
  69. let Svg = GM_getValue('clearSvg', []);
  70. if (Svg.length !== 0) {
  71. globalVariable.set('clearSvg', Svg);
  72. resolve(true);
  73. return;
  74. }
  75. let menuButton = document.querySelector('button[id^="headlessui-menu-button-"]');
  76. menuButton.click();
  77. let menuitems = [];
  78. await new Promise((resolve) => {
  79. let Timer = setInterval(() => {
  80. menuitems = document.querySelectorAll('a[role="menuitem"]');
  81. if (menuitems.length < 4) {
  82. return;
  83. }
  84. clearInterval(Timer);
  85. resolve();
  86. }, 100);
  87. });
  88. let menuitem = menuitems[1];
  89. if (menuitem.name === 1) {
  90. return;
  91. }
  92. let svg = menuitem.querySelector('svg');
  93. globalVariable.set('clearSvg', []);
  94. globalVariable.get('clearSvg').push(svg.outerHTML);
  95. menuitem.click();
  96. setTimeout(() => {
  97. svg = menuitem.querySelector('svg');
  98. globalVariable.get('clearSvg').push(svg.outerHTML);
  99. menuitem.name = 1;
  100. menuitem.remove();
  101. menuButton.click();
  102. GM_setValue('clearSvg', globalVariable.get('clearSvg'));
  103. resolve(true);
  104. }, 100);
  105. });
  106. }
  107.  
  108. function clearChats() {
  109. let url = '/backend-api/conversations';
  110. let method = 'PATCH';
  111. let Token = globalVariable.get('accessToken');
  112. if (Token == null) {
  113. 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`!');
  114. return;
  115. }
  116. let headers = {
  117. Authorization: 'Bearer ' + Token,
  118. 'Content-Type': 'application/json'
  119. };
  120. let body = { is_visible: false };
  121. (async () => {
  122. let NewChatHistoryElement = globalVariable.get('NewChatHistoryElement');
  123. let rHElement = globalVariable.get('rH');
  124. if (rHElement && $(NewChatHistoryElement).find(rHElement).length > 0) {
  125. return;
  126. }
  127. let hide = function (tryOne) {
  128. $(NewChatHistoryElement).parents('nav').find('ol').eq(0).find('li[class]').hide();
  129. if (tryOne) {
  130. setTimeout(() => {
  131. hide(false);
  132. }, 1000);
  133. }
  134. };
  135. hide(true);
  136. conversationsToTrashCan();
  137. setTimeout(() => {
  138. hide(true);
  139. }, 1000);
  140. global_module.clickElement(globalVariable.get('NewChatElement')[0]);
  141. url = global_module.SetUrlParm(url, 'ignoreHookStr', '0');
  142. fetch(url + ignoreHookStr, { method, headers, body: JSON.stringify(body) });
  143. })();
  144. }
  145.  
  146. function createButtonOrShow(id = null, Show = null) {
  147. if (!id) {
  148. return;
  149. }
  150. if (document.getElementById(id) != null) {
  151. if (Show != null) document.getElementById(id).style.display = Show;
  152. return;
  153. }
  154. let border = document.querySelectorAll('div[class^="border-"]');
  155. border = border[border.length - 1];
  156. let div = document.createElement('div');
  157. div.id = id;
  158. let className = border.childNodes[0].className;
  159. div.className = className;
  160. border.insertBefore(div, border.childNodes[0]);
  161. return div;
  162. }
  163.  
  164. async function getbrowserLanguageStr(text) {
  165. return new Promise(async (resolve) => {
  166. let cache = localStorage.getItem(text + '_' + browserLanguage);
  167. if (cache) {
  168. resolve(cache);
  169. return;
  170. }
  171. cache = (await globalVariable.get('TranslateMachine').Translate(text, 'auto', browserLanguage, true)).result;
  172. if (cache) {
  173. resolve(cache);
  174. localStorage.setItem(text + '_' + browserLanguage, cache);
  175. return;
  176. }
  177. resolve(cache);
  178. });
  179. }
  180.  
  181. function conversationsToTrashCan() {
  182. let conversations = globalVariable.get('cacheConversations');
  183. conversations.forEach((value, key) => {
  184. globalVariable.get('trashCanConversations').set(key, '');
  185. });
  186. globalVariable.set('cacheConversations', new Map());
  187. }
  188.  
  189. function createOrShowClearButton(Show = null) {
  190. let div = createButtonOrShow('_clearButton_', Show);
  191. if (!div) {
  192. return;
  193. }
  194. (async () => {
  195. div.innerHTML = globalVariable.get('clearSvg')[0] + (await getbrowserLanguageStr('Clear Conversations'));
  196. })();
  197. div.name = 0;
  198. div.addEventListener('click', function () {
  199. let title = 'Clear Conversations';
  200. if (div.name === 0) {
  201. title = 'Confirm ' + title;
  202. div.name = 1;
  203. } else {
  204. div.name = 0;
  205. clearChats();
  206. }
  207. (async () => {
  208. div.innerHTML = globalVariable.get('clearSvg')[div.name] + (await getbrowserLanguageStr(title));
  209. })();
  210. });
  211. }
  212.  
  213. function addTextBase() {
  214. let style = $('body').find('style[id="text-base"]').eq(0);
  215. if (style.length != 0) {
  216. return;
  217. }
  218. style = document.createElement('style');
  219. style.id = 'text-base';
  220. let css = `.text-base {
  221. max-width: 92%;
  222. }`;
  223. style.innerHTML = css;
  224. document.body.appendChild(style);
  225. }
  226.  
  227. async function initUseElement() {
  228. let ChatHistoryElement = $('div[class*="items-center"][class*="text"]').eq(0);
  229. globalVariable.set('NewChatHistoryElement', ChatHistoryElement);
  230. let newChat = ChatHistoryElement.parents('nav').eq(0).find('a').eq(0);
  231. if (newChat.length === 0) {
  232. setTimeout(() => {
  233. initUseElement();
  234. }, 1000);
  235. return;
  236. }
  237. newChat = newChat.eq(0);
  238. globalVariable.set('NewChatElement', newChat);
  239. await InitSvg();
  240. createOrShowClearButton();
  241. }
  242.  
  243. function getContentMainBodyHistoricalDialogue(req, res, Text, period) {
  244. if (period !== 'done') {
  245. return;
  246. }
  247. setTimeout(() => {
  248. initUseElement();
  249. }, 1000);
  250. }
  251.  
  252. globalVariable.set('cacheConversations', new Map());
  253. globalVariable.set('trashCanConversations', new Map());
  254.  
  255. var HookFun = new Map();
  256. HookFun.set('/api/auth/session', function (req, res, Text, period) {
  257. if (period === 'preload') {
  258. return;
  259. }
  260. new Promise(async (resolve) => {
  261. if (period !== 'done') {
  262. return;
  263. }
  264. addTextBase();
  265. let json = JSON.parse(Text);
  266. let accessToken = json.accessToken;
  267. localStorage.setItem('ChatGPT.accessToken', accessToken);
  268. globalVariable.set('accessToken', accessToken);
  269. resolve(null);
  270. });
  271. });
  272. HookFun.set('/backend-api/conversation', function (req, res, Text, period) {
  273. if (period === 'preload') {
  274. let additional = 'Please reply me with ';
  275. let additionals = additional + browserLanguage;
  276. let body = JSON.parse(req.data);
  277. let messages = body.messages;
  278. if (messages instanceof Array) {
  279. for (let i = 0; i < messages.length; i++) {
  280. let parts = messages[i].content.parts;
  281. if (parts instanceof Array) {
  282. for (let j = 0; j < parts.length; j++) {
  283. if (parts[j].indexOf(additional) != -1) {
  284. continue;
  285. }
  286. parts[j] = parts[j] + '\n' + additionals;
  287. }
  288. }
  289. }
  290. }
  291. req.data = JSON.stringify(body);
  292. setTimeout(() => {
  293. addTextBase();
  294. }, 100);
  295. return;
  296. }
  297. return new Promise(async (resolve) => {
  298. if (period !== 'done') {
  299. return;
  300. }
  301. resolve(null);
  302. });
  303. });
  304. HookFun.set('/backend-api/conversations', function (req, res, Text, period) {
  305. if (period === 'preload') {
  306. return;
  307. }
  308. return new Promise(async (resolve) => {
  309. if (period !== 'done') {
  310. return;
  311. }
  312. addTextBase();
  313. let url = req.url;
  314. if (url.indexOf('?') == -1) {
  315. return;
  316. }
  317. let json = JSON.parse(Text);
  318. if (json.items.length !== 0) {
  319. let i = 0;
  320. while (i != json.items.length) {
  321. let id = json.items[i].id;
  322. if (globalVariable.get('trashCanConversations').has(id)) {
  323. json.items.splice(i, 1);
  324. json.total--;
  325. continue;
  326. }
  327. if (globalVariable.get('cacheConversations').has(id)) {
  328. i++;
  329. continue;
  330. }
  331. HookFun.set('/backend-api/conversation/' + id, getContentMainBodyHistoricalDialogue);
  332. globalVariable.get('cacheConversations').set(id, json.items[i]);
  333. i++;
  334. }
  335. }
  336. if (json.items.length === 0) {
  337. let title = '{_reserveHistory_}';
  338. json.total = 0;
  339. let time = new Date().toISOString();
  340. json.items = [{ id: '', title, create_time: time, update_time: time }];
  341. (async () => {
  342. let rH = await global_module.waitForElement('div:contains("' + title + '")[class*="text-ellipsis"]', null, null, 10, -1);
  343. rH = rH.eq(0);
  344. rH.parent().hide();
  345. globalVariable.set('rH', rH);
  346. })();
  347. }
  348. initUseElement();
  349. Text = JSON.stringify(json);
  350. resolve(Text);
  351. });
  352. });
  353.  
  354. function handleResponse(request) {
  355. if (!request) {
  356. return;
  357. }
  358. if (request.url.indexOf(ignoreHookStr) != -1) {
  359. return;
  360. }
  361. let tempUrl = request.url;
  362. if (tempUrl.indexOf('http') == -1 && tempUrl[0] == '/') {
  363. tempUrl = location.origin + tempUrl;
  364. }
  365. let pathname = new URL(tempUrl).pathname;
  366. let fun = HookFun.get(pathname);
  367. if (!fun) {
  368. return;
  369. }
  370. fun(request, null, null, 'preload');
  371. request.response = (res) => {
  372. let Type = 0;
  373. let responseText = res.responseText;
  374. if (typeof responseText !== 'string') {
  375. Type = 1;
  376. responseText = res.text;
  377. }
  378. if (typeof responseText !== 'string') {
  379. Type = 2;
  380. responseText = JSON.stringify(res.json);
  381. }
  382. const oldText = responseText;
  383. res.responseText = new Promise(async (resolve) => {
  384. let ret = await fun(request, res, responseText, 'done');
  385. if (!ret) {
  386. ret = oldText;
  387. }
  388. if (Type === 2) {
  389. if (typeof ret === 'string') {
  390. ret = JSON.parse(ret);
  391. }
  392. }
  393. resolve(ret);
  394. });
  395. };
  396. }
  397.  
  398. // eslint-disable-next-line no-undef
  399. ajaxHooker.hook(handleResponse);
  400. // eslint-disable-next-line no-undef
  401. globalVariable.set('TranslateMachine', new TranslateMachine());

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址