fix: remove useless thing

This commit is contained in:
ikechan8370 2024-03-09 23:37:47 +08:00
parent 5c544a5ca7
commit bd7aac0517
53 changed files with 350 additions and 2639 deletions

View file

@ -1,373 +1,373 @@
// https://github.com/EvanZhouDev/bard-ai
class Bard {
static JSON = "json";
static MD = "markdown";
static JSON = 'json'
static MD = 'markdown'
// ID derived from Cookie
SNlM0e;
SNlM0e
// HTTPS Headers
#headers;
#headers
// Resolution status of initialization call
#initPromise;
#initPromise
#bardURL = "https://bard.google.com";
#bardURL = 'https://bard.google.com'
// Wether or not to log events to console
#verbose = false;
#verbose = false
// Fetch function
#fetch = fetch;
#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;
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;
// 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),
};
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: " +
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."
);
}
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])}`,
];
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",
}
);
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 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();
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: " +
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;
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;
for (let imageData of images) {
const formattedTag = `!${imageData.tag}(${imageData.url})`
text = text.replace(
new RegExp(`(?!\\!)\\[${imageData.tag.slice(1, -1)}\\]`),
formattedTag
)
}
let { ids, imageBuffer } = config;
return text
}
// Wait until after init
await this.#initPromise;
let { ids, imageBuffer } = config
this.#verbose && console.log("🔎 Starting Bard Query");
// Wait until after init
await this.#initPromise
// 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('🔎 Starting Bard Query')
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 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)."
)
}
// If IDs are provided, but doesn't have every one of the expected IDs, error
const messageStruct = [
[message],
null,
[null, null, null],
];
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 (imageBuffer) {
let imageLocation = await this.#uploadImage(
`bard-ai_upload`,
imageBuffer
);
messageStruct[0].push(0, null, [
[[imageLocation, 1], "bard-ai_upload"],
]);
}
// If IDs are provided, but doesn't have every one of the expected IDs, error
const messageStruct = [
[message],
null,
[null, null, null]
]
if (ids) {
const { conversationID, responseID, choiceID } = ids;
messageStruct[2] = [conversationID, responseID, choiceID];
}
if (imageBuffer) {
let imageLocation = await this.#uploadImage(
'bard-ai_upload',
imageBuffer
)
messageStruct[0].push(0, null, [
[[imageLocation, 1], 'bard-ai_upload']
])
}
// HTTPs data
const data = {
"f.req": JSON.stringify([null, JSON.stringify(messageStruct)]),
at: this.SNlM0e,
};
if (ids) {
const { conversationID, responseID, choiceID } = ids
messageStruct[2] = [conversationID, responseID, choiceID]
}
// URL that we are submitting to
const url = new URL(
"/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate",
this.#bardURL
);
// HTTPs data
const data = {
'f.req': JSON.stringify([null, JSON.stringify(messageStruct)]),
at: this.SNlM0e
}
// Append parameters to the URL
for (const key in params) {
url.searchParams.append(key, params[key]);
}
// URL that we are submitting to
const url = new URL(
'/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate',
this.#bardURL
)
// Encode the data
const formBody = Object.entries(data)
.map(
([property, value]) =>
// 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("&");
)
.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",
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((response) => {
return response.text();
})
.then((text) => {
return JSON.parse(text.split("\n")[3])[0][2];
})
.then((rawData) => JSON.parse(rawData));
.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];
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];
// Text of that answer
const text = answer[1][0]
// Get data about images in that answer
const images =
// 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],
},
})) ?? [];
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: images,
ids: {
conversationID: chatData[1][0],
responseID: chatData[1][1],
choiceID: answer[0],
_reqID: String(parseInt(ids?._reqID ?? 0) + 100000),
},
};
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,
};
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 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" &&
// 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;
) {
let fs
try {
fs = await import("fs")
} catch {
throw new Error(
"Loading from an image file path is not supported in a browser environment.",
);
}
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."
);
}
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."
);
}
// 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;
}
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;
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;
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;
}
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
}
return new Chat();
export () {
return this.ids
}
}
return new Chat()
}
}
export default Bard;
export default Bard