@kudoai/chatgpt.js 2.7.1 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -45,16 +45,16 @@
45
45
  [![](https://img.shields.io/github/stars/KudoAI/chatgpt.js?label=Stars&color=af68ff&logo=github&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/stargazers)
46
46
  [![](https://img.shields.io/badge/License-MIT-green.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/blob/main/LICENSE.md)
47
47
  [![](https://img.shields.io/github/commit-activity/m/KudoAI/chatgpt.js?label=Commits&logo=github&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/commits/main)
48
- [![](https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v2.7.1&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/tree/v2.7.1/dist/chatgpt.min.js)
48
+ [![](https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v2.9.0&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge)](https://github.com/KudoAI/chatgpt.js/tree/v2.9.0/dist/chatgpt.min.js)
49
49
  [![](https://img.shields.io/codefactor/grade/github/kudoai/chatgpt.js?label=Code+Quality&logo=codefactor&logoColor=white&labelColor=464646&color=1acc6c&style=for-the-badge)](https://www.codefactor.io/repository/github/kudoai/chatgpt.js)
50
50
  [![](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fsonarcloud.io%2Fapi%2Fmeasures%2Fcomponent%3Fcomponent%3Dkudoai_chatgpt.js%26metricKeys%3Dvulnerabilities&query=%24.component.measures.0.value&style=for-the-badge&logo=sonarcloud&logoColor=white&labelColor=464646&label=Vulnerabilities&color=gold)](https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=kudoai_chatgpt.js)
51
51
  [![](https://img.shields.io/badge/Mentioned_in-Awesome-cca8c4?logo=awesomelists&logoColor=white&labelColor=464646&style=for-the-badge)](https://github.com/sindresorhus/awesome-chatgpt#javascript)
52
52
  [![](https://img.shields.io/badge/Featured_on-Product_Hunt-ff6154?logo=producthunt&logoColor=white&labelColor=464646&style=for-the-badge)](https://www.producthunt.com/posts/chatgpt-js)
53
- ![](https://img.shields.io/badge/jsDelivr_Hits-1,500,000+-49c5d8.svg?logo=jsdelivr&logoColor=white&labelColor=464646&style=for-the-badge)
53
+ ![](https://img.shields.io/badge/jsDelivr_Requests-1,500,000+-2bbbd8.svg?logo=jsdelivr&logoColor=white&labelColor=464646&style=for-the-badge)
54
54
 
55
55
  </div>
56
56
 
57
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
57
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
58
58
 
59
59
  <div id="intro">
60
60
 
@@ -69,7 +69,7 @@
69
69
  - Easy-to-use
70
70
  - Lightweight (yet optimally performant)
71
71
 
72
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
72
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
73
73
 
74
74
  <div id="importing">
75
75
 
@@ -83,7 +83,7 @@
83
83
 
84
84
  ```js
85
85
  (async () => {
86
- await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.7.1/dist/chatgpt.min.js');
86
+ await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.9.0/dist/chatgpt.min.js');
87
87
  // Your code here...
88
88
  })();
89
89
  ```
@@ -92,7 +92,7 @@
92
92
 
93
93
  ```js
94
94
  var xhr = new XMLHttpRequest();
95
- xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.7.1/dist/chatgpt.min.js');
95
+ xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.9.0/dist/chatgpt.min.js');
96
96
  xhr.onload = function () {
97
97
  if (xhr.status === 200) {
98
98
  var chatgptJS = document.createElement('script');
@@ -114,7 +114,7 @@ function yourCode() {
114
114
 
115
115
  ```js
116
116
  ...
117
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.7.1/dist/chatgpt.min.js
117
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@2.9.0/dist/chatgpt.min.js
118
118
  // ==/UserScript==
119
119
 
120
120
  // Your code here...
@@ -150,7 +150,7 @@ export { chatgpt }
150
150
  })();
151
151
  ```
152
152
 
153
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
153
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
154
154
 
155
155
  <div id="npm">
156
156
 
@@ -168,7 +168,7 @@ After installation, navigate to `node_modules/@kudoai/chatgpt.js` to find the li
168
168
 
169
169
  </div>
170
170
 
171
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
171
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
172
172
 
173
173
  <div id="usage">
174
174
 
@@ -189,9 +189,9 @@ chatgpt.get('reply', 'last');
189
189
 
190
190
  Each call equally fetches the last response. If you think it works, it probably will... so just type it!
191
191
 
192
- If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v2.7.1/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
192
+ If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v2.9.0/docs/USERGUIDE.md), or simply submit an [issue](https://github.com/KudoAI/chatgpt.js/issues) or [PR](https://github.com/KudoAI/chatgpt.js/pulls) and it will be integrated, ezpz!
193
193
 
194
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
194
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
195
195
 
196
196
  <div id="showcase">
197
197
 
@@ -263,7 +263,7 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
263
263
  If you've made something w/ chatgpt.js you want to share, email <a href="mailto:showcase@chatgptjs.org">showcase@chatgptjs.org</a> or just open a <a href="https://github.com/KudoAI/chatgpt.js/pulls" target="_blank" rel="noopener">pull request</a>!
264
264
  </p>
265
265
 
266
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
266
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
267
267
 
268
268
  <div id="contributors">
269
269
 
@@ -301,6 +301,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
301
301
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/44357327?first-contrib=2024.2.14-msg-fetching-for-localization-fails-report&h=51&w=51&mask=circle&maxage=7d "@thedayofcondor")](https://github.com/thedayofcondor)
302
302
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/111466842?first-contrib=2024.2.15-add-en-gb-locale&h=51&w=51&mask=circle&maxage=7d "@Luwa-Tech")](https://github.com/Luwa-Tech)
303
303
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/61795?first-contrib=2024.5.9-update-css-selector-for-getregeneratebutton&h=51&w=51&mask=circle&maxage=7d "@micz")](https://github.com/micz)
304
+ [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/17583722?first-contrib=2024.5.17-chrome-starter-manifest-matches-outdated-alert&h=51&w=51&mask=circle&maxage=7d "@imranaalam")](https://github.com/imranaalam)
304
305
  [![](https://images.weserv.nl/?url=https://avatars.githubusercontent.com/in/29110&h=51&w=51&mask=circle&maxage=7d "Dependabot")](https://github.com/dependabot)
305
306
  <a href="https://chatgpt.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/chatgpt/black-on-white/icon189.png?h=50&w=50&mask=circle&maxage=7d"><img src="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/chatgpt/white-on-black/icon189.png?h=50&w=50&mask=circle&maxage=7d" title="ChatGPT"></picture></a>
306
307
  <a href="https://poe.com"><picture><source media="(prefers-color-scheme: dark)" srcset="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/poe/w-purple-blue-stripes/black-on-white/icon175.png?h=50&w=50&mask=circle&maxage=7d"><img src="https://images.weserv.nl/?url=https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@main/media/images/icons/platforms/poe/w-purple-blue-stripes/white-on-black/icon175.png?h=50&w=50&mask=circle&maxage=7d" title="Poe"></picture></a>
@@ -308,7 +309,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
308
309
 
309
310
  </div><br>
310
311
 
311
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
312
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
312
313
 
313
314
  <div id="partners">
314
315
 
@@ -329,12 +330,12 @@ This library exists thanks to code, translations, issues & ideas from the follow
329
330
 
330
331
  <br>
331
332
 
332
- <img height=8px width="100%" src="https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js@5e41346/docs/assets/images/aqua-separator.png">
333
+ <img height=8px width="100%" src="https://media.chatgptjs.org/images/separators/gradient-aqua.png?78210a7">
333
334
 
334
335
  <div align="center">
335
336
 
336
337
  **[Releases](https://github.com/KudoAI/chatgpt.js/releases)** /
337
- [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v2.7.1/docs/USERGUIDE.md) /
338
+ [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v2.9.0/docs/USERGUIDE.md) /
338
339
  [Discuss](https://github.com/KudoAI/chatgpt.js/discussions) /
339
340
  <a href="#--------------------------------------------------------------------------------english---------简体中文---------繁體中文---------日本---------한국인---------हिंदी---------नेपाली---------deutsch---------español---------français---------italiano---------nederlands---------português---------việt----">Back to top ↑</a>
340
341
 
package/chatgpt.js CHANGED
@@ -8,11 +8,11 @@ const endpoints = {
8
8
  assets: 'https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js',
9
9
  openAI: {
10
10
  session: 'https://chatgpt.com/api/auth/session',
11
- chats: 'https://chat.openai.com/backend-api/conversations',
12
- chat: 'https://chat.openai.com/backend-api/conversation',
13
- share_create: 'https://chat.openai.com/backend-api/share/create',
14
- share: 'https://chat.openai.com/backend-api/share',
15
- instructions: 'https://chat.openai.com/backend-api/user_system_messages'
11
+ chats: 'https://chatgpt.com/backend-api/conversations',
12
+ chat: 'https://chatgpt.com/backend-api/conversation',
13
+ share_create: 'https://chatgpt.com/backend-api/share/create',
14
+ share: 'https://chatgpt.com/backend-api/share',
15
+ instructions: 'https://chatgpt.com/backend-api/user_system_messages'
16
16
  }
17
17
  };
18
18
 
@@ -383,21 +383,25 @@ const chatgpt = { // eslint-disable-line no-redeclare
383
383
  const validMethods = ['api', 'dom'];
384
384
  method = (method || 'dom').trim().toLowerCase(); // set to 'dom' by default
385
385
  if (method && !validMethods.includes(method))
386
- return console.log(`Method argument must be one of: [${ validMethods }]`);
386
+ return console.error(`Method argument must be one of: [${validMethods}]`);
387
387
 
388
388
  if (method == 'dom') {
389
- try { await chatgpt.getChatData(); } catch { return; } // check if chat history exists
390
- chatgpt.menu.open(); setTimeout(() => { // open settings
389
+ const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
390
+ try {
391
+ chatgpt.menu.open(); await delay(10);
391
392
  const settingsBtn = document.querySelector(
392
- 'a[role="menuitem"] svg path[d*="M12.003 10.5a1.5"]')?.parentNode.parentNode;
393
- if (settingsBtn) settingsBtn.click();
394
- setTimeout(() => { // clear chats
395
- const settingsBtns = document.querySelectorAll('[id*=radix] button'),
396
- deleteBtn = settingsBtns[settingsBtns.length - 1];
397
- if (deleteBtn) deleteBtn.click();
398
- setTimeout(() => { // confirm clear
399
- document.querySelector('button[class*="danger"').click();
400
- }, 10); }, 333); }, 10);
393
+ 'a[role="menuitem"] svg path[d*="M12.003 10.5a1.5"]').parentNode.parentNode;
394
+ settingsBtn.click(); await delay(333);
395
+ const settingsBtns = document.querySelectorAll('[id*=radix] button'),
396
+ deleteBtn = settingsBtns[settingsBtns.length - 1];
397
+ deleteBtn.click(); await delay(10);
398
+ document.querySelector('button[class*="danger"').click(); // confirm clear
399
+ return console.info('Chats successfully cleared.');
400
+ } catch (err) {
401
+ console.error(err.message);
402
+ if (arguments.length == 0) {
403
+ console.info('Using backend API method instead.'); this.clearChats('api'); }
404
+ }
401
405
 
402
406
  } else { // API method
403
407
  // NOTE: DOM is not updated to reflect new empty chat list (until session refresh)
@@ -413,7 +417,7 @@ const chatgpt = { // eslint-disable-line no-redeclare
413
417
  console.info('Chats successfully cleared'); resolve();
414
418
  };
415
419
  xhr.send(JSON.stringify({ is_visible: false }));
416
- }).catch(reject);
420
+ }).catch(err => reject(new Error(err.message)));
417
421
  });
418
422
  }
419
423
  },
@@ -493,6 +497,8 @@ const chatgpt = { // eslint-disable-line no-redeclare
493
497
  }
494
498
  },
495
499
 
500
+ continue: function() { this.response.continue(); },
501
+
496
502
  detectLanguage: async function(text) {
497
503
  if (!text) return console.error('Text argument not supplied. Pass some text!');
498
504
  if (typeof text !== 'string') return console.error('Text argument must be a string!');
@@ -842,20 +848,18 @@ const chatgpt = { // eslint-disable-line no-redeclare
842
848
  });});};
843
849
 
844
850
  // Return chat data
845
- return new Promise(resolve => { chatgpt.getAccessToken().then(token => {
846
- if (!detailsToGet.includes('msg')) getChatDetails(token, detailsToGet).then(data => {
847
- return resolve(data); // get just the chat details
848
- });
849
- else getChatMsgs(token).then(messages => { return resolve(messages); }); // otherwise get specific msg's
850
- });});
851
+ return new Promise(resolve => chatgpt.getAccessToken().then(token => {
852
+ return resolve(detailsToGet.includes('msg') ? getChatMsgs(token)
853
+ : getChatDetails(token, detailsToGet));
854
+ }));
851
855
  },
852
856
 
853
857
  getChatInput: function() { return chatgpt.getChatBox().value; },
854
858
 
855
859
  getContinueGeneratingButton: function() {
856
- for (const svg of document.querySelectorAll('form button svg')) {
857
- if (svg.querySelector('polygon[points*="11 19 2 12 11 5 11 19"]'))
858
- return svg.parentNode.parentNode;
860
+ for (const formBtnSVG of document.querySelectorAll('form button svg')) {
861
+ if (formBtnSVG.querySelector('path[d*="M4.472 2.5a1"]'))
862
+ return formBtnSVG.parentNode.parentNode;
859
863
  }},
860
864
 
861
865
  getFooterDiv: function() { return document.querySelector('main form').parentNode.parentNode.nextElementSibling; },
@@ -863,11 +867,13 @@ const chatgpt = { // eslint-disable-line no-redeclare
863
867
  getLastPrompt: function() { return chatgpt.getChatData('active', 'msg', 'user', 'latest'); },
864
868
  getLastResponse: function() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
865
869
 
866
- getNewChatLink: function() {
867
- for (const navLink of document.querySelectorAll('nav a')) {
868
- if (/(new|clear) chat/i.test(navLink.text)) {
869
- return navLink;
870
- }}},
870
+ getNewChatButton: function() {
871
+ for (const navBtnSVG of document.querySelectorAll('nav button svg'))
872
+ if (navBtnSVG.querySelector('path[d*="M15.673 3.913a3.121"]')) // new chat icon found
873
+ return navBtnSVG.parentNode;
874
+ },
875
+
876
+ getNewChatLink: function() { return document.querySelector('nav a[href="/"]'); },
871
877
 
872
878
  getRegenerateButton: function() {
873
879
  for (const mainSVG of document.querySelectorAll('main svg')) {
@@ -881,19 +887,21 @@ const chatgpt = { // eslint-disable-line no-redeclare
881
887
  // responseToGet = index of response to get (defaults to latest if '' unpassed)
882
888
  // regenResponseToGet = index of regenerated response to get (defaults to latest if '' unpassed)
883
889
 
884
- if (window.location.href.startsWith('https://chat.openai.com/c/'))
885
- return chatgpt.getResponseFromDOM.apply(null, arguments);
886
- else return chatgpt.getResponseFromAPI.apply(null, arguments);
890
+ return chatgpt.response.get(...arguments);
887
891
  },
888
892
 
889
893
  getResponseFromAPI: function(chatToGet, responseToGet) { return chatgpt.response.getFromAPI(chatToGet, responseToGet); },
890
894
  getResponseFromDOM: function(pos) { return chatgpt.response.getFromDOM(pos); },
891
895
  getScrollToBottomButton: function() { return document.querySelector('button[class*="cursor"][class*="bottom"]'); },
892
- getSendButton: function() { return document.querySelector('form button[class*="bottom"]'); },
896
+
897
+ getSendButton: function() {
898
+ return document.querySelector('[data-testid="send-button"]') // pre-GPT-4o
899
+ || document.querySelector('path[d*="M15.192 8.906a1.143"]')?.parentNode.parentNode; // post-GPT-4o
900
+ },
893
901
 
894
902
  getStopGeneratingButton: function() {
895
903
  for (const svg of document.querySelectorAll('form button svg')) {
896
- if (svg.querySelector('path[d*="2 0 0 1 2"]'))
904
+ if (svg.querySelector('path[d*="2 0 0 1 2"], rect'))
897
905
  return svg.parentNode;
898
906
  }},
899
907
 
@@ -907,11 +915,10 @@ const chatgpt = { // eslint-disable-line no-redeclare
907
915
  history: {
908
916
  isLoaded: function() {
909
917
  return new Promise(resolve => {
910
- const checkChatHistory = () => {
918
+ (function checkChatHistory() {
911
919
  if (document.querySelector('nav')) resolve(true);
912
920
  else setTimeout(checkChatHistory, 100);
913
- };
914
- checkChatHistory();
921
+ })();
915
922
  });}
916
923
  },
917
924
 
@@ -1047,17 +1054,19 @@ const chatgpt = { // eslint-disable-line no-redeclare
1047
1054
 
1048
1055
  isIdle: function() {
1049
1056
  return new Promise(resolve => {
1050
- const intervalId = setInterval(() => {
1051
- if (chatgpt.getRegenerateButton()) {
1052
- clearInterval(intervalId); resolve(true);
1053
- }}, 100);});},
1057
+ (function checkIsIdle() {
1058
+ if (chatgpt.getRegenerateButton()) resolve(true);
1059
+ else setTimeout(checkIsIdle, 100);
1060
+ })();
1061
+ });},
1054
1062
 
1055
1063
  isLoaded: function() {
1056
1064
  return new Promise(resolve => {
1057
- const intervalId = setInterval(() => {
1058
- if (document.querySelector('nav button[id*="menu"]')) {
1059
- clearInterval(intervalId); setTimeout(() => { resolve(true); }, 500);
1060
- }}, 100);});},
1065
+ (function checkIsLoaded() {
1066
+ if (chatgpt.getNewChatButton()) resolve(true);
1067
+ else setTimeout(checkIsLoaded, 100);
1068
+ })();
1069
+ });},
1061
1070
 
1062
1071
  isLightMode: function() { return document.documentElement.classList.toString().includes('light'); },
1063
1072
  isMobileDevice: function() { return chatgpt.browser.isMobile(); },
@@ -1153,15 +1162,13 @@ const chatgpt = { // eslint-disable-line no-redeclare
1153
1162
  },
1154
1163
 
1155
1164
  close: function() {
1156
- const menuBtn = document.querySelector('nav [id*="menu-button"][aria-expanded="true"]');
1157
- if (menuBtn) try { menuBtn.click(); } catch (err) { return console.error(err.message); }
1158
- else { console.info('Menu already hidden!'); }
1165
+ try { document.querySelector('nav [id*="menu-button"][aria-expanded="true"]').click(); }
1166
+ catch (err) { console.error(err.message); }
1159
1167
  },
1160
1168
 
1161
1169
  open: function() {
1162
- const menuBtn = document.querySelector('nav [id*="menu-button"][aria-expanded="false"]');
1163
- if (menuBtn) try { menuBtn.click(); } catch (err) { return console.error(err.message); }
1164
- else { console.info('Menu already open!'); }
1170
+ try { document.querySelector('nav [id*="menu-button"][aria-expanded="false"]').click(); }
1171
+ catch (err) { console.error(err.message); }
1165
1172
  }
1166
1173
  },
1167
1174
 
@@ -1408,13 +1415,15 @@ const chatgpt = { // eslint-disable-line no-redeclare
1408
1415
  resend: async function() { chatgpt.send(await chatgpt.getChatData('latest', 'msg', 'user', 'latest')); },
1409
1416
 
1410
1417
  response: {
1418
+ continue: function() { try { chatgpt.getContinueBtn().click(); } catch (err) { console.error(err.message); }},
1419
+
1411
1420
  get: function() {
1412
1421
  // * Returns response via DOM by index arg if OpenAI chat page is active, otherwise uses API w/ following args:
1413
1422
  // chatToGet = index|title|id of chat to get (defaults to latest if '' unpassed)
1414
1423
  // responseToGet = index of response to get (defaults to latest if '' unpassed)
1415
1424
  // regenResponseToGet = index of regenerated response to get (defaults to latest if '' unpassed)
1416
1425
 
1417
- if (window.location.href.startsWith('https://chat.openai.com/c/'))
1426
+ if (window.location.href.startsWith('https://chatgpt.com/c/'))
1418
1427
  return this.getFromDOM.apply(null, arguments);
1419
1428
  else return this.getFromAPI.apply(null, arguments);
1420
1429
  },
@@ -1459,47 +1468,32 @@ const chatgpt = { // eslint-disable-line no-redeclare
1459
1468
  );
1460
1469
  response = responseDivs[nthOfResponse - 1].textContent;
1461
1470
  }
1462
- response = response.replace(/^ChatGPTChatGPT/, ''); // strip sender name
1471
+ response = response.replace(/^ChatGPT(?:ChatGPT)?/, ''); // strip sender name
1463
1472
  }
1464
1473
  return response;
1465
1474
  },
1466
1475
 
1467
1476
  getLast: function() { return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest'); },
1468
-
1469
- regenerate: function() {
1470
- const regenBtn = chatgpt.getRegenerateButton();
1471
- if (regenBtn) regenBtn.click();
1472
- else console.error('Regenerate button not found!');
1473
- },
1474
-
1475
- stopGenerating: function() {
1476
- for (const svg of document.querySelectorAll('form button svg')) {
1477
- if (svg.querySelector('path[d*="2 0 0 1 2"]')) {
1478
- svg.parentNode.click(); return;
1479
- }}}
1477
+ regenerate: function() { try { chatgpt.getRegenerateBtn().click(); } catch (err) { console.error(err.message); }},
1478
+ stopGenerating: function() { try { chatgpt.getStopBtn().click(); } catch (err) { console.error(err.message); }}
1480
1479
  },
1481
1480
 
1482
1481
  reviewCode: function() { chatgpt.code.review(); },
1483
-
1484
- scrollToBottom: function() {
1485
- const scrollBtn = chatgpt.getScrollToBottomButton();
1486
- if (scrollBtn) scrollBtn.click();
1487
- else console.error('Scroll button not found!');
1488
- },
1482
+ scrollToBottom: function() { try { chatgpt.getScrollBtn().click(); } catch (err) { console.error(err.message); }},
1489
1483
 
1490
1484
  send: function(msg, method='') {
1491
1485
  for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] !== 'string')
1492
1486
  return console.error(`Argument ${ i + 1 } must be a string!`);
1493
1487
  const textArea = document.querySelector('form textarea'),
1494
- sendButton = document.querySelector('form button[class*="bottom"]');
1488
+ sendBtn = this.getSendButton();
1495
1489
  textArea.value = msg;
1496
1490
  textArea.dispatchEvent(new Event('input', { bubbles: true })); // enable send button
1497
- const delaySend = setInterval(() => {
1498
- if (!sendButton?.hasAttribute('disabled')) { // send msg
1499
- method.toLowerCase() == 'click' || chatgpt.browser.isMobile() ? sendButton.click()
1491
+
1492
+ setTimeout(function delaySend() {
1493
+ if (!sendBtn?.hasAttribute('disabled')) { // send msg
1494
+ method.toLowerCase() == 'click' || chatgpt.browser.isMobile() ? sendBtn.click()
1500
1495
  : textArea.dispatchEvent(new KeyboardEvent('keydown', { keyCode: 13, bubbles: true }));
1501
- clearInterval(delaySend);
1502
- }
1496
+ } else setTimeout(delaySend, 25);
1503
1497
  }, 25);
1504
1498
  },
1505
1499
 
@@ -1639,10 +1633,6 @@ const chatgpt = { // eslint-disable-line no-redeclare
1639
1633
  elements: [], observer: {},
1640
1634
 
1641
1635
  activateObserver: function() {
1642
- const chatHistoryNav = document.querySelector('nav'),
1643
- firstButton = chatHistoryNav.querySelector('a');
1644
- if (chatgpt.history.isOff()) // Hide enable history spam div
1645
- try { firstButton.parentNode.nextElementSibling.style.display = 'none'; } catch (err) {}
1646
1636
 
1647
1637
  // Stop the previous observer to preserve resources
1648
1638
  if (this.observer instanceof MutationObserver)
@@ -1753,28 +1743,34 @@ const chatgpt = { // eslint-disable-line no-redeclare
1753
1743
  show: function() { this.isOff() ? this.toggle() : console.info('Sidebar already shown!'); },
1754
1744
  isOff: function() { return !this.isOn(); },
1755
1745
  isOn: function() {
1746
+ const sidebar = document.querySelector('#__next > div > div');
1756
1747
  return chatgpt.browser.isMobile() ?
1757
1748
  document.documentElement.style.overflow == 'hidden'
1758
- : document.querySelector('#__next > div > div').style.visibility != 'hidden';
1749
+ : sidebar.style.visibility != 'hidden' && sidebar.style.width != '0px';
1759
1750
  },
1760
1751
 
1761
1752
  toggle: function() {
1762
1753
  const isMobileDevice = chatgpt.browser.isMobile(),
1763
- navBtnSelector = isMobileDevice ? '#__next button' : 'main button' ,
1754
+ isGPT4oUI = !!document.documentElement.className.includes(' '),
1755
+ navBtnSelector = isMobileDevice ? '#__next button' : isGPT4oUI ? 'nav button' : 'main button',
1764
1756
  isToggleBtn = isMobileDevice ? () => true // since 1st one is toggle
1765
- : btn => Array.from(btn.querySelectorAll('*'))
1766
- .some(child => child.style.transform.includes('translateY'));
1757
+ : isGPT4oUI ? btn => btn.querySelectorAll('svg path[d*="M8.857 3h6.286c1.084"]').length > 0
1758
+ : /* post-GPT-4o desktop */ btn => [...btn.querySelectorAll('*')]
1759
+ .some(child => child.style.transform.includes('translateY'));
1767
1760
  for (const btn of document.querySelectorAll(navBtnSelector))
1768
1761
  if (isToggleBtn(btn)) { btn.click(); return; }
1769
- }
1770
- },
1762
+ },
1771
1763
 
1772
- startNewChat: function() {
1773
- for (const navLink of document.querySelectorAll('nav a')) {
1774
- if (/(new|clear) chat/i.test(navLink.text)) {
1775
- navLink.click(); return;
1776
- }}},
1764
+ isloaded: function() {
1765
+ return new Promise(resolve => {
1766
+ (function checkIsLoaded() {
1767
+ if (document.querySelector('nav a[href="/"]')) resolve(true);
1768
+ else setTimeout(checkIsLoaded, 100);
1769
+ })();
1770
+ });}
1771
+ },
1777
1772
 
1773
+ startNewChat: function() { try { this.getNewChatBtn().click(); } catch (err) { console.error(err.message); }},
1778
1774
  stop: function() { this.response.stopGenerating(); },
1779
1775
 
1780
1776
  suggest: async function(ideaType, details) {
@@ -1879,6 +1875,7 @@ const funcAliases = [
1879
1875
  ['actAs', 'actas', 'act', 'become', 'persona', 'premadePrompt', 'preMadePrompt', 'prePrompt', 'preprompt', 'roleplay', 'rolePlay', 'rp'],
1880
1876
  ['activateAutoRefresh', 'activateAutoRefresher', 'activateRefresher', 'activateSessionRefresher',
1881
1877
  'autoRefresh', 'autoRefresher', 'autoRefreshSession', 'refresher', 'sessionRefresher'],
1878
+ ['continue', 'continueChat', 'continueGenerating', 'continueResponse'],
1882
1879
  ['deactivateAutoRefresh', 'deactivateAutoRefresher', 'deactivateRefresher', 'deactivateSessionRefresher'],
1883
1880
  ['detectLanguage', 'getLanguage'],
1884
1881
  ['executeCode', 'codeExecute'],
@@ -1886,7 +1883,9 @@ const funcAliases = [
1886
1883
  ['getFooterDiv', 'getFooter'],
1887
1884
  ['getHeaderDiv', 'getHeader'],
1888
1885
  ['getLastPrompt', 'getLastQuery', 'getMyLastMsg', 'getMyLastQuery'],
1886
+ ['getContinueGeneratingButton', 'getContinueButton'],
1889
1887
  ['getScrollToBottomButton', 'getScrollButton'],
1888
+ ['getStopGeneratingButton', 'getStopButton'],
1890
1889
  ['getTextarea', 'getTextArea', 'getChatbox', 'getChatBox'],
1891
1890
  ['isFullScreen', 'isFullscreen'],
1892
1891
  ['logOut', 'logout', 'logOff', 'logoff', 'signOut', 'signout', 'signOff', 'signoff'],
@@ -1902,7 +1901,8 @@ const funcAliases = [
1902
1901
  ['send', 'sendChat', 'sendMsg'],
1903
1902
  ['sendInNewChat', 'sendNewChat'],
1904
1903
  ['sentiment', 'analyzeSentiment', 'sentimentAnalysis'],
1905
- ['stop', 'stopGenerating'],
1904
+ ['startNewChat', 'new', 'newChat'],
1905
+ ['stop', 'stopChat', 'stopGenerating', 'stopResponse'],
1906
1906
  ['suggest', 'suggestion', 'recommend'],
1907
1907
  ['toggleAutoRefresh', 'toggleAutoRefresher', 'toggleRefresher', 'toggleSessionRefresher'],
1908
1908
  ['toggleScheme', 'toggleMode'],
@@ -1916,7 +1916,10 @@ const synonyms = [
1916
1916
  ['analyze', 'check', 'evaluate', 'review'],
1917
1917
  ['ask', 'send', 'submit'],
1918
1918
  ['button', 'btn'],
1919
+ ['continue', 'resume'],
1920
+ ['chats', 'history'],
1919
1921
  ['chat', 'conversation', 'convo'],
1922
+ ['clear', 'delete', 'remove'],
1920
1923
  ['data', 'details'],
1921
1924
  ['deactivate', 'deActivate', 'turnOff'],
1922
1925
  ['execute', 'interpret', 'interpreter', 'run'],