|
3 | 3 | // @description Adds the magic of AI to Amazon shopping |
4 | 4 | // @author KudoAI |
5 | 5 | // @namespace https://kudoai.com |
6 | | -// @version 2025.1.18.5 |
| 6 | +// @version 2025.1.18.6 |
7 | 7 | // @license MIT |
8 | 8 | // @icon https://amazongpt.kudoai.com/assets/images/icons/amazongpt/black-gold-teal/icon48.png?v=0fddfc7 |
9 | 9 | // @icon64 https://amazongpt.kudoai.com/assets/images/icons/amazongpt/black-gold-teal/icon64.png?v=0fddfc7 |
|
2595 | 2595 | } |
2596 | 2596 |
|
2597 | 2597 | // Get/show answer from AI |
2598 | | - const reqMethod = apis[get.reply.api].method |
| 2598 | + const reqAPI = get.reply.api, reqMethod = apis[reqAPI].method |
2599 | 2599 | const xhrConfig = { |
2600 | | - headers: api.createHeaders(get.reply.api), method: reqMethod, |
| 2600 | + headers: api.createHeaders(reqAPI), method: reqMethod, |
2601 | 2601 | responseType: config.streamingDisabled || !config.proxyAPIenabled ? 'text' : 'stream', |
2602 | 2602 | onerror: err => { log.error(err) |
2603 | 2603 | if (!config.proxyAPIenabled) |
2604 | 2604 | appAlert(!config.openAIkey ? 'login' : ['openAInotWorking', 'suggestProxy']) |
2605 | 2605 | else api.tryNew(get.reply) |
2606 | 2606 | }, |
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)}` : '' ) |
2611 | 2611 | } |
2612 | | - if (reqMethod == 'POST') xhrConfig.data = await api.createPayload(get.reply.api, msgChain) |
| 2612 | + if (reqMethod == 'POST') xhrConfig.data = await api.createPayload(reqAPI, msgChain) |
2613 | 2613 | xhr(xhrConfig) |
2614 | 2614 | } |
2615 | 2615 | } |
|
2624 | 2624 | return new RegExp([...failFlags, ...escapedAPIurls].join('|')) |
2625 | 2625 | }, |
2626 | 2626 |
|
2627 | | - stream(caller, stream) { |
| 2627 | + stream(resp, { caller, callerAPI }) { |
2628 | 2628 | if (config.streamingDisabled || !config.proxyAPIenabled) return |
2629 | 2629 | 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)) |
2633 | 2634 |
|
2634 | | - function processStreamText({ done, value }) { |
| 2635 | + function processStreamText(callerAPI, { done, value }) { |
2635 | 2636 |
|
2636 | 2637 | // Handle stream done |
2637 | 2638 | 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() |
2639 | 2640 | if (env.browser.isChromium) { // clear/add timeout since reader.read() doesn't signal done |
2640 | 2641 | clearTimeout(this.timeout) ; this.timeout = setTimeout(handleProcessCompletion, 500) } |
2641 | 2642 |
|
2642 | 2643 | // Process/show chunk |
2643 | | - if (caller.api == 'MixerBox AI') { // pre-process chunks |
| 2644 | + if (callerAPI == 'MixerBox AI') { // pre-process chunks |
2644 | 2645 | const extractedChunks = Array.from(chunk.matchAll(/data:(.*)/g), match => match[1] |
2645 | 2646 | .replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n')) |
2646 | 2647 | .filter(match => !/message_(?:start|end)|done/.test(match)) |
2647 | 2648 | chunk = extractedChunks.join('') |
2648 | 2649 | } |
2649 | | - accumulatedChunks = apis[caller.api].accumulatesText ? chunk : accumulatedChunks + chunk |
| 2650 | + accumulatedChunks = apis[callerAPI].accumulatesText ? chunk : accumulatedChunks + chunk |
2650 | 2651 | try { // to show stream text |
2651 | 2652 | let textToShow = '' |
2652 | | - if (caller.api == 'GPTforLove') { // extract parentID + latest chunk text |
| 2653 | + if (callerAPI == 'GPTforLove') { // extract parentID + latest chunk text |
2653 | 2654 | const jsonLines = accumulatedChunks.split('\n'), |
2654 | 2655 | nowResult = JSON.parse(jsonLines[jsonLines.length -1]) |
2655 | 2656 | if (nowResult.id) apis.GPTforLove.parentID = nowResult.id // for contextual replies |
|
2663 | 2664 | if (caller.status != 'done' && !caller.sender) api.tryNew(caller) |
2664 | 2665 | return |
2665 | 2666 | } 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 |
2668 | 2669 | && textToShow.trim() != '' // empty chunk not read |
2669 | 2670 | ) show.reply(textToShow) |
2670 | 2671 | } |
2671 | 2672 | } catch (err) { log.error('Error showing stream', err.message) } |
2672 | 2673 | 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 }) |
2675 | 2676 | }).catch(err => log.error('Error reading stream', err.message)) |
2676 | 2677 | } |
2677 | 2678 |
|
|
2686 | 2687 | } |
2687 | 2688 | }, |
2688 | 2689 |
|
2689 | | - text(caller, resp) { |
| 2690 | + text(resp, { caller, callerAPI }) { |
2690 | 2691 | return new Promise(() => { |
2691 | 2692 | if (caller == get.reply && config.proxyAPIenabled && !config.streamingDisabled |
2692 | 2693 | || caller.status == 'done') return |
2693 | 2694 | log.caller = `get.${caller.name}() » dataProcess.text()` |
2694 | | - const failFlagsAndURLs = dataProcess.initFailFlags(caller.api) ; let respText = '' |
| 2695 | + const failFlagsAndURLs = this.initFailFlags(callerAPI) ; let respText = '' |
2695 | 2696 | if (resp.status != 200) { |
2696 | 2697 | log.error('Response status', resp.status) |
2697 | 2698 | log.info('Response text', resp.response || resp.responseText) |
2698 | | - if (caller == get.reply && caller.api == 'OpenAI') |
| 2699 | + if (caller == get.reply && callerAPI == 'OpenAI') |
2699 | 2700 | appAlert(resp.status == 401 ? 'login' |
2700 | 2701 | : resp.status == 403 ? 'checkCloudflare' |
2701 | 2702 | : resp.status == 429 ? ['tooManyRequests', 'suggestProxy'] |
2702 | 2703 | : ['openAInotWorking', 'suggestProxy'] ) |
2703 | 2704 | else api.tryNew(caller) |
2704 | | - } else if (caller.api == 'OpenAI' && resp.response) { |
| 2705 | + } else if (callerAPI == 'OpenAI' && resp.response) { |
2705 | 2706 | const failMatch = failFlagsAndURLs.exec(resp.response) |
2706 | 2707 | if (failMatch) { // suggest proxy |
2707 | 2708 | log.dev('Response text', resp.response) |
|
2714 | 2715 | } catch (err) { handleProcessError(err) } |
2715 | 2716 | } |
2716 | 2717 | } else if (resp.responseText) { // show response |
2717 | | - if (/AIchatOS|FREEGPT|ToYaml/.test(caller.api)) { |
| 2718 | + if (/AIchatOS|FREEGPT|ToYaml/.test(callerAPI)) { |
2718 | 2719 | try { |
2719 | 2720 | const text = resp.responseText, chunkSize = 1024 |
2720 | 2721 | let currentIdx = 0 |
|
2724 | 2725 | } |
2725 | 2726 | handleProcessCompletion() |
2726 | 2727 | } catch (err) { handleProcessError(err) } |
2727 | | - } else if (caller.api == 'GPTforLove') { |
| 2728 | + } else if (callerAPI == 'GPTforLove') { |
2728 | 2729 | try { |
2729 | 2730 | let chunks = resp.responseText.trim().split('\n'), |
2730 | 2731 | lastObj = JSON.parse(chunks[chunks.length - 1]) |
2731 | 2732 | if (lastObj.id) apis.GPTforLove.parentID = lastObj.id |
2732 | 2733 | respText = lastObj.text ; handleProcessCompletion() |
2733 | 2734 | } catch (err) { handleProcessError(err) } |
2734 | | - } else if (caller.api == 'MixerBox AI') { |
| 2735 | + } else if (callerAPI == 'MixerBox AI') { |
2735 | 2736 | try { |
2736 | 2737 | const extractedData = Array.from(resp.responseText.matchAll(/data:(.*)/g), match => match[1] |
2737 | 2738 | .replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n')) |
|
2751 | 2752 | api.tryNew(caller) |
2752 | 2753 | } else { |
2753 | 2754 | 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() |
2755 | 2756 | show.reply(respText) ; show.replyCornerBtns() |
2756 | 2757 | }}} |
2757 | 2758 |
|
|
0 commit comments