Skip to content

Commit

Permalink
Added custom stream completion signal detection for APIs that support it
Browse files Browse the repository at this point in the history
  • Loading branch information
adamlui committed Jan 26, 2025
1 parent 327309f commit 54cc057
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 28 deletions.
18 changes: 11 additions & 7 deletions amazongpt/greasemonkey/amazongpt.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// @description Adds the magic of AI to Amazon shopping
// @author KudoAI
// @namespace https://kudoai.com
// @version 2025.1.25.20
// @version 2025.1.26
// @license MIT
// @icon https://amazongpt.kudoai.com/assets/images/icons/amazongpt/black-gold-teal/icon48.png?v=0fddfc7
// @icon64 https://amazongpt.kudoai.com/assets/images/icons/amazongpt/black-gold-teal/icon64.png?v=0fddfc7
Expand Down Expand Up @@ -2640,7 +2640,8 @@
if (config.streamingDisabled || !config.proxyAPIenabled) return
log.caller = `get.${caller.name}() » dataProcess.stream()`
const failFlagsAndURLs = this.initFailFlags(callerAPI),
reader = resp.response.getReader() ; let textToShow = ''
reader = resp.response.getReader()
let textToShow = '', isDone = false
reader.read().then(chunk => handleChunk(chunk, callerAPI))
.catch(err => log.error('Error processing stream', err.message))

Expand All @@ -2661,13 +2662,15 @@
else { // AI response
apis.GPTforLove.parentID = chunkObjs[0].id || null // for contextual replies
chunkObjs.forEach(obj => replyChunk += obj.delta || '') // accumulate AI reply text
if (respChunk.includes('"finish_reason":"stop"')) isDone = true
}
} else if (callerAPI == 'MixerBox AI') { // extract/normalize AI reply data
replyChunk = [...respChunk.matchAll(/data:(.*)/g)] // arrayify data
.filter(match => !/message_(?:start|end)|done/.test(match)) // exclude signals
.map(match => // normalize whitespace
match[1].replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n'))
.join('') // stringify AI reply text
if (/data:(?:message_end|done)/.test(respChunk)) isDone = true
} else replyChunk = respChunk // no processing required for all other APIs
textToShow += replyChunk

Expand All @@ -2687,11 +2690,12 @@
}
} catch (err) { log.error('Error showing stream', err.message) }

// Read next chunk, process if designated sender
return reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
// handleProcessCompletion() or read next chunk
return isDone ? handleProcessCompletion() // from API's custom signal
: reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
}

function handleProcessCompletion() {
Expand Down
18 changes: 11 additions & 7 deletions bravegpt/greasemonkey/bravegpt.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
// @description:zu Yengeza izimpendulo ze-AI ku-Brave Search (inikwa amandla yi-GPT-4o!)
// @author KudoAI
// @namespace https://kudoai.com
// @version 2025.1.25.21
// @version 2025.1.26
// @license MIT
// @icon https://assets.bravegpt.com/images/icons/bravegpt/icon48.png?v=df624b0
// @icon64 https://assets.bravegpt.com/images/icons/bravegpt/icon64.png?v=df624b0
Expand Down Expand Up @@ -3390,7 +3390,8 @@
if (config.streamingDisabled || !config.proxyAPIenabled) return
log.caller = `get.${caller.name}() » dataProcess.stream()`
const failFlagsAndURLs = this.initFailFlags(callerAPI),
reader = resp.response.getReader() ; let textToShow = ''
reader = resp.response.getReader()
let textToShow = '', isDone = false
reader.read().then(chunk => handleChunk(chunk, callerAPI))
.catch(err => log.error('Error processing stream', err.message))

Expand All @@ -3411,13 +3412,15 @@
else { // AI response
apis.GPTforLove.parentID = chunkObjs[0].id || null // for contextual replies
chunkObjs.forEach(obj => replyChunk += obj.delta || '') // accumulate AI reply text
if (respChunk.includes('"finish_reason":"stop"')) isDone = true
}
} else if (callerAPI == 'MixerBox AI') { // extract/normalize AI reply data
replyChunk = [...respChunk.matchAll(/data:(.*)/g)] // arrayify data
.filter(match => !/message_(?:start|end)|done/.test(match)) // exclude signals
.map(match => // normalize whitespace
match[1].replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n'))
.join('') // stringify AI reply text
if (/data:(?:message_end|done)/.test(respChunk)) isDone = true
} else replyChunk = respChunk // no processing required for all other APIs
textToShow += replyChunk

Expand All @@ -3437,11 +3440,12 @@
}
} catch (err) { log.error('Error showing stream', err.message) }

// Read next chunk, process if designated sender
return reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
// handleProcessCompletion() or read next chunk
return isDone ? handleProcessCompletion() // from API's custom signal
: reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
}

function handleProcessCompletion() {
Expand Down
18 changes: 11 additions & 7 deletions duckduckgpt/greasemonkey/duckduckgpt.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@
// @description:zu Yengeza izimpendulo ze-AI ku-DuckDuckGo (inikwa amandla yi-GPT-4o!)
// @author KudoAI
// @namespace https://kudoai.com
// @version 2025.1.25.23
// @version 2025.1.26
// @license MIT
// @icon https://assets.ddgpt.com/images/icons/duckduckgpt/icon48.png?v=06af076
// @icon64 https://assets.ddgpt.com/images/icons/duckduckgpt/icon64.png?v=06af076
Expand Down Expand Up @@ -3274,7 +3274,8 @@
if (config.streamingDisabled || !config.proxyAPIenabled) return
log.caller = `get.${caller.name}() » dataProcess.stream()`
const failFlagsAndURLs = this.initFailFlags(callerAPI),
reader = resp.response.getReader() ; let textToShow = ''
reader = resp.response.getReader()
let textToShow = '', isDone = false
reader.read().then(chunk => handleChunk(chunk, callerAPI))
.catch(err => log.error('Error processing stream', err.message))

Expand All @@ -3295,13 +3296,15 @@
else { // AI response
apis.GPTforLove.parentID = chunkObjs[0].id || null // for contextual replies
chunkObjs.forEach(obj => replyChunk += obj.delta || '') // accumulate AI reply text
if (respChunk.includes('"finish_reason":"stop"')) isDone = true
}
} else if (callerAPI == 'MixerBox AI') { // extract/normalize AI reply data
replyChunk = [...respChunk.matchAll(/data:(.*)/g)] // arrayify data
.filter(match => !/message_(?:start|end)|done/.test(match)) // exclude signals
.map(match => // normalize whitespace
match[1].replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n'))
.join('') // stringify AI reply text
if (/data:(?:message_end|done)/.test(respChunk)) isDone = true
} else replyChunk = respChunk // no processing required for all other APIs
textToShow += replyChunk

Expand All @@ -3321,11 +3324,12 @@
}
} catch (err) { log.error('Error showing stream', err.message) }

// Read next chunk, process if designated sender
return reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
// handleProcessCompletion() or read next chunk
return isDone ? handleProcessCompletion() // from API's custom signal
: reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
}

function handleProcessCompletion() {
Expand Down
18 changes: 11 additions & 7 deletions googlegpt/greasemonkey/googlegpt.user.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
// @description:zu Yengeza izimpendulo ze-AI ku-Google Search (inikwa amandla yi-Google Gemma + GPT-4o!)
// @author KudoAI
// @namespace https://kudoai.com
// @version 2025.1.25.21
// @version 2025.1.26
// @license MIT
// @icon https://assets.googlegpt.io/images/icons/googlegpt/black/icon48.png?v=59409b2
// @icon64 https://assets.googlegpt.io/images/icons/googlegpt/black/icon64.png?v=59409b2
Expand Down Expand Up @@ -3571,7 +3571,8 @@
if (config.streamingDisabled || !config.proxyAPIenabled) return
log.caller = `get.${caller.name}() » dataProcess.stream()`
const failFlagsAndURLs = this.initFailFlags(callerAPI),
reader = resp.response.getReader() ; let textToShow = ''
reader = resp.response.getReader()
let textToShow = '', isDone = false
reader.read().then(chunk => handleChunk(chunk, callerAPI))
.catch(err => log.error('Error processing stream', err.message))

Expand All @@ -3592,13 +3593,15 @@
else { // AI response
apis.GPTforLove.parentID = chunkObjs[0].id || null // for contextual replies
chunkObjs.forEach(obj => replyChunk += obj.delta || '') // accumulate AI reply text
if (respChunk.includes('"finish_reason":"stop"')) isDone = true
}
} else if (callerAPI == 'MixerBox AI') { // extract/normalize AI reply data
replyChunk = [...respChunk.matchAll(/data:(.*)/g)] // arrayify data
.filter(match => !/message_(?:start|end)|done/.test(match)) // exclude signals
.map(match => // normalize whitespace
match[1].replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n'))
.join('') // stringify AI reply text
if (/data:(?:message_end|done)/.test(respChunk)) isDone = true
} else replyChunk = respChunk // no processing required for all other APIs
textToShow += replyChunk

Expand All @@ -3618,11 +3621,12 @@
}
} catch (err) { log.error('Error showing stream', err.message) }

// Read next chunk, process if designated sender
return reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
// handleProcessCompletion() or read next chunk
return isDone ? handleProcessCompletion() // from API's custom signal
: reader.read().then(({ done, value }) => {
if (caller.sender == callerAPI) handleChunk({ done, value }, callerAPI) // recurse
else if (env.browser.isChromium) clearTimeout(this.timeout) // skip handleProcessCompletion()
}).catch(err => log.error('Error reading stream', err.message))
}

function handleProcessCompletion() {
Expand Down

0 comments on commit 54cc057

Please sign in to comment.