From 64f2699b2210cf7f4b655e66d09cfc0b133361cf Mon Sep 17 00:00:00 2001 From: ikechan8370 Date: Thu, 5 Oct 2023 11:31:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=80=82=E5=BA=94=E5=BF=85=E5=BA=94API?= =?UTF-8?q?=E6=94=B9=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 60 ++++++++++-------- utils/SydneyAIClient.js | 137 ++++++++++++++++++++++------------------ 2 files changed, 108 insertions(+), 89 deletions(-) diff --git a/apps/chat.js b/apps/chat.js index ebeca33..864279f 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -1716,40 +1716,44 @@ export class chatgpt extends plugin { } } } else - if (message && typeof message === 'string' && message.indexOf('限流') > -1) { - throttledTokens.push(bingToken) - let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS')) - const badBingToken = bingTokens.findIndex(element => element.Token === bingToken) - const now = new Date() - const hours = now.getHours() - now.setHours(hours + 6) - bingTokens[badBingToken].State = '受限' - bingTokens[badBingToken].DisactivationTime = now - await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens)) + if (message && typeof message === 'string' && message.indexOf('限流') > -1) { + throttledTokens.push(bingToken) + let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS')) + const badBingToken = bingTokens.findIndex(element => element.Token === bingToken) + const now = new Date() + const hours = now.getHours() + now.setHours(hours + 6) + bingTokens[badBingToken].State = '受限' + bingTokens[badBingToken].DisactivationTime = now + await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens)) // 不减次数 - } else if (message && typeof message === 'string' && message.indexOf('UnauthorizedRequest') > -1) { + } else if (message && typeof message === 'string' && message.indexOf('UnauthorizedRequest') > -1) { // token过期了 - let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS')) - const badBingToken = bingTokens.findIndex(element => element.Token === bingToken) - // 可能是微软抽风,给三次机会 - if (bingTokens[badBingToken].exception) { - if (bingTokens[badBingToken].exception <= 3) { - bingTokens[badBingToken].exception += 1 + let bingTokens = JSON.parse(await redis.get('CHATGPT:BING_TOKENS')) + const badBingToken = bingTokens.findIndex(element => element.Token === bingToken) + if (badBingToken > 0) { + // 可能是微软抽风,给三次机会 + if (bingTokens[badBingToken]?.exception) { + if (bingTokens[badBingToken].exception <= 3) { + bingTokens[badBingToken].exception += 1 + } else { + bingTokens[badBingToken].exception = 0 + bingTokens[badBingToken].State = '过期' + } + } else { + bingTokens[badBingToken].exception = 1 + } + await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens)) } else { - bingTokens[badBingToken].exception = 0 - bingTokens[badBingToken].State = '过期' + retry = retry - 1 } - } else { - bingTokens[badBingToken].exception = 1 - } - await redis.set('CHATGPT:BING_TOKENS', JSON.stringify(bingTokens)) - errorMessage = 'UnauthorizedRequest:必应token不正确或已过期' + errorMessage = 'UnauthorizedRequest:必应token不正确或已过期' // logger.warn(`token${bingToken}疑似不存在或已过期,再试试`) // retry = retry - 1 - } else { - retry-- - errorMessage = message === 'Timed out waiting for response. Try enabling debug mode to see more information.' ? (reply ? `${reply}\n不行了,我的大脑过载了,处理不过来了!` : '必应的小脑瓜不好使了,不知道怎么回答!') : message - } + } else { + retry-- + errorMessage = message === 'Timed out waiting for response. Try enabling debug mode to see more information.' ? (reply ? `${reply}\n不行了,我的大脑过载了,处理不过来了!` : '必应的小脑瓜不好使了,不知道怎么回答!') : message + } } } while (retry > 0) if (errorMessage) { diff --git a/utils/SydneyAIClient.js b/utils/SydneyAIClient.js index b856688..e2e3a07 100644 --- a/utils/SydneyAIClient.js +++ b/utils/SydneyAIClient.js @@ -100,7 +100,7 @@ export default class SydneyAIClient { this.opts.host = 'https://edgeservices.bing.com/edgesvc' } logger.mark('使用host:' + this.opts.host) - let response = await fetch(`${this.opts.host}/turing/conversation/create`, fetchOptions) + let response = await fetch(`${this.opts.host}/turing/conversation/create?bundleVersion=1.1055.6`, fetchOptions) let text = await response.text() let retry = 10 while (retry >= 0 && response.status === 200 && !text) { @@ -115,7 +115,11 @@ export default class SydneyAIClient { throw new Error('创建sydney对话失败: status code: ' + response.status + response.statusText) } try { - return JSON.parse(text) + let r = JSON.parse(text) + if (!r.conversationSignature) { + r.encryptedconversationsignature = response.headers.get('x-sydney-encryptedconversationsignature') + } + return r } catch (err) { logger.error('创建sydney对话失败: status code: ' + response.status + response.statusText) logger.error(text) @@ -123,7 +127,7 @@ export default class SydneyAIClient { } } - async createWebSocketConnection () { + async createWebSocketConnection (encryptedconversationsignature = '') { await this.initCache() // let WebSocket = await getWebSocket() return new Promise((resolve, reject) => { @@ -136,7 +140,11 @@ export default class SydneyAIClient { sydneyHost = Config.sydneyReverseProxy.replace('https://', 'wss://').replace('http://', 'ws://') } logger.mark(`use sydney websocket host: ${sydneyHost}`) - let ws = new WebSocket(sydneyHost + '/sydney/ChatHub', undefined, { agent, origin: 'https://edgeservices.bing.com' }) + let host = sydneyHost + '/sydney/ChatHub' + if (encryptedconversationsignature) { + host += `?sec_access_token=${encodeURIComponent(encryptedconversationsignature)}` + } + let ws = new WebSocket(host, undefined, { agent, origin: 'https://edgeservices.bing.com' }) ws.on('error', (err) => { console.error(err) reject(err) @@ -219,6 +227,7 @@ export default class SydneyAIClient { // if (messageType === 'Chat') { // logger.warn('该Bing账户token已被限流,降级至使用非搜索模式。本次对话AI将无法使用Bing搜索返回的内容') // } + let encryptedconversationsignature = '' if (typeof onProgress !== 'function') { onProgress = () => { } } @@ -231,7 +240,7 @@ export default class SydneyAIClient { if (createNewConversationResponse.result?.value === 'UnauthorizedRequest') { throw new Error(`UnauthorizedRequest: ${createNewConversationResponse.result.message}`) } - if (!createNewConversationResponse.conversationSignature || !createNewConversationResponse.conversationId || !createNewConversationResponse.clientId) { + if (!createNewConversationResponse.conversationId || !createNewConversationResponse.clientId) { const resultValue = createNewConversationResponse.result?.value if (resultValue) { throw new Error(`${resultValue}: ${createNewConversationResponse.result.message}`) @@ -241,7 +250,8 @@ export default class SydneyAIClient { ({ conversationSignature, conversationId, - clientId + clientId, + encryptedconversationsignature } = createNewConversationResponse) } let pureSydney = Config.toneStyle === 'Sydney' @@ -331,7 +341,7 @@ export default class SydneyAIClient { role: 'User', message } - const ws = await this.createWebSocketConnection() + const ws = await this.createWebSocketConnection(encryptedconversationsignature) if (Config.debug) { logger.mark('sydney websocket constructed successful') } @@ -361,62 +371,67 @@ export default class SydneyAIClient { let maxConv = Config.maxNumUserMessagesInConversation const currentDate = moment().format('YYYY-MM-DDTHH:mm:ssZ') const imageDate = await this.kblobImage(opts.imageUrl) + let argument0 = { + source: 'cib', + optionsSets, + allowedMessageTypes: ['ActionRequest', 'Chat', 'Context', + // 'InternalSearchQuery', 'InternalSearchResult', 'Disengaged', 'InternalLoaderMessage', 'Progress', 'RenderCardRequest', 'AdsQuery', + 'SemanticSerp', 'GenerateContentQuery', 'SearchQuery'], + sliceIds: [ + + ], + requestId: crypto.randomUUID(), + traceId: genRanHex(32), + scenario: 'Underside', + verbosity: 'verbose', + isStartOfSession: invocationId === 0, + message: { + locale: 'zh-CN', + market: 'zh-CN', + region: 'WW', + location: 'lat:47.639557;long:-122.128159;re=1000m;', + locationHints: [ + { + country: 'Macedonia', + state: 'Centar', + city: 'Skopje', + zipcode: '1004', + timezoneoffset: 1, + countryConfidence: 8, + cityConfidence: 5, + Center: { + Latitude: 41.9961, + Longitude: 21.4317 + }, + RegionType: 2, + SourceType: 1 + } + ], + author: 'user', + inputMethod: 'Keyboard', + imageUrl: imageDate.blobId ? `https://www.bing.com/images/blob?bcid=${imageDate.blobId}` : undefined, + originalImageUrl: imageDate.processedBlobId ? `https://www.bing.com/images/blob?bcid=${imageDate.processedBlobId}` : undefined, + text: message, + messageType, + userIpAddress: await generateRandomIP(), + timestamp: currentDate + // messageType: 'SearchQuery' + }, + tone: 'Creative', + conversationSignature, + participant: { + id: clientId + }, + spokenTextMode: 'None', + conversationId, + previousMessages + } + if (encryptedconversationsignature) { + delete argument0.conversationSignature + } const obj = { arguments: [ - { - source: 'cib', - optionsSets, - allowedMessageTypes: ['ActionRequest', 'Chat', 'Context', - // 'InternalSearchQuery', 'InternalSearchResult', 'Disengaged', 'InternalLoaderMessage', 'Progress', 'RenderCardRequest', 'AdsQuery', - 'SemanticSerp', 'GenerateContentQuery', 'SearchQuery'], - sliceIds: [ - - ], - traceId: genRanHex(32), - scenario: 'Underside', - verbosity: 'verbose', - isStartOfSession: invocationId === 0, - message: { - locale: 'zh-CN', - market: 'zh-CN', - region: 'WW', - location: 'lat:47.639557;long:-122.128159;re=1000m;', - locationHints: [ - { - country: 'Macedonia', - state: 'Centar', - city: 'Skopje', - zipcode: '1004', - timezoneoffset: 1, - countryConfidence: 8, - cityConfidence: 5, - Center: { - Latitude: 41.9961, - Longitude: 21.4317 - }, - RegionType: 2, - SourceType: 1 - } - ], - author: 'user', - inputMethod: 'Keyboard', - imageUrl: imageDate.blobId ? `https://www.bing.com/images/blob?bcid=${imageDate.blobId}` : undefined, - originalImageUrl: imageDate.processedBlobId ? `https://www.bing.com/images/blob?bcid=${imageDate.processedBlobId}` : undefined, - text: message, - messageType, - userIpAddress: await generateRandomIP(), - timestamp: currentDate - // messageType: 'SearchQuery' - }, - tone: 'Creative', - conversationSignature, - participant: { - id: clientId - }, - spokenTextMode: 'None', - conversationId, - previousMessages - } + argument0 ], invocationId: invocationId.toString(), target: 'chat',