@kudoai/chatgpt.js 3.8.1 → 3.8.3
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 +26 -0
- package/README.md +16 -12
- package/chatgpt.js +71 -47
- package/dist/chatgpt.min.js +25 -19
- package/docs/README.md +17 -12
- package/docs/USERGUIDE.md +14 -12
- package/package.json +11 -11
- package/starters/chrome/extension/components/icons.js +28 -21
- package/starters/chrome/extension/components/modals.js +5 -2
- package/starters/chrome/extension/content.js +3 -3
- package/starters/chrome/extension/icons/faded/icon128.png +0 -0
- package/starters/chrome/extension/icons/faded/icon16.png +0 -0
- package/starters/chrome/extension/icons/faded/icon32.png +0 -0
- package/starters/chrome/extension/icons/faded/icon64.png +0 -0
- package/starters/chrome/extension/icons/icon128.png +0 -0
- package/starters/chrome/extension/icons/icon16.png +0 -0
- package/starters/chrome/extension/icons/icon32.png +0 -0
- package/starters/chrome/extension/icons/icon64.png +0 -0
- package/starters/chrome/extension/lib/chatgpt.js +71 -47
- package/starters/chrome/extension/lib/settings.js +11 -4
- package/starters/chrome/extension/manifest.json +1 -1
- package/starters/chrome/extension/popup/controller.js +196 -65
- package/starters/chrome/extension/popup/index.html +3 -3
- package/starters/chrome/extension/popup/style.css +88 -25
- package/starters/chrome/extension/service-worker.js +1 -2
- package/starters/greasemonkey/chatgpt.js-greasemonkey-starter.user.js +4 -4
|
@@ -1,33 +1,40 @@
|
|
|
1
|
-
// Requires lib/dom.js
|
|
1
|
+
// Requires lib/dom.js
|
|
2
2
|
|
|
3
3
|
window.icons = {
|
|
4
4
|
|
|
5
|
-
create(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
create({ key, size = 18, width, height, ...otherAttrs }) {
|
|
6
|
+
if (!key) return console.error('Option \'key\' required by icons.create()')
|
|
7
|
+
const icon = {
|
|
8
|
+
data: this[key], attrs: { width: width || size, height: height || size, class: key, ...otherAttrs }}
|
|
9
|
+
if (icon.data?.svg) { // return <svg>
|
|
10
|
+
icon.svg = dom.create.svgElem('svg', { ...icon.data.svg, ...icon.attrs })
|
|
11
|
+
;(function create(elems) {
|
|
12
|
+
return elems.map(elem => {
|
|
13
|
+
const [tag, attrs] = Object.entries(elem)[0], svgElem = dom.create.svgElem(tag, attrs)
|
|
14
|
+
if (attrs.elems) svgElem.append(...create(attrs.elems)) // recursively create() sub-elems
|
|
15
|
+
return svgElem
|
|
16
|
+
})
|
|
17
|
+
})(icon.data.elems).forEach(elem => icon.svg.append(elem))
|
|
18
|
+
return icon.svg
|
|
19
|
+
} else if (icon.data?.src) // return <img> w/ src
|
|
20
|
+
return dom.create.elem('img', { src: icon.data.src, ...icon.attrs })
|
|
21
|
+
else
|
|
22
|
+
return console.error(`No <svg|src> data found for key ${key}`)
|
|
14
23
|
},
|
|
15
24
|
|
|
16
|
-
caretDown: {
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
caretDown: { svg: { viewBox: '0 0 24 24' }, elems: [{ path: { d: 'm0 6.4 12 12 12-12z' }}]},
|
|
26
|
+
|
|
27
|
+
open: {
|
|
28
|
+
svg: { viewBox: '0 0 512 512' },
|
|
29
|
+
elems: [{ path: { transform: 'translate(85.333333, 64)',
|
|
30
|
+
d: 'M128,63.999444 L128,106.666444 L42.6666667,106.666667 L42.6666667,320 L256,320 L256,234.666444 L298.666,234.666444 L298.666667,362.666667 L4.26325641e-14,362.666667 L4.26325641e-14,64 L128,63.999444 Z M362.666667,1.42108547e-14 L362.666667,170.666667 L320,170.666667 L320,72.835 L143.084945,249.751611 L112.915055,219.581722 L289.83,42.666 L192,42.6666667 L192,1.42108547e-14 L362.666667,1.42108547e-14 Z' }}]
|
|
19
31
|
},
|
|
20
32
|
|
|
21
33
|
plus: {
|
|
22
|
-
|
|
23
|
-
elems: [
|
|
24
|
-
[ 'path', { d: 'M899.901 600.38H600.728v299.173c0 74.383-179.503 74.383-179.503 0V600.38H122.051c-74.384 0-74.384-179.503 0-179.503h299.173V121.703c0-74.384 179.503-74.384 179.503 0v299.174H899.9c74.385 0 74.385 179.503.001 179.503z' }]
|
|
25
|
-
]
|
|
34
|
+
svg: { viewBox: '0 0 1024 1024' },
|
|
35
|
+
elems: [{ path: { d: 'M899.901 600.38H600.728v299.173c0 74.383-179.503 74.383-179.503 0V600.38H122.051c-74.384 0-74.384-179.503 0-179.503h299.173V121.703c0-74.384 179.503-74.384 179.503 0v299.174H899.9c74.385 0 74.385 179.503.001 179.503z' }}]
|
|
26
36
|
},
|
|
27
37
|
|
|
28
38
|
questionMark: {
|
|
29
|
-
|
|
30
|
-
get src() { return `${app.urls.assetHost.replace(
|
|
31
|
-
'@latest', '@00e245b')}/images/icons/question-mark/icon16.png` }
|
|
32
|
-
}
|
|
39
|
+
src: 'https://cdn.jsdelivr.net/gh/KudoAI/chatgpt.js-chrome-starter@8a59f80/images/icons/question-mark/icon16.png' }
|
|
33
40
|
};
|
|
@@ -21,10 +21,13 @@ window.modals = {
|
|
|
21
21
|
+ `<span style="${labelStyles}">📜 Open source code:</span> `
|
|
22
22
|
+ `<a href="${app.urls.gitHub}" target="_blank" rel="nopener">`
|
|
23
23
|
+ app.urls.gitHub + '</a>\n'
|
|
24
|
+
+ `<span style="${labelStyles}">🚀 Latest changes:</span> `
|
|
25
|
+
+ `<a href="${app.urls.gitHub}/commits" target="_blank" rel="nopener">`
|
|
26
|
+
+ `${app.urls.gitHub}/commits</a>\n`
|
|
24
27
|
+ `<span style="${labelStyles}">⚡ Powered by:</span> `
|
|
25
|
-
+ `<a href="${app.urls.
|
|
28
|
+
+ `<a href="${app.urls.chatgptjs}" target="_blank" rel="noopener">chatgpt.js</a>`,
|
|
26
29
|
[ function getSupport(){}, function rateUs(){}, function moreAiExtensions(){} ], // button labels
|
|
27
|
-
'',
|
|
30
|
+
'', 747 // modal width
|
|
28
31
|
)
|
|
29
32
|
|
|
30
33
|
// Format text
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
alert: () => modals.alert(...['title', 'msg', 'btns', 'checkbox', 'width'].map(arg => options[arg])),
|
|
21
21
|
showAbout: () => { config.skipAlert = true ; chatgpt.isLoaded().then(() => modals.open('about')) },
|
|
22
22
|
syncConfigToUI: () => syncConfigToUI(options)
|
|
23
|
-
}[action]?.() || console.warn(`
|
|
23
|
+
}[action]?.() || console.warn(`Chome msg listener warning: "${action}"`))
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
// Init SETTINGS
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
if (foundState) msg = msg.replace(foundState, '')
|
|
37
37
|
|
|
38
38
|
// Show notification
|
|
39
|
-
chatgpt.notify(`${app.symbol} ${msg}`, pos, notifDuration, shadow || env.ui.scheme == '
|
|
39
|
+
chatgpt.notify(`${app.symbol} ${msg}`, pos, notifDuration, shadow || env.ui.scheme == 'light')
|
|
40
40
|
const notif = document.querySelector('.chatgpt-notif:last-child')
|
|
41
41
|
|
|
42
42
|
// Append styled state word
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
// Add RISING PARTICLES styles for modals
|
|
82
82
|
;['gray', 'white'].forEach(color => document.head.append(
|
|
83
83
|
dom.create.elem('link', { rel: 'stylesheet',
|
|
84
|
-
href: `https://cdn.jsdelivr.net/gh/adamlui/ai-web-extensions@
|
|
84
|
+
href: `https://cdn.jsdelivr.net/gh/adamlui/ai-web-extensions@71695ca/assets/styles/rising-particles/dist/${
|
|
85
85
|
color}.min.css`
|
|
86
86
|
})))
|
|
87
87
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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=
|
|
29
|
-
deepResearch: 'button[data-testid=
|
|
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=
|
|
38
|
-
reason: 'button[data-testid=
|
|
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
|
|
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: '
|
|
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${
|
|
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 '${
|
|
77
|
+
return reject(`🤖 chatgpt.js >> Persona '${persona}' was not found!`)
|
|
78
78
|
chatgpt.send(selectedPrompt.prompt, 'click')
|
|
79
|
-
console.info(`Loading ${
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
201
|
-
|
|
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
|
-
|
|
216
|
-
|
|
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
|
-
|
|
218
|
+
-o-user-select: none ; -ms-user-select: none ;
|
|
219
219
|
transition: var(--transition) ; /* for fade-in + move-in */
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
242
|
-
|
|
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 >> [${
|
|
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_${
|
|
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 ${
|
|
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="${
|
|
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 +
|
|
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 +
|
|
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
|
-
&&
|
|
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 ${
|
|
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 ${
|
|
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(
|
|
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 =
|
|
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] = `${
|
|
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 ${
|
|
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${
|
|
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 ? '' : `${
|
|
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 [${
|
|
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 ${
|
|
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 ${
|
|
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', `${
|
|
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', `${
|
|
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 '${
|
|
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
|
|
@@ -1869,7 +1893,7 @@ const chatgpt = {
|
|
|
1869
1893
|
if (!sidebar) { return console.error('Sidebar element not found!') || false }
|
|
1870
1894
|
else return chatgpt.browser.isMobile() ?
|
|
1871
1895
|
document.documentElement.style.overflow == 'hidden'
|
|
1872
|
-
: sidebar.style.visibility != 'hidden' && sidebar.
|
|
1896
|
+
: sidebar.style.visibility != 'hidden' && parseInt(getComputedStyle(sidebar).width) > 150
|
|
1873
1897
|
},
|
|
1874
1898
|
|
|
1875
1899
|
toggle() {
|
|
@@ -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 ${
|
|
1927
|
+
console.info(`Creating ${ideaType}...`)
|
|
1904
1928
|
await chatgpt.isIdle()
|
|
1905
1929
|
return chatgpt.getChatData('active', 'msg', 'chatgpt', 'latest')
|
|
1906
1930
|
},
|
|
@@ -3,12 +3,14 @@ window.settings = {
|
|
|
3
3
|
|
|
4
4
|
controls: {
|
|
5
5
|
// Add settings options as keys, with each key's value being an object that includes:
|
|
6
|
-
// - 'type': the control type (e.g. 'toggle', 'link' or 'prompt')
|
|
6
|
+
// - 'type': the control type (e.g. 'toggle', 'slider', 'link' or 'prompt')
|
|
7
7
|
// - 'label': a descriptive label
|
|
8
8
|
// - 'defaultVal' (optional): default value of setting (true for toggles if unspecified, false otherwise)
|
|
9
9
|
// - 'category' (optional): string key from this.categories to group control under
|
|
10
10
|
// - 'symbol' (optional): for icon display (e.g. ⌚)
|
|
11
11
|
// - 'helptip' (optional): tooltip to display on hover
|
|
12
|
+
// - 'throttle' (optional): true/false or ms to disable toggles on click (defaults to 1500 if true)
|
|
13
|
+
// - 'dependencies' (optional): array of key names of categories/controls that must also be enabled
|
|
12
14
|
|
|
13
15
|
// NOTE: Controls are displayed in top-to-bottom order (within categories and in top-level)
|
|
14
16
|
// NOTE: Toggles are disabled by default unless defaultVal is true
|
|
@@ -26,6 +28,9 @@ window.settings = {
|
|
|
26
28
|
// - 'color' (optional): hex code (w/o #) of color for left-border
|
|
27
29
|
// - 'helptip' (optional): tooltip to display on hover
|
|
28
30
|
// - 'autoExpand' (optional): true/false to auto-expand categories on toolbar icon click
|
|
31
|
+
// - 'throttle' (optional): true/false or ms to disable toggles on click (defaults to 1500 if true)
|
|
32
|
+
// - 'throttle' (optional): true/false or ms to disable toggles on click (defaults to 1500 if true)
|
|
33
|
+
// - 'dependencies' (optional): array of key names of categories/controls that must also be enabled
|
|
29
34
|
|
|
30
35
|
// NOTE: Categories are displayed in top-to-bottom order
|
|
31
36
|
|
|
@@ -43,9 +48,11 @@ window.settings = {
|
|
|
43
48
|
|
|
44
49
|
load(...keys) {
|
|
45
50
|
return Promise.all(keys.flat().map(async key => // resolve promise when all keys load
|
|
46
|
-
config[key] = (await chrome.storage.local.get(key))[key]
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
config[key] = (await chrome.storage.local.get(key))[key] ?? initDefaultVal(key)))
|
|
52
|
+
function initDefaultVal(key) {
|
|
53
|
+
const ctrlData = settings.controls?.[key]
|
|
54
|
+
return ctrlData?.defaultVal ?? ( ctrlData?.type == 'slider' ? 100 : ctrlData?.type == 'toggle' )
|
|
55
|
+
}
|
|
49
56
|
},
|
|
50
57
|
|
|
51
58
|
save(key, val) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "ChatGPT Extension",
|
|
4
4
|
"short_name": "ChatGPT 🧩",
|
|
5
5
|
"description": "A Chromium extension template to start using chatgpt.js like a boss!",
|
|
6
|
-
"version": "2025.
|
|
6
|
+
"version": "2025.8.14",
|
|
7
7
|
"author": "KudoAI",
|
|
8
8
|
"homepage_url": "https://github.com/KudoAI/chatgpt.js-chrome-starter",
|
|
9
9
|
"icons": { "16": "icons/icon16.png", "32": "icons/icon32.png", "64": "icons/icon64.png", "128": "icons/icon128.png" },
|