|
149 | 149 | // @description:zu Yengeza izimpendulo ze-AI ku-Google Search (inikwa amandla yi-Google Gemma + GPT-4o!)
|
150 | 150 | // @author KudoAI
|
151 | 151 | // @namespace https://kudoai.com
|
152 |
| -// @version 2025.1.14.4 |
| 152 | +// @version 2025.1.14.5 |
153 | 153 | // @license MIT
|
154 | 154 | // @icon https://assets.googlegpt.io/images/icons/googlegpt/black/icon48.png?v=59409b2
|
155 | 155 | // @icon64 https://assets.googlegpt.io/images/icons/googlegpt/black/icon64.png?v=59409b2
|
|
370 | 370 | // @connect chatgpt.com
|
371 | 371 | // @connect update.greasyfork.org
|
372 | 372 | // @connect fanyi.sogou.com
|
| 373 | +// @connect toyaml.com |
373 | 374 | // @require https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.5.0/dist/chatgpt.min.js#sha256-+C0x4BOFQc38aZB3pvUC2THu+ZSvuCxRphGdtRLjCDg=
|
374 | 375 | // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js#sha256-dppVXeVTurw1ozOPNE3XqhYmDJPOosfbKQcHyQSE58w=
|
375 | 376 | // @require https://cdn.jsdelivr.net/npm/generate-ip@2.4.4/dist/generate-ip.min.js#sha256-aQQKAQcMgCu8IpJp9HKs387x0uYxngO+Fb4pc5nSF4I=
|
|
793 | 794 | },
|
794 | 795 | expectedOrigin: { url: 'https://chatgpt.com', headers: { 'Priority': 'u=4' }},
|
795 | 796 | method: 'POST', streamable: true
|
| 797 | + }, |
| 798 | + 'ToYaml.com': { |
| 799 | + endpoint: 'https://toyaml.com/streams', |
| 800 | + expectedOrigin: { url: 'https://toyaml.com/chat.html', headers: { 'x-requested-with': 'XMLHttpRequest' }}, |
| 801 | + method: 'GET', streamable: true, watermark: '【本答案来自 toyaml.com】' |
796 | 802 | }
|
797 | 803 | }
|
798 | 804 |
|
|
3373 | 3379 | const ip = ipv4.generate({ verbose: false })
|
3374 | 3380 | const headers = {
|
3375 | 3381 | 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate, br, zstd',
|
3376 |
| - 'Connection': 'keep-alive', 'Content-Type': 'application/json', 'DNT': '1', |
3377 |
| - 'Host': new URL(apis[api].endpoints?.completions || apis[api].endpoint).hostname, |
3378 |
| - 'Origin': apis[api].expectedOrigin.url, 'Sec-Fetch-Site': 'same-origin', |
3379 |
| - 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'X-Forwarded-For': ip, 'X-Real-IP': ip |
| 3382 | + 'Connection': 'keep-alive', 'DNT': '1', |
| 3383 | + 'Origin': apis[api].expectedOrigin.url, 'X-Forwarded-For': ip, 'X-Real-IP': ip |
3380 | 3384 | }
|
3381 | 3385 | headers.Referer = headers.Origin + '/'
|
3382 |
| - if (api == 'OpenAI') headers.Authorization = 'Bearer ' + config.openAIkey |
3383 |
| - Object.assign(headers, apis[api].expectedOrigin.headers) |
| 3386 | + if (apis[api].method == 'POST') Object.assign(headers, { |
| 3387 | + 'Content-Type': 'application/json', |
| 3388 | + 'Host': new URL(apis[api].endpoints?.completions || apis[api].endpoint).hostname, |
| 3389 | + 'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors' |
| 3390 | + }) |
| 3391 | + else if (apis[api].method == 'GET') headers['x-requested-with'] = 'XMLHttpRequest' |
| 3392 | + Object.assign(headers, apis[api].expectedOrigin.headers) // API-specific ones |
| 3393 | + if (api == 'OpenAI') headers.Authorization = `Bearer ${config.openAIkey}` |
3384 | 3394 | return headers
|
3385 | 3395 | },
|
3386 | 3396 |
|
|
3504 | 3514 | }
|
3505 | 3515 |
|
3506 | 3516 | // Get/show answer from AI
|
3507 |
| - xhr({ |
3508 |
| - method: apis[get.reply.api].method, |
3509 |
| - url: apis[get.reply.api].endpoints?.completions || apis[get.reply.api].endpoint, |
| 3517 | + const reqMethod = apis[get.reply.api].method |
| 3518 | + const xhrConfig = { |
| 3519 | + headers: api.createHeaders(get.reply.api), method: reqMethod, |
3510 | 3520 | responseType: config.streamingDisabled || !config.proxyAPIenabled ? 'text' : 'stream',
|
3511 |
| - headers: api.createHeaders(get.reply.api), data: await api.createPayload(get.reply.api, msgChain), |
3512 |
| - onload: resp => dataProcess.text(get.reply, resp), |
3513 |
| - onloadstart: resp => dataProcess.stream(get.reply, resp), |
3514 | 3521 | onerror: err => { log.error(err)
|
3515 | 3522 | if (!config.proxyAPIenabled)
|
3516 | 3523 | appAlert(!config.openAIkey ? 'login' : ['openAInotWorking', 'suggestProxy'])
|
3517 | 3524 | else api.tryNew(get.reply)
|
3518 |
| - } |
3519 |
| - }) |
| 3525 | + }, |
| 3526 | + onload: resp => dataProcess.text(get.reply, resp), |
| 3527 | + onloadstart: resp => dataProcess.stream(get.reply, resp), |
| 3528 | + url: ( apis[get.reply.api].endpoints?.completions || apis[get.reply.api].endpoint ) |
| 3529 | + + ( reqMethod == 'GET' ? `?q=${encodeURIComponent(msgChain[msgChain.length -1].content)}` : '' ) |
| 3530 | + } |
| 3531 | + if (reqMethod == 'POST') xhrConfig.data = await api.createPayload(get.reply.api, msgChain) |
| 3532 | + xhr(xhrConfig) |
3520 | 3533 |
|
3521 | 3534 | // Get/show related queries if enabled on 1st get.reply()
|
3522 | 3535 | if (!config.rqDisabled && get.reply.attemptCnt == 1)
|
|
3575 | 3588 |
|
3576 | 3589 | // Get queries
|
3577 | 3590 | const payload = await api.createPayload(get.related.api, [{ role: 'user', content: rqPrompt }])
|
3578 |
| - return new Promise(resolve => xhr({ |
3579 |
| - method: apis[get.related.api].method, |
3580 |
| - url: apis[get.related.api].endpoints?.completions || apis[get.related.api].endpoint, |
3581 |
| - responseType: 'text', headers: api.createHeaders(get.related.api), |
3582 |
| - data: payload, |
3583 |
| - onload: resp => dataProcess.text(get.related, resp).then(resolve), |
3584 |
| - onerror: err => { log.error(err) ; api.tryNew(get.related) } |
3585 |
| - })) |
| 3591 | + return new Promise(resolve => { |
| 3592 | + const reqMethod = apis[get.related.api].method |
| 3593 | + const xhrConfig = { |
| 3594 | + headers: api.createHeaders(get.related.api), method: reqMethod, responseType: 'text', |
| 3595 | + onerror: err => { log.error(err) ; api.tryNew(get.related) }, |
| 3596 | + onload: resp => dataProcess.text(get.related, resp).then(resolve), |
| 3597 | + url: ( apis[get.related.api].endpoints?.completions || apis[get.related.api].endpoint ) |
| 3598 | + + ( reqMethod == 'GET' ? `?q=${rqPrompt}` : '' ) |
| 3599 | + } |
| 3600 | + if (reqMethod == 'POST') xhrConfig.data = payload |
| 3601 | + xhr(xhrConfig) |
| 3602 | + }) |
3586 | 3603 | }
|
3587 | 3604 | }
|
3588 | 3605 |
|
|
3604 | 3621 | reader.read().then(processStreamText).catch(err => log.error('Error processing stream', err.message))
|
3605 | 3622 |
|
3606 | 3623 | function processStreamText({ done, value }) {
|
3607 |
| - if (done) { caller.sender = null |
3608 |
| - if (appDiv.querySelector('.loading')) // no text shown |
3609 |
| - api.tryNew(caller) |
3610 |
| - else { // text was shown |
3611 |
| - caller.status = 'done' ; caller.attemptCnt = null |
3612 |
| - show.replyCornerBtns() ; api.clearTimedOut(caller.triedAPIs) |
3613 |
| - } return |
3614 |
| - } |
| 3624 | + if (done) { handleProcessCompletion() ; return } |
3615 | 3625 | let chunk = new TextDecoder('utf8').decode(new Uint8Array(value))
|
| 3626 | + if (chunk.includes(apis[caller.api].watermark)) { handleProcessCompletion() ; return } |
3616 | 3627 | if (caller.api == 'MixerBox AI') { // pre-process chunks
|
3617 | 3628 | const extractedChunks = Array.from(chunk.matchAll(/data:(.*)/g), match => match[1]
|
3618 | 3629 | .replace(/\[SPACE\]/g, ' ').replace(/\[NEWLINE\]/g, '\n'))
|
|
3647 | 3658 | processStreamText({ done, value })
|
3648 | 3659 | }).catch(err => log.error('Error reading stream', err.message))
|
3649 | 3660 | }
|
| 3661 | + |
| 3662 | + function handleProcessCompletion() { |
| 3663 | + caller.sender = null |
| 3664 | + if (appDiv.querySelector('.loading')) // no text shown |
| 3665 | + api.tryNew(caller) |
| 3666 | + else { // text was shown |
| 3667 | + caller.status = 'done' ; caller.attemptCnt = null |
| 3668 | + show.replyCornerBtns() ; api.clearTimedOut(caller.triedAPIs) |
| 3669 | + } return |
| 3670 | + } |
3650 | 3671 | },
|
3651 | 3672 |
|
3652 | 3673 | text(caller, resp) {
|
|
3678 | 3699 | } catch (err) { handleProcessError(err) }
|
3679 | 3700 | }
|
3680 | 3701 | } else if (resp.responseText) {
|
3681 |
| - if (/AIchatOS|FREEGPT/.test(caller.api)) { |
| 3702 | + if (/AIchatOS|ToYaml.com|FREEGPT/.test(caller.api)) { |
3682 | 3703 | try { // to show response or return related queries
|
3683 | 3704 | const text = resp.responseText, chunkSize = 1024
|
3684 | 3705 | let currentIdx = 0
|
|
3715 | 3736 | api.tryNew(caller)
|
3716 | 3737 | } else {
|
3717 | 3738 | caller.status = 'done' ; api.clearTimedOut(caller.triedAPIs) ; caller.attemptCnt = null
|
| 3739 | + respText = respText.replace(apis[caller.api].watermark, '').trim() |
3718 | 3740 | if (caller == get.reply) { show.reply(respText, footerContent) ; show.replyCornerBtns() }
|
3719 | 3741 | else resolve(arrayify(respText))
|
3720 |
| - }}} |
| 3742 | + } |
| 3743 | + } |
| 3744 | + } |
3721 | 3745 |
|
3722 | 3746 | function handleProcessError(err) { // suggest proxy or try diff API
|
3723 | 3747 | log.debug('Response text', resp.response)
|
|
0 commit comments