@kudoai/chatgpt.js 3.8.1 → 3.8.2

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/LICENSE.md CHANGED
@@ -1,3 +1,29 @@
1
+ <div align="center">
2
+ <h6>
3
+ <a href="docs/">
4
+ <picture>
5
+ <source type="image/svg+xml" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptjs.org/images/icons/earth/white/icon32.svg?v=e638eac">
6
+ <img height=14 src="https://assets.chatgptjs.org/images/icons/earth/black/icon32.svg?v=e638eac">
7
+ </picture>
8
+ </a>
9
+ English |
10
+ <a href="docs/zh-cn/LICENSE.md">简体中文</a> |
11
+ <a href="docs/zh-tw/LICENSE.md">繁體中文</a> |
12
+ <a href="docs/ja/LICENSE.md">日本</a> |
13
+ <a href="docs/ko/LICENSE.md">한국인</a> |
14
+ <a href="docs/hi/LICENSE.md">हिंदी</a> |
15
+ <a href="docs/ne/LICENSE.md">नेपाली</a> |
16
+ <a href="docs/de/LICENSE.md">Deutsch</a> |
17
+ <a href="docs/es/LICENSE.md">Español</a> |
18
+ <a href="docs/fr/LICENSE.md">Français</a> |
19
+ <a href="docs/it/LICENSE.md">Italiano</a> |
20
+ <a href="docs/nl/LICENSE.md">Nederlands</a> |
21
+ <a href="docs/pt/LICENSE.md">Português</a> |
22
+ <a href="docs/ru/LICENSE.md">Английский</a> |
23
+ <a href="docs/vi/LICENSE.md">Việt</a>
24
+ </h6>
25
+ </div>
26
+
1
27
  # MIT License
2
28
 
3
29
  **Copyright © 2023–2025 [KudoAI](https://github.com/KudoAI) & [contributors](.#-contributors).**
package/README.md CHANGED
@@ -51,18 +51,20 @@
51
51
  <img src="https://img.shields.io/badge/License-MIT-fc4f2d.svg?logo=internetarchive&logoColor=white&labelColor=464646&style=for-the-badge"></a>
52
52
  <a href="https://www.npmjs.com/package/@kudoai/chatgpt.js/v/latest" target="_blank" rel="noopener">
53
53
  <img src="https://img.shields.io/npm/v/%40kudoai%2Fchatgpt.js?logo=npm&logoColor=white&labelColor=464646&color=blue&style=for-the-badge&label=Latest+Release"></a>
54
- <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.8.1/dist/chatgpt.min.js" target="_blank" rel="noopener">
55
- <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.8.1&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
54
+ <a href="https://github.com/KudoAI/chatgpt.js/tree/v3.8.2/dist/chatgpt.min.js" target="_blank" rel="noopener">
55
+ <img src="https://img.shields.io/github/size/KudoAI/chatgpt.js/dist/chatgpt.min.js?branch=v3.8.2&label=Minified%20Size&logo=databricks&logoColor=white&labelColor=464646&color=ff69b4&style=for-the-badge"></a>
56
56
  <a href="https://www.codefactor.io/repository/github/kudoai/chatgpt.js" target="_blank" rel="noopener">
57
57
  <img src="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"></a>
58
58
  <a href="https://sonarcloud.io/component_measures?metric=new_vulnerabilities&id=kudoai_chatgpt.js" target="_blank" rel="noopener">
59
59
  <img src="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"></a>
60
60
  <a href="https://github.com/sindresorhus/awesome-chatgpt#javascript" target="_blank" rel="noopener">
61
61
  <img src="https://img.shields.io/badge/Mentioned_in-Awesome-cca8c4?logo=awesomelists&logoColor=white&labelColor=464646&style=for-the-badge"></a>
62
+ <a href="https://opentools.ai/tools/chatgptjs">
63
+ <img alt="[Voted Top Tool on OpenTools.ai]" src="https://img.shields.io/badge/Voted_Top_Tool-OpenTools.ai-f43f5e?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzNTAiIGhlaWdodD0iMzUwIiBzdHlsZT0ic2hhcGUtcmVuZGVyaW5nOmdlb21ldHJpY1ByZWNpc2lvbjt0ZXh0LXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb247aW1hZ2UtcmVuZGVyaW5nOm9wdGltaXplUXVhbGl0eTtmaWxsLXJ1bGU6ZXZlbm9kZDtjbGlwLXJ1bGU6ZXZlbm9kZCI+PHBhdGggZmlsbD0iI2ZlZmZmZSIgZD0iTTM2LjUgMzAuNWM5My44MzItMSAxODcuODMyLTEuMzMzIDI4Mi0xIC4xNjcgOTQuMDAxIDAgMTg4LjAwMS0uNSAyODJsLTc4LTc4Yy0uNS00MS42NjUtLjY2Ny04My4zMzItLjUtMTI1LTQxLjY2OC4xNjctODMuMzM1IDAtMTI1LS41YTg1MzcuOTUgODUzNy45NSAwIDAgMC03OC03Ny41WiIgc3R5bGU9Im9wYWNpdHk6Ljk4NCIvPjxwYXRoIGZpbGw9IiNmZWZmZmUiIGQ9Ik0yOS41IDM1LjVhMjkyNC4wMjQgMjkyNC4wMjQgMCAwIDEgNzguNSA3OWMuNSA0MS42NjUuNjY3IDgzLjMzMi41IDEyNSA0Mi4wMDEtLjE2NyA4NC4wMDEgMCAxMjYgLjVhODQzMy4xNiA4NDMzLjE2IDAgMCAxIDc3IDc3LjVjLTkzLjk5OCAxLTE4Ny45OTggMS4zMzMtMjgyIDF2LTI4M1oiIHN0eWxlPSJvcGFjaXR5Oi45ODEiLz48L3N2Zz4=&logoColor=white&labelColor=464646&style=for-the-badge"></a>
62
64
  <a href="https://www.producthunt.com/posts/chatgpt-js" target="_blank" rel="noopener">
63
65
  <img src="https://img.shields.io/badge/Featured_on-Product_Hunt-ff6154?logo=producthunt&logoColor=white&labelColor=464646&style=for-the-badge"></a>
64
66
  <a href="https://trendshift.io/repositories/2896" target="_blank" rel="noopener">
65
- <img src="https://img.shields.io/badge/GitHub-Trended_Top_20-869da0?logo=github&logoColor=white&labelColor=464646&style=for-the-badge"></a>
67
+ <img src="https://img.shields.io/badge/Trended-Top_20_Repository-869da0?logo=github&logoColor=white&labelColor=464646&style=for-the-badge"></a>
66
68
  <a href="#">
67
69
  <img src="https://img.shields.io/badge/jsDelivr_Requests-2,000,000+-2bbbd8.svg?logo=jsdelivr&logoColor=white&labelColor=464646&style=for-the-badge"></a>
68
70
 
@@ -118,7 +120,7 @@
118
120
 
119
121
  ```js
120
122
  (async () => {
121
- await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.1/dist/chatgpt.min.js');
123
+ await import('https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
122
124
  // Your code here...
123
125
  })();
124
126
  ```
@@ -127,7 +129,7 @@
127
129
 
128
130
  ```js
129
131
  var xhr = new XMLHttpRequest();
130
- xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.1/dist/chatgpt.min.js');
132
+ xhr.open('GET', 'https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js');
131
133
  xhr.onload = function () {
132
134
  if (xhr.status === 200) {
133
135
  var chatgptJS = document.createElement('script');
@@ -150,7 +152,7 @@ function yourCode() {
150
152
 
151
153
  ```js
152
154
  ...
153
- // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.1/dist/chatgpt.min.js
155
+ // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.8.2/dist/chatgpt.min.js
154
156
  // ==/UserScript==
155
157
 
156
158
  // Your code here...
@@ -220,7 +222,7 @@ chatgpt.get('reply', 'last');
220
222
 
221
223
  Each call equally fetches the last response. If you think it works, it probably will... so just type it!
222
224
 
223
- If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.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!
225
+ If it didn't, check out the extended [userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.2/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!
224
226
 
225
227
  <img height=8px width="100%" src="https://assets.chatgptjs.org/images/separators/gradient-aqua.png?v=e638eac">
226
228
 
@@ -241,7 +243,7 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
241
243
  [Readme](https://amazongpt.kudoai.com/#readme) /
242
244
  [Discuss](https://github.com/KudoAI/amazongpt/discussions)
243
245
 
244
- ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.autoclearchatgpt.com/images/icons/openai/white/icon48.png?cece513"><img width=21 src="https://assets.autoclearchatgpt.com/images/icons/openai/black/icon48.png?cece513"></picture> [Autoclear ChatGPT History](https://autoclearchatgpt.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#chatgpt" target="_blank" rel="noopener"><img src="https://assets.autoclearchatgpt.com/images/badges/awesome/badge.svg?2c0d9fc" style="margin:0 0 -2px 5px"></a>
246
+ ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.autoclearchatgpt.com/images/icons/openai/white/icon48.png?cece513"><img width=21 src="https://assets.autoclearchatgpt.com/images/icons/openai/black/icon48.png?cece513"></picture> [Autoclear ChatGPT History](https://autoclearchatgpt.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#-chatgpt" target="_blank" rel="noopener"><img src="https://assets.autoclearchatgpt.com/images/badges/awesome/badge.svg?2c0d9fc" style="margin:0 0 -2px 5px"></a>
245
247
 
246
248
  > Auto-clear your ChatGPT query history for maximum privacy.
247
249
  <br>[Install](https://docs.autoclearchatgpt.com/#-installation) /
@@ -255,7 +257,7 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
255
257
  [Readme](https://docs.bravegpt.com/#readme) /
256
258
  [Discuss](https://github.com/KudoAI/bravegpt/discussions)
257
259
 
258
- ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptautocontinue.com/images/icons/continue-symbol/white/icon48.png?v=61c4f16"><img width=21 src="https://assets.chatgptautocontinue.com/images/icons/continue-symbol/black/icon48.png?v=61c4f16"></picture> [ChatGPT Auto-Continue ⏩](https://chatgptautocontinue.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#chatgpt" target="_blank" rel="noopener"><img src="https://assets.chatgptautocontinue.com/images/badges/awesome/badge.svg?3c80c0c" style="margin:0 0 -3px 3px"></a>
260
+ ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptautocontinue.com/images/icons/continue-symbol/white/icon48.png?v=61c4f16"><img width=21 src="https://assets.chatgptautocontinue.com/images/icons/continue-symbol/black/icon48.png?v=61c4f16"></picture> [ChatGPT Auto-Continue ⏩](https://chatgptautocontinue.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#-chatgpt" target="_blank" rel="noopener"><img src="https://assets.chatgptautocontinue.com/images/badges/awesome/badge.svg?3c80c0c" style="margin:0 0 -3px 3px"></a>
259
261
 
260
262
  > Automatically continue generating answers when ChatGPT responses get cut-off.
261
263
  <br>[Install](https://docs.chatgptautocontinue.com/#-installation) /
@@ -269,7 +271,7 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
269
271
  [Readme](https://github.com/adamlui/chatgpt-auto-talk#readme) /
270
272
  [Discuss](https://github.com/adamlui/chatgpt-auto-talk/discussions)
271
273
 
272
- ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptautorefresh.com/images/icons/openai/white/icon48.png?a45cf1e"><img width=21 src="https://assets.chatgptautorefresh.com/images/icons/openai/black/icon48.png?a45cf1e"></picture> [ChatGPT Auto Refresh ↻](https://chatgptautorefresh.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#chatgpt" target="_blank" rel="noopener"><img src="https://assets.chatgptautorefresh.com/images/badges/awesome/badge.svg?1080f44" style="margin:0 0 -2px 5px"></a>
274
+ ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.chatgptautorefresh.com/images/icons/openai/white/icon48.png?a45cf1e"><img width=21 src="https://assets.chatgptautorefresh.com/images/icons/openai/black/icon48.png?a45cf1e"></picture> [ChatGPT Auto Refresh ↻](https://chatgptautorefresh.com) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#-chatgpt" target="_blank" rel="noopener"><img src="https://assets.chatgptautorefresh.com/images/badges/awesome/badge.svg?1080f44" style="margin:0 0 -2px 5px"></a>
273
275
 
274
276
  > Keeps ChatGPT sessions fresh to eliminate network errors + Cloudflare checks.
275
277
  <br>[Install](https://docs.chatgptautorefresh.com/#-installation) /
@@ -283,7 +285,7 @@ https://github.com/KudoAI/chatgpt.js/assets/10906554/f53c740f-d5e0-49b6-ae02-3b3
283
285
  [Readme](https://docs.ddgpt.com/#readme) /
284
286
  [Discuss](https://github.com/KudoAI/duckduckgpt/discussions)
285
287
 
286
- ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.googlegpt.io/images/icons/app/white/icon48.png"><img width=21 src="https://assets.googlegpt.io/images/icons/app/black/icon48.png"></picture> [GoogleGPT](https://googlegpt.io) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#chatgpt" target="_blank" rel="noopener"><img src="https://assets.googlegpt.io/images/badges/awesome/badge.svg?699c63d" style="margin:0 0 -2px 5px"></a>
288
+ ### <picture><source type="image/png" media="(prefers-color-scheme: dark)" srcset="https://assets.googlegpt.io/images/icons/app/white/icon48.png"><img width=21 src="https://assets.googlegpt.io/images/icons/app/black/icon48.png"></picture> [GoogleGPT](https://googlegpt.io) &nbsp;<a href="https://github.com/awesome-scripts/awesome-userscripts#-chatgpt" target="_blank" rel="noopener"><img src="https://assets.googlegpt.io/images/badges/awesome/badge.svg?699c63d" style="margin:0 0 -2px 5px"></a>
287
289
 
288
290
  > Add AI chat & search summaries to Google Search, powered by the latest LLMs!
289
291
  <br>[Install](https://greasyfork.googlegpt.io) /
@@ -413,6 +415,8 @@ This library exists thanks to code, translations, issues & ideas from the follow
413
415
  <img title="@AliasUruz" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/130197125?first-contrib=2024.12.1-new-chat-selector-outdated-report&h=47&w=47&mask=circle&maxage=7d"></a>
414
416
  <a href="https://github.com/ericdachen" target="_blank" rel="noopener">
415
417
  <img title="@ericdachen" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/54382303?first-contrib=2025.3.20-implement-warp-to-golden-sponsors&h=47&w=47&mask=circle&maxage=7d"></a>
418
+ <a href="https://github.com/m-k8s" target="_blank" rel="noopener">
419
+ <img title="@m-k8s" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/u/42094254?first-contrib=2025.7.26-fixed-hand,ling-of-intermediate-msgs-by-getchatdata&h=47&w=47&mask=circle&maxage=7d"></a>
416
420
  <a href="https://github.com/dependabot" target="_blank" rel="noopener">
417
421
  <img title="Dependabot" src="https://images.weserv.nl/?url=https://avatars.githubusercontent.com/in/29110&h=47&w=47&mask=circle&maxage=7d"></a>
418
422
  <a href="https://chatgpt.com" target="_blank" rel="noopener">
@@ -476,7 +480,7 @@ This library exists thanks to code, translations, issues & ideas from the follow
476
480
  <div align="center">
477
481
 
478
482
  **[Releases](https://github.com/KudoAI/chatgpt.js/releases)** /
479
- [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.1/docs/USERGUIDE.md) /
483
+ [Userguide](https://github.com/KudoAI/chatgpt.js/blob/v3.8.2/docs/USERGUIDE.md) /
480
484
  [Discuss](https://github.com/KudoAI/chatgpt.js/discussions) /
481
485
  [Back to top ↑](#top)
482
486
 
package/chatgpt.js CHANGED
@@ -25,8 +25,8 @@ const chatgpt = {
25
25
  selectors: {
26
26
  btns: {
27
27
  continue: 'button:has(svg[class*=rotate] > path[d^="M4.47189"])',
28
- createImage: 'button[data-testid="composer-create-image"]',
29
- deepResearch: 'button[data-testid="composer-deep-research"]',
28
+ createImage: 'button[data-testid=composer-create-image]',
29
+ deepResearch: 'button[data-testid=composer-deep-research]',
30
30
  login: 'button[data-testid*=login]',
31
31
  newChat: 'a[href="/"]:has(svg),' // Pencil button (when logged in)
32
32
  + 'button:has([d^="M3.06957"])', // Cycle Arrows button (in temp chat logged out)
@@ -34,10 +34,10 @@ const chatgpt = {
34
34
  // 'Try Again' entry of model selector below msg
35
35
  + 'div[role=menuitem] div:has(svg):has(path[d^="M3.06957"])',
36
36
  scroll: 'button:has(> svg > path[d^="M12 21C11.7348"])',
37
- search: 'button[data-testid="composer-button-search"]',
38
- reason: 'button[data-testid="composer-button-reason"]',
37
+ search: 'button[data-testid=composer-button-search]',
38
+ reason: 'button[data-testid=composer-button-reason]',
39
39
  send: 'button[data-testid=send-button]',
40
- sidebar: 'button[data-testid*=sidebar-button]',
40
+ sidebar: 'div[style*=-sidebar-width] button[data-testid=close-sidebar-button], div[style*=-sidebar-rail-width] button[aria-controls=stage-slideover-sidebar]',
41
41
  stop: 'button[data-testid=stop-button]',
42
42
  upload: 'button:has(> svg > path[d^="M12 3C12.5523"])',
43
43
  voice: 'button[data-testid*=composer-speech-button]'
@@ -49,9 +49,9 @@ const chatgpt = {
49
49
  chatHistory: 'div#history',
50
50
  errors: { toast: 'div.toast-root', txt: 'div[class*=text-error]' },
51
51
  footer: 'div#thread-bottom-container > div:last-of-type > div, span.text-sm.leading-none',
52
- header: 'div#page-header, main div.sticky:first-of-type',
52
+ header: 'header#page-header',
53
53
  links: { newChat: 'nav a[href="/"]', sidebarItem: 'nav a' },
54
- sidebar: 'div.bg-token-sidebar-surface-primary',
54
+ sidebar: 'div#stage-slideover-sidebar, div.bg-token-sidebar-surface-primary',
55
55
  ssgManifest: 'script[src*="_ssgManifest.js"]'
56
56
  },
57
57
 
@@ -69,14 +69,14 @@ const chatgpt = {
69
69
  console.log('\n%c🤖 chatgpt.js personas\n',
70
70
  'font-family: sans-serif ; font-size: xxx-large ; font-weight: bold')
71
71
  for (const prompt of data) // list personas
72
- console.log(`%c${ prompt.title }`, 'font-family: monospace ; font-size: larger ;')
72
+ console.log(`%c${prompt.title}`, 'font-family: monospace ; font-size: larger ;')
73
73
  return resolve()
74
74
  }
75
75
  const selectedPrompt = data.find(obj => obj.title.toLowerCase() == persona.toLowerCase())
76
76
  if (!selectedPrompt)
77
- return reject(`🤖 chatgpt.js >> Persona '${ persona }' was not found!`)
77
+ return reject(`🤖 chatgpt.js >> Persona '${persona}' was not found!`)
78
78
  chatgpt.send(selectedPrompt.prompt, 'click')
79
- console.info(`Loading ${ persona } persona...`)
79
+ console.info(`Loading ${persona} persona...`)
80
80
  chatgpt.isIdle().then(() => console.info('Persona activated!'))
81
81
  return resolve()
82
82
  }
@@ -183,11 +183,11 @@ const chatgpt = {
183
183
  }
184
184
  modalStyle.textContent = ( // update prev/new style contents
185
185
  `.chatgpt-modal { /* vars */
186
- --transition: opacity 0.65s cubic-bezier(.165,.84,.44,1), /* for fade-in */
187
- transform 0.55s cubic-bezier(.165,.84,.44,1) ; /* for move-in */
188
- --bg-transition: background-color 0.25s ease ; /* for bg dim */
189
- --btn-transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ; /* for smooth zoom */
190
- --btn-shadow: 2px 1px ${ scheme == 'dark' ? '54px #00cfff' : '30px #9cdaff' }}`
186
+ --transition: opacity 0.65s cubic-bezier(.165,.84,.44,1), /* for fade-in */
187
+ transform 0.55s cubic-bezier(.165,.84,.44,1) ; /* for move-in */
188
+ --bg-transition: background-color 0.25s ease ; /* for bg dim */
189
+ --btn-transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ; /* for smooth zoom */
190
+ --btn-shadow: 2px 1px ${ scheme == 'dark' ? '54px #00cfff' : '30px #9cdaff' }}`
191
191
 
192
192
  + '.no-mobile-tap-outline { outline: none ; -webkit-tap-highlight-color: transparent }'
193
193
 
@@ -197,8 +197,8 @@ const chatgpt = {
197
197
  position: fixed ; top: 0 ; left: 0 ; width: 100% ; height: 100% ; /* expand to full view-port */
198
198
  display: flex ; justify-content: center ; align-items: center ; z-index: 9999 ; /* align */
199
199
  transition: var(--bg-transition) ; /* for bg dim */
200
- -webkit-transition: var(--bg-transition) ; -moz-transition: var(--bg-transition) ;
201
- -o-transition: var(--bg-transition) ; -ms-transition: var(--bg-transition) }`
200
+ -webkit-transition: var(--bg-transition) ; -moz-transition: var(--bg-transition) ;
201
+ -o-transition: var(--bg-transition) ; -ms-transition: var(--bg-transition) }`
202
202
 
203
203
  // Alert styles
204
204
  + `.chatgpt-modal > div {
@@ -212,13 +212,13 @@ const chatgpt = {
212
212
  border: 1px solid ${ scheme == 'dark' ? 'white' : '#b5b5b5' };
213
213
  transform: translateX(-3px) translateY(7px) ; /* offset to move-in from */
214
214
  max-width: 75vw ; word-wrap: break-word ; border-radius: 15px ;
215
- --shadow: 0 30px 60px rgba(0,0,0,0.12) ; box-shadow: var(--shadow) ;
216
- -webkit-box-shadow: var(--shadow) ; -moz-box-shadow: var(--shadow) ;
215
+ --shadow: 0 30px 60px rgba(0,0,0,0.12) ; box-shadow: var(--shadow) ;
216
+ -webkit-box-shadow: var(--shadow) ; -moz-box-shadow: var(--shadow) ;
217
217
  user-select: none ; -webkit-user-select: none ; -moz-user-select: none ;
218
- -o-user-select: none ; -ms-user-select: none ;
218
+ -o-user-select: none ; -ms-user-select: none ;
219
219
  transition: var(--transition) ; /* for fade-in + move-in */
220
- -webkit-transition: var(--transition) ; -moz-transition: var(--transition) ;
221
- -o-transition: var(--transition) ; -ms-transition: var(--transition) }
220
+ -webkit-transition: var(--transition) ; -moz-transition: var(--transition) ;
221
+ -o-transition: var(--transition) ; -ms-transition: var(--transition) }
222
222
  .chatgpt-modal h2 { font-weight: bold ; font-size: 24px ; margin-bottom: 9px }
223
223
  .chatgpt-modal a { color: ${ scheme == 'dark' ? '#00cfff' : '#1e9ebb' }}
224
224
  .chatgpt-modal a:hover { text-decoration: underline }
@@ -238,8 +238,8 @@ const chatgpt = {
238
238
  ${ isMobile ? 'margin-top: 5px ; margin-bottom: 3px ;' : '' }
239
239
  border-radius: 0 ; border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' };
240
240
  transition: var(--btn-transition) ;
241
- -webkit-transition: var(--btn-transition) ; -moz-transition: var(--btn-transition) ;
242
- -o-transition: var(--btn-transition) ; -ms-transition: var(--btn-transition) }
241
+ -webkit-transition: var(--btn-transition) ; -moz-transition: var(--btn-transition) ;
242
+ -o-transition: var(--btn-transition) ; -ms-transition: var(--btn-transition) }
243
243
  .chatgpt-modal button:hover {
244
244
  transform: scale(1.055) ; color: black ;
245
245
  background-color: #${ scheme == 'dark' ? '00cfff' : '9cdaff' };
@@ -422,7 +422,7 @@ const chatgpt = {
422
422
  this.toggle.refreshFrame()
423
423
  document.removeEventListener('visibilitychange', this.toggle.beacons)
424
424
  clearTimeout(this.isActive) ; this.isActive = null
425
- console.log(`↻ ChatGPT >> [${ chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh de-activated`)
425
+ console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh de-activated`)
426
426
  } else
427
427
  console.log(`↻ ChatGPT >> [${chatgpt.autoRefresh.nowTimeStamp()}] Auto refresh already inactive!`)
428
428
  },
@@ -648,7 +648,7 @@ const chatgpt = {
648
648
  year = now.getFullYear(),
649
649
  hour = now.getHours().toString().padStart(2, '0'),
650
650
  minute = now.getMinutes().toString().padStart(2, '0')
651
- filename = `ChatGPT_${ day }-${ month }-${ year }_${ hour }-${ minute }.txt`
651
+ filename = `ChatGPT_${day}-${month}-${year}_${hour}-${minute}.txt`
652
652
 
653
653
  // Create transcript from active chat
654
654
  if (chatToGet == 'active' && /\/\w{8}-\w{4}-\w{4}-\w{4}-\w{12}$/.test(window.location.href)) {
@@ -692,13 +692,13 @@ const chatgpt = {
692
692
  }
693
693
 
694
694
  // Export transcript
695
- console.info(`Exporting transcript as ${ format.toUpperCase() }...`)
695
+ console.info(`Exporting transcript as ${format.toUpperCase()}...`)
696
696
  if (format == 'pdf') { // convert SVGs + launch PDF printer
697
697
 
698
698
  // Convert SVG icons to data URLs for proper PDF rendering
699
699
  transcript = transcript.replace(/<svg.*?<\/svg>/g, (match) => {
700
700
  const dataURL = 'data:image/svg+xml,' + encodeURIComponent(match)
701
- return `<img src="${ dataURL }">`
701
+ return `<img src="${dataURL}">`
702
702
  })
703
703
 
704
704
  // Launch PDF printer
@@ -886,7 +886,7 @@ const chatgpt = {
886
886
  (chatToGet == 'active' && !new RegExp(`\/${re_chatID.source}$`).test(location.href))) {
887
887
  chatToGet = Number.isInteger(chatToGet) ? chatToGet : 0 // preserve index, otherwise get latest
888
888
  if (chatToGet > data.length) // reject if index out-of-bounds
889
- return reject(`🤖 chatgpt.js >> Chat with index ${ chatToGet + 1 }`
889
+ return reject(`🤖 chatgpt.js >> Chat with index ${ chatToGet +1 }`
890
890
  + ` is out of bounds. Only ${data.length} chats exist!`)
891
891
  for (const detail of detailsToGet) detailsToReturn[detail] = data[chatToGet][detail]
892
892
  return resolve(detailsToReturn)
@@ -931,7 +931,7 @@ const chatgpt = {
931
931
  userMessages.sort((a, b) => a.msg.create_time - b.msg.create_time) // sort in chronological order
932
932
 
933
933
  if (parseInt(msgToGet, 10) + 1 > userMessages.length) // reject if index out of bounds
934
- return reject(`🤖 chatgpt.js >> Message/response with index ${ msgToGet + 1 }`
934
+ return reject(`🤖 chatgpt.js >> Message/response with index ${ msgToGet +1 }`
935
935
  + ` is out of bounds. Only ${userMessages.length} messages/responses exist!`)
936
936
 
937
937
  // Fill [chatGPTMessages]
@@ -939,8 +939,9 @@ const chatgpt = {
939
939
  let sub = []
940
940
  for (const key in data) {
941
941
  if (data[key].message != null && data[key].message.author.role == 'assistant'
942
- && data[key].parent == userMessage.id)
942
+ && isUserMsgAncestor(key, userMessage.id)) {
943
943
  sub.push(data[key].message)
944
+ }
944
945
  }
945
946
  sub.sort((a, b) => a.create_time - b.create_time) // sort in chronological order
946
947
  sub = sub.map(x => { // pull out msgs after sorting
@@ -973,6 +974,17 @@ const chatgpt = {
973
974
  return resolve(msgToGet == 'all' ? msgsToReturn // if 'all' passed, return array
974
975
  : msgToGet == 'latest' ? msgsToReturn[msgsToReturn.length - 1] // else if 'latest' passed, return latest
975
976
  : msgsToReturn[msgToGet] ) // else return element of array
977
+
978
+ function isUserMsgAncestor(msgID, targetUserID) {
979
+ let currentID = msgID ; const maxDepth = 10 ; let depth = 0
980
+ while (currentID && depth < maxDepth) {
981
+ const currentMsg = data[currentID]
982
+ if (!currentMsg?.message) return false
983
+ if (currentMsg.id == targetUserID) return true
984
+ currentID = currentMsg.parent ; depth++
985
+ }
986
+ return false
987
+ }
976
988
  }
977
989
  xhr.send()
978
990
  })})}
@@ -1105,7 +1117,7 @@ const chatgpt = {
1105
1117
  const validMethods = ['POST', 'GET']
1106
1118
  method = (method || '').trim().toUpperCase()
1107
1119
  if (!method || !validMethods.includes(method)) // reject if not valid method
1108
- return console.error(`Valid methods are ${ validMethods }`)
1120
+ return console.error(`Valid methods are ${validMethods}`)
1109
1121
  if (!token) return console.error('Please provide a valid access token!')
1110
1122
  if (body && typeof body != 'object') // reject if body is passed but not an object
1111
1123
  return console.error(`Invalid body data type. Got ${ typeof body }, expected object`)
@@ -1126,7 +1138,7 @@ const chatgpt = {
1126
1138
  return reject('🤖 chatgpt.js >> ' + responseData.detail.description)
1127
1139
  else if (xhr.status != 200)
1128
1140
  return reject('🤖 chatgpt.js >> Request failed. Cannot contact custom instructions endpoint.')
1129
- console.info(`Custom instructions successfully contacted with method ${ method }`)
1141
+ console.info(`Custom instructions successfully contacted with method ${method}`)
1130
1142
  return resolve(responseData || {}) // return response data no matter what the method is
1131
1143
  }
1132
1144
  xhr.send(JSON.stringify(body) || '') // if body is passed send it, else just send the request
@@ -1291,7 +1303,12 @@ const chatgpt = {
1291
1303
 
1292
1304
  minify() { chatgpt.code.minify(); },
1293
1305
 
1294
- notify(msg, position, notifDuration, shadow) {
1306
+ notify(...args) {
1307
+ const scheme = chatgpt.isDarkMode() ? 'dark' : 'light'
1308
+ let msg, position, notifDuration, shadow, toast
1309
+ if (typeof args[0] == 'object' && !Array.isArray(args[0]))
1310
+ ({ msg, position, notifDuration, shadow, toast } = args[0])
1311
+ else [msg, position, notifDuration, shadow] = args
1295
1312
  notifDuration = notifDuration ? +notifDuration : 1.75; // sec duration to maintain notification visibility
1296
1313
  const fadeDuration = 0.35, // sec duration of fade-out
1297
1314
  vpYoffset = 23, vpXoffset = 27 // px offset from viewport border
@@ -1325,7 +1342,7 @@ const chatgpt = {
1325
1342
  + (notificationDiv.isRight ? 'Right' : 'Left')
1326
1343
 
1327
1344
  // Create/append/update notification style (if missing or outdated)
1328
- const thisUpdated = 1735767823541 // timestamp of last edit for this file's `notifStyle`
1345
+ const thisUpdated = 1746996635555 // timestamp of last edit for this file's `notifStyle`
1329
1346
  let notifStyle = document.querySelector('#chatgpt-notif-style') // try to select existing style
1330
1347
  if (!notifStyle || parseInt(notifStyle.getAttribute('last-updated'), 10) < thisUpdated) { // if missing or outdated
1331
1348
  if (!notifStyle) { // outright missing, create/id/attr/append it first
@@ -1356,6 +1373,13 @@ const chatgpt = {
1356
1373
  + '45% { opacity: 0.05 ; transform: rotateX(-81deg) }'
1357
1374
  + '100% { opacity: 0 ; transform: rotateX(-180deg) scale(1.15) }}'
1358
1375
  )
1376
+ if (toast) notifStyle.textContent += `
1377
+ div.chatgpt-notif {
1378
+ position: absolute ; left: 50% ; right: 21% !important ; text-align: center ;
1379
+ ${ scheme == 'dark' ? 'border: 2px solid white ;' : '' }
1380
+ margin-${ !notificationDiv.isTop ? 'bottom: 105px' : 'top: 42px' };
1381
+ transform: translate(-50%, -50%) scale(0.6) !important }
1382
+ div.chatgpt-notif > div.notif-close-btn { top: 18px ; right: 7px ; transform: scale(2) }`
1359
1383
  }
1360
1384
 
1361
1385
  // Enqueue notification
@@ -1377,7 +1401,7 @@ const chatgpt = {
1377
1401
  const oldDiv = document.getElementById(divId),
1378
1402
  offsetProp = oldDiv.style.top ? 'top' : 'bottom', // pick property to change
1379
1403
  vOffset = +parseInt(oldDiv.style[offsetProp]) +5 + oldDiv.getBoundingClientRect().height
1380
- oldDiv.style[offsetProp] = `${ vOffset }px` // change prop
1404
+ oldDiv.style[offsetProp] = `${vOffset}px` // change prop
1381
1405
  }
1382
1406
  } catch (err) { console.warn('Failed to re-position notification:', err) }
1383
1407
  }
@@ -1395,7 +1419,7 @@ const chatgpt = {
1395
1419
 
1396
1420
  // Add notification dismissal to timeout schedule + button clicks
1397
1421
  const dismissNotif = () => {
1398
- notificationDiv.style.animation = `notif-zoom-fade-out ${ fadeDuration }s ease-out`;
1422
+ notificationDiv.style.animation = `notif-zoom-fade-out ${fadeDuration}s ease-out`;
1399
1423
  clearTimeout(dismissFuncTID)
1400
1424
  }
1401
1425
  const dismissFuncTID = setTimeout(dismissNotif, hideDelay * 1000) // maintain visibility for `hideDelay` secs, then dismiss
@@ -1426,7 +1450,7 @@ const chatgpt = {
1426
1450
  }
1427
1451
  Object.keys(colors).forEach(elem => { // populate dark scheme colors if missing
1428
1452
  colors[elem][1] = colors[elem][1] ||
1429
- '#' + (Number(`0x1${ colors[elem][0].replace(/^#/, '') }`) ^ 0xFFFFFF)
1453
+ '#' + (Number(`0x1${colors[elem][0].replace(/^#/, '')}`) ^ 0xFFFFFF)
1430
1454
  .toString(16).substring(1).toUpperCase() // convert to hex
1431
1455
  })
1432
1456
 
@@ -1456,7 +1480,7 @@ const chatgpt = {
1456
1480
  : (( Object.keys(this).find(obj => Object.keys(this[obj]).includes(this[functionName[1]].name)) + '.' )
1457
1481
  + this[functionName[1]].name )),
1458
1482
  isAsync = this[functionName[1]]?.constructor.name == 'AsyncFunction'
1459
- console.log('%c>> %c' + ( isChatGptObjParent ? '' : `${ functionName[0] }.%c`) + functionName[1]
1483
+ console.log('%c>> %c' + ( isChatGptObjParent ? '' : `${functionName[0]}.%c`) + functionName[1]
1460
1484
  + ' - https://chatgptjs.org/userguide/' + /(?:.*\.)?(.*)/.exec(rootFunction)[1].toLowerCase() + ( isAsync ? '-async' : '' ) + '\n%c[%c'
1461
1485
  + ((( functionName[0] == 'chatgpt' && functionName[1] == this[functionName[1]].name ) || // parent is chatgpt + names match or
1462
1486
  !isChatGptObjParent) // parent is chatgpt.obj
@@ -1641,14 +1665,14 @@ const chatgpt = {
1641
1665
  const validValues = ['dark', 'light', 'system']
1642
1666
  if (!value) return console.error('Please specify a scheme value!')
1643
1667
  if (!validValues.includes(value))
1644
- return console.error(`Invalid scheme value. Valid values are [${ validValues }]`)
1668
+ return console.error(`Invalid scheme value. Valid values are [${validValues}]`)
1645
1669
 
1646
1670
  // Determine scheme to set
1647
1671
  let schemeToSet = value
1648
1672
  if (value == 'system')
1649
1673
  schemeToSet = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
1650
1674
  localStorage.setItem('theme', value)
1651
- console.info(`Scheme set to ${ value.toUpperCase() }.`)
1675
+ console.info(`Scheme set to ${value.toUpperCase()}.`)
1652
1676
 
1653
1677
  // Toggle scheme if necessary
1654
1678
  if (!document.documentElement.classList.contains(schemeToSet)) this.toggle()
@@ -1666,7 +1690,7 @@ const chatgpt = {
1666
1690
  for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] != 'string')
1667
1691
  return console.error(`Argument ${ i + 1 } must be a string.`)
1668
1692
  chatgpt.send('What is the sentiment of the following text'
1669
- + ( entity ? ` towards the entity ${ entity },` : '')
1693
+ + ( entity ? ` towards the entity ${entity},` : '')
1670
1694
  + ' from strongly negative to strongly positive?\n\n' + text )
1671
1695
  console.info('Analyzing sentiment...')
1672
1696
  await chatgpt.isIdle()
@@ -1687,7 +1711,7 @@ const chatgpt = {
1687
1711
  return new Promise((resolve, reject) => {
1688
1712
  const xhr = new XMLHttpRequest()
1689
1713
  chatgpt.getChatData(chatToGet).then(chat => {
1690
- xhr.open('GET', `${ chatgpt.endpoints.openAI.chat }/${ chat.id }`, true)
1714
+ xhr.open('GET', `${chatgpt.endpoints.openAI.chat}/${chat.id}`, true)
1691
1715
  xhr.setRequestHeader('Content-Type', 'application/json')
1692
1716
  xhr.setRequestHeader('Authorization', 'Bearer ' + token)
1693
1717
  xhr.onload = () => {
@@ -1720,13 +1744,13 @@ const chatgpt = {
1720
1744
  const confirmShareChat = (token, data) => {
1721
1745
  return new Promise((resolve, reject) => {
1722
1746
  const xhr = new XMLHttpRequest()
1723
- xhr.open('PATCH', `${ chatgpt.endpoints.openAI.share }/${ data.share_id }`, true)
1747
+ xhr.open('PATCH', `${chatgpt.endpoints.openAI.share}/${data.share_id}`, true)
1724
1748
  xhr.setRequestHeader('Content-Type', 'application/json')
1725
1749
  xhr.setRequestHeader('Authorization', 'Bearer ' + token)
1726
1750
  xhr.onload = () => {
1727
1751
  if (xhr.status != 200)
1728
1752
  return reject('🤖 chatgpt.js >> Request failed. Cannot share chat.')
1729
- console.info(`Chat shared at '${ data.share_url }'`)
1753
+ console.info(`Chat shared at '${data.share_url}'`)
1730
1754
  return resolve() // the response has nothing useful
1731
1755
  }
1732
1756
  xhr.send(JSON.stringify({ // request body
@@ -1900,7 +1924,7 @@ const chatgpt = {
1900
1924
  for (let i = 0; i < arguments.length; i++) if (typeof arguments[i] != 'string')
1901
1925
  return console.error(`Argument ${ i + 1 } must be a string.`)
1902
1926
  chatgpt.send('Suggest some names. ' + ( details || '' ))
1903
- console.info(`Creating ${ ideaType }...`)
1927
+ console.info(`Creating ${ideaType}...`)
1904
1928
  await chatgpt.isIdle()
1905
1929
  return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest')
1906
1930
  },