diff --git a/README.md b/README.md index 476fb29..afc92f0 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,14 @@ let response = await bot.ask("Hello?"); console.log(response); ``` -## Usage: ***Using proxy is recomended!*** +## Features + +- **Simulating Response Streaming**: The package simulates response streaming, allowing you to get the response as soon as it is available. +- **Multiple conversations**: The package supports multiple conversations, allowing you to have multiple parallel conversations with the chatbot. +- **Proxy Support**: The package supports proxies, allowing you to use the chatbot from any location. +- **Lightweight**: The package is very lightweight, making it easy to use and integrate into your projects. + +## Usage: **_Using proxy is recomended!_** ```javascript import { Bard } from "GoogleBard"; @@ -51,4 +58,11 @@ let conversationId = "conversation name"; // optional: to make it remember old c let response = await bot.ask("Hello?", conversationId); console.log(response); + +// Simulating response streaming + +await bot.askStream((res) => { + console.log(res); +}, "Hello?", conversationId); + ``` diff --git a/example.env b/example.env new file mode 100644 index 0000000..4dc1743 --- /dev/null +++ b/example.env @@ -0,0 +1,5 @@ +PROXY_HOST= +PROXY_PORT= +PROXY_PROTOCOL= +PROXY_USERNAME= +PROXY_PASSWORD= diff --git a/examples/cli.js b/examples/cli.js index 0dd1a03..c9331e1 100644 --- a/examples/cli.js +++ b/examples/cli.js @@ -1,6 +1,9 @@ import { Bard } from "../dist/index.js"; +import { config } from "dotenv"; import readline from "readline"; +config(); + const rl = readline.createInterface({ input: process.stdin, output: process.stdout @@ -16,7 +19,7 @@ let bot = new Bard(cookies, { username: process.env.PROXY_USERNAME, password: process.env.PROXY_PASSWORD }, - protocol: "http" + protocol: process.env.PROXY_PROTOCOL } }); @@ -29,8 +32,10 @@ async function main() { }); process.stdout.write("Google Bard: "); - let response = await bot.ask(prompt, "default"); - console.log(response); + await bot.askStream(res => { + process.stdout.write(res.toString()); + }, prompt); + console.log(); } } diff --git a/package-lock.json b/package-lock.json index 989c2dd..18970be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { "name": "googlebard", - "version": "1.0.1", + "version": "1.0.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "googlebard", - "version": "1.0.1", + "version": "1.0.2", "license": "MIT", "dependencies": { "axios": "1.3.2", "cheerio": "1.0.0-rc.12", - "dbcontext": "1.0.1" + "dbcontext": "1.0.1", + "dotenv": "16.0.3" }, "devDependencies": { "@types/node": "18.11.18", @@ -199,6 +200,14 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dotenv": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", + "engines": { + "node": ">=12" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", diff --git a/package.json b/package.json index 552b5b6..30cee54 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "googlebard", - "version": "1.0.1", + "version": "1.0.2", "description": "A reverse engineered API for Google Bard chatbot", "main": "dist/index.js", "type": "module", @@ -58,7 +58,8 @@ "dependencies": { "axios": "1.3.2", "cheerio": "1.0.0-rc.12", - "dbcontext": "1.0.1" + "dbcontext": "1.0.1", + "dotenv": "16.0.3" }, "bugs": { "url": "https://github.com/PawanOsman/GoogleBard/issues" diff --git a/src/classes/bard.ts b/src/classes/bard.ts index 97be723..f128403 100644 --- a/src/classes/bard.ts +++ b/src/classes/bard.ts @@ -2,22 +2,28 @@ import vm from "vm"; import fs from "fs"; import https from "https"; import { load } from "cheerio"; +import Wait from "../utils/wait.js"; +import Random from "../utils/random.js"; import Options from "../models/options.js"; -import axios, { AxiosInstance } from "axios"; import AppDbContext from "./app-dbcontext.js"; import Conversation from "../models/conversation.js"; +import axios, { AxiosInstance, AxiosRequestConfig } from "axios"; class Bard { private axios: AxiosInstance; private db: AppDbContext; + private cookies: string = ""; constructor(cookie: string, options?: Options) { this.db = new AppDbContext(); + + this.cookies = cookie; + const agent = new https.Agent({ rejectUnauthorized: false, }); - let axiosOptions = { + let axiosOptions: AxiosRequestConfig = { proxy: options?.proxy, httpsAgent: agent, headers: { @@ -26,7 +32,6 @@ class Bard { "Accept-Language": "en-US,en;q=0.5", "Accept-Encoding": "gzip, deflate, br", Connection: "keep-alive", - Cookie: cookie, "Upgrade-Insecure-Requests": "1", "Sec-Fetch-Dest": "document", "Sec-Fetch-Mode": "navigate", @@ -42,7 +47,7 @@ class Bard { private async waitForLoad() { while (this.db === null) { - await this.wait(1000); + await Wait(1000); } await this.db.WaitForLoad(); } @@ -89,10 +94,6 @@ class Bard { }; } - wait(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); - } - private ParseResponse(text: string) { let resData = { r: "", @@ -143,7 +144,11 @@ class Bard { private async GetRequestParams() { try { - const response = await this.axios.get("https://bard.google.com"); + const response = await this.axios.get("https://bard.google.com", { + headers: { + Cookie: this.cookies, + }, + }); let $ = load(response.data); let script = $("script[data-id=_gd]").html(); script = script.replace("window.WIZ_global_data", "googleData"); @@ -159,12 +164,22 @@ class Bard { } } - public async ask(prompt: string = "Hello", conversationId?: string) { + public async ask(prompt: string, conversationId?: string) { + return await this.askStream((data) => {}, prompt, conversationId); + } + + public async askStream(data: (arg0: string) => void, prompt: string, conversationId?: string) { let resData = await this.send(prompt, conversationId); - return resData[0]; + let responseChunks = resData[0].split(" "); + for await (let chunk of responseChunks) { + if (chunk === "") continue; + data(`${chunk} `); + await Wait(Random(25, 250)); // simulate typing + } + return resData[1]; } - private async send(prompt: string = "Hello", conversationId?: string) { + private async send(prompt: string, conversationId?: string) { await this.waitForLoad(); let conversation = this.getConversationById(conversationId); try { @@ -176,6 +191,9 @@ class Bard { "f.req": JSON.stringify([null, `[[${JSON.stringify(prompt)}],null,${JSON.stringify([conversation.c, conversation.r, conversation.rc])}]`]), }), { + headers: { + Cookie: this.cookies, + }, params: { bl: bl, rt: "c", @@ -183,6 +201,11 @@ class Bard { }, }, ); + + // let cookies = response.headers["set-cookie"]; + + // if (cookies) this.cookies = cookies.join("; "); + let parsedResponse = this.ParseResponse(response.data); conversation.c = parsedResponse.c; conversation.r = parsedResponse.r; diff --git a/src/utils/random.ts b/src/utils/random.ts new file mode 100644 index 0000000..f892f97 --- /dev/null +++ b/src/utils/random.ts @@ -0,0 +1,5 @@ +function Random(min: number, max: number) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +export default Random; diff --git a/src/utils/wait.ts b/src/utils/wait.ts new file mode 100644 index 0000000..b1d7add --- /dev/null +++ b/src/utils/wait.ts @@ -0,0 +1,5 @@ +function Wait(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +export default Wait;