From 8efcce45a04bda2bb8ec66e44026a635d97472bf Mon Sep 17 00:00:00 2001 From: zyc404 Date: Wed, 8 May 2024 15:42:35 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4bard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/chat.js | 13 +- apps/management.js | 15 -- guoba.support.js | 22 -- model/conversation.js | 20 +- model/core.js | 50 ----- resources/view/setting_view.json | 25 --- utils/bard.js | 373 ------------------------------- utils/config.js | 3 - 8 files changed, 4 insertions(+), 517 deletions(-) delete mode 100644 utils/bard.js diff --git a/apps/chat.js b/apps/chat.js index bc1058e..3cbe2e9 100644 --- a/apps/chat.js +++ b/apps/chat.js @@ -735,10 +735,6 @@ export class chatgpt extends plugin { key = `CHATGPT:CONVERSATIONS_XH:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}` break } - case 'bard': { - key = `CHATGPT:CONVERSATIONS_BARD:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}` - break - } case 'azure': { key = `CHATGPT:CONVERSATIONS_AZURE:${e.sender.user_id}` break @@ -797,8 +793,8 @@ export class chatgpt extends plugin { if (chatMessage?.noMsg) { return false } - // 处理星火和bard图片 - if ((use === 'bard' || use === 'xh') && chatMessage?.images) { + // 处理星火图片 + if (use === 'xh' && chatMessage?.images) { chatMessage.images.forEach(element => { this.reply([element.tag, segment.image(element.url)]) }) @@ -826,11 +822,6 @@ export class chatgpt extends plugin { } previousConversation.messages.push(chatMessage.message) } - if (use === 'bard' && !chatMessage.error) { - previousConversation.parentMessageId = chatMessage.responseID - previousConversation.clientId = chatMessage.choiceID - previousConversation.invocationId = chatMessage._reqID - } if (Config.debug) { logger.info(chatMessage) } diff --git a/apps/management.js b/apps/management.js index 6bd69e2..33f40bd 100644 --- a/apps/management.js +++ b/apps/management.js @@ -123,11 +123,6 @@ export class ChatgptManagement extends plugin { fnc: 'useAzureBasedSolution', permission: 'master' }, - { - reg: '^#chatgpt切换(Bard|bard)$', - fnc: 'useBardBasedSolution', - permission: 'master' - }, { reg: '^#chatgpt切换(通义千问|qwen|千问)$', fnc: 'useQwenSolution', @@ -968,16 +963,6 @@ azure语音:Azure 语音是微软 Azure 平台提供的一项语音服务, } } - async useBardBasedSolution () { - let use = await redis.get('CHATGPT:USE') - if (use !== 'bard') { - await redis.set('CHATGPT:USE', 'bard') - await this.reply('已切换到基于Bard的解决方案') - } else { - await this.reply('当前已经是Bard模式了') - } - } - async patchGemini () { const _path = process.cwd() let packageJson = fs.readFileSync(`${_path}/package.json`) diff --git a/guoba.support.js b/guoba.support.js index 293d7ce..82ab825 100644 --- a/guoba.support.js +++ b/guoba.support.js @@ -531,28 +531,6 @@ export function supportGuoba () { bottomHelpMessage: '替换回复内容中的文本', component: 'Input' }, - { - label: '以下为Bard方式的配置', - component: 'Divider' - }, - { - field: 'bardPsid', - label: 'BardCookie', - bottomHelpMessage: '获取https://bard.google.com/页面的cookie,可完整输入,需至少包含__Secure-1PSID和__Secure-1PSIDTS', - component: 'Input' - }, - { - field: 'bardReverseProxy', - label: 'Bard反代地址', - bottomHelpMessage: 'bard反代服务器地址,用于绕过地区限制', - component: 'Input' - }, - { - field: 'bardForceUseReverse', - label: 'Bard使用反代', - bottomHelpMessage: '开启后将通过反代访问bard', - component: 'Switch' - }, { label: '以下为通义千问API方式的配置', component: 'Divider' diff --git a/model/conversation.js b/model/conversation.js index ced1084..bbe46b6 100644 --- a/model/conversation.js +++ b/model/conversation.js @@ -3,8 +3,8 @@ import { Config } from '../utils/config.js' import { KeyvFile } from 'keyv-file' import _ from 'lodash' -export const originalValues = ['星火', '通义千问', '克劳德', '克劳德2', '必应', 'api', 'API', 'api3', 'API3', 'glm', '巴德', '双子星', '双子座', '智谱'] -export const correspondingValues = ['xh', 'qwen', 'claude', 'claude2', 'bing', 'api', 'api', 'api3', 'api3', 'chatglm', 'bard', 'gemini', 'gemini', 'chatglm4'] +export const originalValues = ['星火', '通义千问', '克劳德', '克劳德2', '必应', 'api', 'API', 'api3', 'API3', 'glm', '双子星', '双子座', '智谱'] +export const correspondingValues = ['xh', 'qwen', 'claude', 'claude2', 'bing', 'api', 'api', 'api3', 'api3', 'chatglm', 'gemini', 'gemini', 'chatglm4'] export class ConversationManager { async endConversation (e) { @@ -35,11 +35,6 @@ export class ConversationManager { await this.reply('星火对话已结束') return } - if (use === 'bard') { - await redis.del(`CHATGPT:CONVERSATIONS_BARD:${(e.isGroup && Config.groupMerge) ? e.group_id.toString() : e.sender.user_id}`) - await this.reply('Bard对话已结束') - return - } let ats = e.message.filter(m => m.type === 'at') const isAtMode = Config.toggleMode === 'at' if (isAtMode) ats = ats.filter(item => item.qq !== getUin(e)) @@ -259,17 +254,6 @@ export class ConversationManager { } break } - case 'bard': { - let cs = await redis.keys('CHATGPT:CONVERSATIONS_BARD:*') - for (let i = 0; i < cs.length; i++) { - await redis.del(cs[i]) - if (Config.debug) { - logger.info('delete bard conversation of qq: ' + cs[i]) - } - deleted++ - } - break - } case 'bing': { let cs = await redis.keys('CHATGPT:CONVERSATIONS_BING:*') let we = await redis.keys('CHATGPT:WRONG_EMOTION:*') diff --git a/model/core.js b/model/core.js index 031e4d8..1157ced 100644 --- a/model/core.js +++ b/model/core.js @@ -25,7 +25,6 @@ import XinghuoClient from '../utils/xinghuo/xinghuo.js' import { getMessageById, upsertMessage } from '../utils/history.js' import { v4 as uuid } from 'uuid' import fetch from 'node-fetch' -import Bard from '../utils/bard.js' import { CustomGoogleGeminiClient } from '../client/CustomGoogleGeminiClient.js' import { resizeAndCropImage } from '../utils/dalle.js' import fs from 'fs' @@ -706,55 +705,6 @@ class Core { } return msg } - } else if (use === 'bard') { - // 处理cookie - const matchesPSID = /__Secure-1PSID=([^;]+)/.exec(Config.bardPsid) - const matchesPSIDTS = /__Secure-1PSIDTS=([^;]+)/.exec(Config.bardPsid) - const cookie = { - '__Secure-1PSID': matchesPSID[1], - '__Secure-1PSIDTS': matchesPSIDTS[1] - } - if (!matchesPSID[1] || !matchesPSIDTS[1]) { - throw new Error('未绑定bard') - } - // 处理图片 - const image = await getImg(e) - let imageBuff - if (image) { - try { - let imgResponse = await fetch(image[0]) - if (imgResponse.ok) { - imageBuff = await imgResponse.arrayBuffer() - } - } catch (error) { - logger.warn(`错误的图片链接${image[0]}`) - } - } - // 发送数据 - let bot = new Bard(cookie, { - fetch, - bardURL: Config.bardForceUseReverse ? Config.bardReverseProxy : 'https://bard.google.com' - }) - let chat = await bot.createChat(conversation?.conversationId - ? { - conversationID: conversation.conversationId, - responseID: conversation.parentMessageId, - choiceID: conversation.clientId, - _reqID: conversation.invocationId - } - : {}) - let response = await chat.ask(prompt, { - image: imageBuff, - format: Bard.JSON - }) - return { - conversationId: response.ids.conversationID, - responseID: response.ids.responseID, - choiceID: response.ids.choiceID, - _reqID: response.ids._reqID, - text: response.content, - images: response.images - } } else if (use === 'gemini') { let client = new CustomGoogleGeminiClient({ e, diff --git a/resources/view/setting_view.json b/resources/view/setting_view.json index a0c09ee..6a3a039 100644 --- a/resources/view/setting_view.json +++ b/resources/view/setting_view.json @@ -81,10 +81,6 @@ "label": "Azure OpenAI", "value": "azure" }, - { - "label": "Bard", - "value": "bard" - }, { "label": "ChatGPT API3", "value": "api3" @@ -819,27 +815,6 @@ } ] }, - { - "title": "Bard", - "tab": "bard", - "view": [ - { - "type": "password", - "label": "BardCookie", - "data": "bardPsid" - }, - { - "type": "url", - "label": "Bard反代地址", - "data": "bardReverseProxy" - }, - { - "type": "check", - "label": "使用Bard反代", - "data": "bardForceUseReverse" - } - ] - }, { "title": "通义千问", "tab": "qwen", diff --git a/utils/bard.js b/utils/bard.js deleted file mode 100644 index a28e060..0000000 --- a/utils/bard.js +++ /dev/null @@ -1,373 +0,0 @@ -// https://github.com/EvanZhouDev/bard-ai - -class Bard { - static JSON = 'json' - static MD = 'markdown' - - // ID derived from Cookie - SNlM0e - - // HTTPS Headers - #headers - - // Resolution status of initialization call - #initPromise - - #bardURL = 'https://bard.google.com' - - // Wether or not to log events to console - #verbose = false - - // Fetch function - #fetch = fetch - - constructor (cookie, config) { - // Register some settings - if (config?.verbose == true) this.#verbose = true - if (config?.fetch) this.#fetch = config.fetch - // 可变更访问地址,利用反向代理绕过区域限制 - if (config?.bardURL) this.#bardURL = config.bardURL - - // If a Cookie is provided, initialize - if (cookie) { - this.#initPromise = this.#init(cookie) - } else { - throw new Error('Please provide a Cookie when initializing Bard.') - } - this.cookie = cookie - } - - // You can also choose to initialize manually - async #init (cookie) { - this.#verbose && console.log('🚀 Starting intialization') - // Assign headers - this.#headers = { - Host: this.#bardURL.match(/^https?:\/\/([^\/]+)\/?$/)[1], - 'X-Same-Domain': '1', - 'User-Agent': - 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36', - 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', - Origin: this.#bardURL, - Referer: this.#bardURL, - Cookie: (typeof cookie === 'object') ? (Object.entries(cookie).map(([key, val]) => `${key}=${val};`).join('')) : ('__Secure-1PSID=' + cookie) - } - - let responseText - // Attempt to retrieve SNlM0e - try { - this.#verbose && - console.log('🔒 Authenticating your Google account') - responseText = await this.#fetch(this.#bardURL, { - method: 'GET', - headers: this.#headers, - credentials: 'include' - }) - .then((response) => response.text()) - } catch (e) { - // Failure to get server - throw new Error( - 'Could not fetch Google Bard. You may be disconnected from internet: ' + - e - ) - } - - try { - const SNlM0e = responseText.match(/SNlM0e":"(.*?)"/)[1] - // Assign SNlM0e and return it - this.SNlM0e = SNlM0e - this.#verbose && console.log('✅ Initialization finished\n') - return SNlM0e - } catch { - throw new Error( - 'Could not use your Cookie. Make sure that you copied correctly the Cookie with name __Secure-1PSID exactly. If you are sure your cookie is correct, you may also have reached your rate limit.' - ) - } - } - - async #uploadImage (name, buffer) { - this.#verbose && console.log('🖼️ Starting image processing') - let size = buffer.byteLength - let formBody = [ - `${encodeURIComponent('File name')}=${encodeURIComponent([name])}` - ] - - try { - this.#verbose && - console.log('💻 Finding Google server destination') - let response = await this.#fetch( - 'https://content-push.googleapis.com/upload/', - { - method: 'POST', - headers: { - 'X-Goog-Upload-Command': 'start', - 'X-Goog-Upload-Protocol': 'resumable', - 'X-Goog-Upload-Header-Content-Length': size, - 'X-Tenant-Id': 'bard-storage', - 'Push-Id': 'feeds/mcudyrk2a4khkz' - }, - body: formBody, - credentials: 'include' - } - ) - - const uploadUrl = response.headers.get('X-Goog-Upload-URL') - this.#verbose && console.log('📤 Sending your image') - response = await this.#fetch(uploadUrl, { - method: 'POST', - headers: { - 'X-Goog-Upload-Command': 'upload, finalize', - 'X-Goog-Upload-Offset': 0, - 'X-Tenant-Id': 'bard-storage' - }, - body: buffer, - credentials: 'include' - }) - - const imageFileLocation = await response.text() - - this.#verbose && console.log('✅ Image finished working\n') - return imageFileLocation - } catch (e) { - throw new Error( - 'Could not fetch Google Bard. You may be disconnected from internet: ' + - e - ) - } - } - - // Query Bard - async #query (message, config) { - let formatMarkdown = (text, images) => { - if (!images) return text - - for (let imageData of images) { - const formattedTag = `!${imageData.tag}(${imageData.url})` - text = text.replace( - new RegExp(`(?!\\!)\\[${imageData.tag.slice(1, -1)}\\]`), - formattedTag - ) - } - - return text - } - - let { ids, imageBuffer } = config - - // Wait until after init - await this.#initPromise - - this.#verbose && console.log('🔎 Starting Bard Query') - - // If user has not run init - if (!this.SNlM0e) { - throw new Error( - "Please initialize Bard first. If you haven't passed in your Cookie into the class, run Bard.init(cookie)." - ) - } - - this.#verbose && console.log('🏗️ Building Request') - // HTTPS parameters - const params = { - bl: 'boq_assistant-bard-web-server_20230711.08_p0', - _reqID: ids?._reqID ?? '0', - rt: 'c' - } - - // If IDs are provided, but doesn't have every one of the expected IDs, error - const messageStruct = [ - [message], - null, - [null, null, null] - ] - - if (imageBuffer) { - let imageLocation = await this.#uploadImage( - 'bard-ai_upload', - imageBuffer - ) - messageStruct[0].push(0, null, [ - [[imageLocation, 1], 'bard-ai_upload'] - ]) - } - - if (ids) { - const { conversationID, responseID, choiceID } = ids - messageStruct[2] = [conversationID, responseID, choiceID] - } - - // HTTPs data - const data = { - 'f.req': JSON.stringify([null, JSON.stringify(messageStruct)]), - at: this.SNlM0e - } - - // URL that we are submitting to - const url = new URL( - '/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate', - this.#bardURL - ) - - // Append parameters to the URL - for (const key in params) { - url.searchParams.append(key, params[key]) - } - - // Encode the data - const formBody = Object.entries(data) - .map( - ([property, value]) => - `${encodeURIComponent(property)}=${encodeURIComponent( - value - )}` - ) - .join('&') - - this.#verbose && console.log('💭 Sending message to Bard') - // Send the fetch request - const chatData = await this.#fetch(url.toString(), { - method: 'POST', - headers: this.#headers, - body: formBody, - credentials: 'include' - }) - .then((response) => { - return response.text() - }) - .then((text) => { - return JSON.parse(text.split('\n')[3])[0][2] - }) - .then((rawData) => JSON.parse(rawData)) - - this.#verbose && console.log('🧩 Parsing output') - // Get first Bard-recommended answer - const answer = chatData[4][0] - - // Text of that answer - const text = answer[1][0] - - // Get data about images in that answer - const images = - answer[4]?.map((x) => ({ - tag: x[2], - url: x[3][0][0], - info: { - raw: x[0][0][0], - source: x[1][0][0], - alt: x[0][4], - website: x[1][1], - favicon: x[1][3] - } - })) ?? [] - - this.#verbose && console.log('✅ All done!\n') - // Put everything together and return - return { - content: formatMarkdown(text, images), - images, - ids: { - conversationID: chatData[1][0], - responseID: chatData[1][1], - choiceID: answer[0], - _reqID: String(parseInt(ids?._reqID ?? 0) + 100000) - } - } - } - - async #parseConfig (config) { - let result = { - useJSON: false, - imageBuffer: undefined, // Returns as {extension, filename} - ids: undefined - } - - // Verify that format is one of the two types - if (config?.format) { - switch (config.format) { - case Bard.JSON: - result.useJSON = true - break - case Bard.MD: - result.useJSON = false - break - default: - throw new Error( - 'Format can obly be Bard.JSON for JSON output or Bard.MD for Markdown output.' - ) - } - } - - // Verify that the image passed in is either a path to a jpeg, jpg, png, or webp, or that it is a Buffer - if (config?.image) { - if ( - config.image instanceof ArrayBuffer - ) { - result.imageBuffer = config.image - } else if ( - typeof config.image === 'string' && - /\.(jpeg|jpg|png|webp)$/.test(config.image) - ) { - let fs - - try { - fs = await import('fs') - } catch { - throw new Error( - 'Loading from an image file path is not supported in a browser environment.' - ) - } - - result.imageBuffer = fs.readFileSync( - config.image - ).buffer - } else { - throw new Error( - 'Provide your image as a file path to a .jpeg, .jpg, .png, or .webp, or a Buffer.' - ) - } - } - - // Verify that all values in IDs exist - if (config?.ids) { - if (config.ids.conversationID && config.ids.responseID && config.ids.choiceID && config.ids._reqID) { - result.ids = config.ids - } else { - throw new Error( - 'Please provide the IDs exported exactly as given.' - ) - } - } - return result - } - - // Ask Bard a question! - async ask (message, config) { - let { useJSON, imageBuffer, ids } = await this.#parseConfig(config) - let response = await this.#query(message, { imageBuffer, ids }) - return useJSON ? response : response.content - } - - createChat (ids) { - let bard = this - class Chat { - ids = ids - - async ask (message, config) { - let { useJSON, imageBuffer } = await bard.#parseConfig(config) - let response = await bard.#query(message, { - imageBuffer, - ids: this.ids - }) - this.ids = response.ids - return useJSON ? response : response.content - } - - export () { - return this.ids - } - } - - return new Chat() - } -} - -export default Bard diff --git a/utils/config.js b/utils/config.js index c103a7c..a265704 100644 --- a/utils/config.js +++ b/utils/config.js @@ -136,9 +136,6 @@ const defaultConfig = { // slackCozeEnableGlobalPreset: true, // slackCozeGlobalPreset: '', // slackCozeSpecifiedChannel: '', - bardPsid: '', - bardReverseProxy: '', - bardForceUseReverse: false, cloudTranscode: 'https://silk.201666.xyz', cloudRender: false, cloudMode: 'url',