Skip to content

Commit c3a7a5a

Browse files
committed
Changed data process methods to atomically track current API state (#81)
1 parent f785f0b commit c3a7a5a

File tree

4 files changed

+137
-133
lines changed

4 files changed

+137
-133
lines changed

amazongpt/greasemonkey/amazongpt.user.js

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// @description Adds the magic of AI to Amazon shopping
44
// @author KudoAI
55
// @namespace https://kudoai.com
6-
// @version 2025.1.18.5
6+
// @version 2025.1.18.6
77
// @license MIT
88
// @icon https://amazongpt.kudoai.com/assets/images/icons/amazongpt/black-gold-teal/icon48.png?v=0fddfc7
99
// @icon64 https://amazongpt.kudoai.com/assets/images/icons/amazongpt/black-gold-teal/icon64.png?v=0fddfc7
@@ -2595,21 +2595,21 @@
25952595
}
25962596

25972597
// Get/show answer from AI
2598-
const reqMethod = apis[get.reply.api].method
2598+
const reqAPI = get.reply.api, reqMethod = apis[reqAPI].method
25992599
const xhrConfig = {
2600-
headers: api.createHeaders(get.reply.api), method: reqMethod,
2600+
headers: api.createHeaders(reqAPI), method: reqMethod,
26012601
responseType: config.streamingDisabled || !config.proxyAPIenabled ? 'text' : 'stream',
26022602
onerror: err => { log.error(err)
26032603
if (!config.proxyAPIenabled)
26042604
appAlert(!config.openAIkey ? 'login' : ['openAInotWorking', 'suggestProxy'])
26052605
else api.tryNew(get.reply)
26062606
},
2607-
onload: resp => dataProcess.text(get.reply, resp),
2608-
onloadstart: resp => dataProcess.stream(get.reply, resp),
2609-
url: ( apis[get.reply.api].endpoints?.completions || apis[get.reply.api].endpoint )
2610-
+ ( reqMethod == 'GET' ? `?q=${encodeURIComponent(msgChain[msgChain.length -1].content)}` : '' )
2607+
onload: resp => dataProcess.text(resp, { caller: get.reply, callerAPI: reqAPI }),
2608+
onloadstart: resp => dataProcess.stream(resp, { caller: get.reply, callerAPI: reqAPI }),
2609+
url: ( apis[reqAPI].endpoints?.completions || apis[reqAPI].endpoint )
2610+
+ ( reqMethod == 'GET' ? `?q=${encodeURIComponent(msgChain[msgChain.length -1].content)}` : '' )
26112611
}
2612-
if (reqMethod == 'POST') xhrConfig.data = await api.createPayload(get.reply.api, msgChain)
2612+
if (reqMethod == 'POST') xhrConfig.data = await api.createPayload(reqAPI, msgChain)
26132613
xhr(xhrConfig)
26142614
}
26152615
}
@@ -2624,32 +2624,33 @@
26242624
return new RegExp([...failFlags, ...escapedAPIurls].join('|'))
26252625
},
26262626

2627-
stream(caller, stream) {
2627+
stream(resp, { caller, callerAPI }) {
26282628
if (config.streamingDisabled || !config.proxyAPIenabled) return
26292629
log.caller = `get.${caller.name}() » dataProcess.stream()`
2630-
const failFlagsAndURLs = dataProcess.initFailFlags(caller.api),
2631-
reader = stream.response.getReader() ; let accumulatedChunks = ''
2632-
reader.read().then(processStreamText).catch(err => log.error('Error processing stream', err.message))
2630+
const failFlagsAndURLs = this.initFailFlags(callerAPI),
2631+
reader = resp.response.getReader() ; let accumulatedChunks = ''
2632+
reader.read().then(result => processStreamText(callerAPI, result))
2633+
.catch(err => log.error('Error processing stream', err.message))
26332634

2634-
function processStreamText({ done, value }) {
2635+
function processStreamText(callerAPI, { done, value }) {
26352636

26362637
// Handle stream done
26372638
let chunk = new TextDecoder('utf8').decode(new Uint8Array(value))
2638-
if (done || chunk.includes(apis[caller.api].watermark)) return handleProcessCompletion()
2639+
if (done || chunk.includes(apis[callerAPI].watermark)) return handleProcessCompletion()
26392640
if (env.browser.isChromium) { // clear/add timeout since reader.read() doesn't signal done
26402641
clearTimeout(this.timeout) ; this.timeout = setTimeout(handleProcessCompletion, 500) }
26412642

26422643
// Process/show chunk
2643-
if (caller.api == 'MixerBox AI') { // pre-process chunks
2644+
if (callerAPI == 'MixerBox AI') { // pre-process chunks
26442645
const extractedChunks = Array.from(chunk.matchAll(/data:(.*)/g), match => match[1]
26452646
.replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n'))
26462647
.filter(match => !/message_(?:start|end)|done/.test(match))
26472648
chunk = extractedChunks.join('')
26482649
}
2649-
accumulatedChunks = apis[caller.api].accumulatesText ? chunk : accumulatedChunks + chunk
2650+
accumulatedChunks = apis[callerAPI].accumulatesText ? chunk : accumulatedChunks + chunk
26502651
try { // to show stream text
26512652
let textToShow = ''
2652-
if (caller.api == 'GPTforLove') { // extract parentID + latest chunk text
2653+
if (callerAPI == 'GPTforLove') { // extract parentID + latest chunk text
26532654
const jsonLines = accumulatedChunks.split('\n'),
26542655
nowResult = JSON.parse(jsonLines[jsonLines.length -1])
26552656
if (nowResult.id) apis.GPTforLove.parentID = nowResult.id // for contextual replies
@@ -2663,15 +2664,15 @@
26632664
if (caller.status != 'done' && !caller.sender) api.tryNew(caller)
26642665
return
26652666
} else if (caller.status != 'done') { // app waiting or sending
2666-
if (!caller.sender) caller.sender = caller.api // app is waiting, become sender
2667-
if (caller.sender == caller.api // app is sending from this caller.api
2667+
if (!caller.sender) caller.sender = callerAPI // app is waiting, become sender
2668+
if (caller.sender == callerAPI // app is sending from this api
26682669
&& textToShow.trim() != '' // empty chunk not read
26692670
) show.reply(textToShow)
26702671
}
26712672
} catch (err) { log.error('Error showing stream', err.message) }
26722673
return reader.read().then(({ done, value }) => {
2673-
if (caller.sender == caller.api) // am designated sender, recurse
2674-
processStreamText({ done, value })
2674+
if (caller.sender == callerAPI) // am designated sender, recurse
2675+
processStreamText(callerAPI, { done, value })
26752676
}).catch(err => log.error('Error reading stream', err.message))
26762677
}
26772678

@@ -2686,22 +2687,22 @@
26862687
}
26872688
},
26882689

2689-
text(caller, resp) {
2690+
text(resp, { caller, callerAPI }) {
26902691
return new Promise(() => {
26912692
if (caller == get.reply && config.proxyAPIenabled && !config.streamingDisabled
26922693
|| caller.status == 'done') return
26932694
log.caller = `get.${caller.name}() » dataProcess.text()`
2694-
const failFlagsAndURLs = dataProcess.initFailFlags(caller.api) ; let respText = ''
2695+
const failFlagsAndURLs = this.initFailFlags(callerAPI) ; let respText = ''
26952696
if (resp.status != 200) {
26962697
log.error('Response status', resp.status)
26972698
log.info('Response text', resp.response || resp.responseText)
2698-
if (caller == get.reply && caller.api == 'OpenAI')
2699+
if (caller == get.reply && callerAPI == 'OpenAI')
26992700
appAlert(resp.status == 401 ? 'login'
27002701
: resp.status == 403 ? 'checkCloudflare'
27012702
: resp.status == 429 ? ['tooManyRequests', 'suggestProxy']
27022703
: ['openAInotWorking', 'suggestProxy'] )
27032704
else api.tryNew(caller)
2704-
} else if (caller.api == 'OpenAI' && resp.response) {
2705+
} else if (callerAPI == 'OpenAI' && resp.response) {
27052706
const failMatch = failFlagsAndURLs.exec(resp.response)
27062707
if (failMatch) { // suggest proxy
27072708
log.dev('Response text', resp.response)
@@ -2714,7 +2715,7 @@
27142715
} catch (err) { handleProcessError(err) }
27152716
}
27162717
} else if (resp.responseText) { // show response
2717-
if (/AIchatOS|FREEGPT|ToYaml/.test(caller.api)) {
2718+
if (/AIchatOS|FREEGPT|ToYaml/.test(callerAPI)) {
27182719
try {
27192720
const text = resp.responseText, chunkSize = 1024
27202721
let currentIdx = 0
@@ -2724,14 +2725,14 @@
27242725
}
27252726
handleProcessCompletion()
27262727
} catch (err) { handleProcessError(err) }
2727-
} else if (caller.api == 'GPTforLove') {
2728+
} else if (callerAPI == 'GPTforLove') {
27282729
try {
27292730
let chunks = resp.responseText.trim().split('\n'),
27302731
lastObj = JSON.parse(chunks[chunks.length - 1])
27312732
if (lastObj.id) apis.GPTforLove.parentID = lastObj.id
27322733
respText = lastObj.text ; handleProcessCompletion()
27332734
} catch (err) { handleProcessError(err) }
2734-
} else if (caller.api == 'MixerBox AI') {
2735+
} else if (callerAPI == 'MixerBox AI') {
27352736
try {
27362737
const extractedData = Array.from(resp.responseText.matchAll(/data:(.*)/g), match => match[1]
27372738
.replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n'))
@@ -2751,7 +2752,7 @@
27512752
api.tryNew(caller)
27522753
} else {
27532754
caller.status = 'done' ; api.clearTimedOut(caller.triedAPIs) ; caller.attemptCnt = null
2754-
respText = respText.replace(apis[caller.api].watermark, '').trim()
2755+
respText = respText.replace(apis[callerAPI].watermark, '').trim()
27552756
show.reply(respText) ; show.replyCornerBtns()
27562757
}}}
27572758

0 commit comments

Comments
 (0)