kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
Merge pull request #166 from waylaidwanderer/feat/add-proxy-support
commit
29ace8f990
|
@ -1,6 +1,7 @@
|
||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||||
|
|
||||||
*.swp
|
*.swp
|
||||||
|
.idea
|
||||||
|
|
||||||
# dependencies
|
# dependencies
|
||||||
/node_modules
|
/node_modules
|
||||||
|
|
Plik diff jest za duży
Load Diff
17
readme.md
17
readme.md
|
@ -47,6 +47,7 @@ Thanks && cheers,
|
||||||
- [Demos](#demos)
|
- [Demos](#demos)
|
||||||
- [Authentication](#authentication)
|
- [Authentication](#authentication)
|
||||||
- [CAPTCHAs](#captchas)
|
- [CAPTCHAs](#captchas)
|
||||||
|
- [Using Proxies](#using-proxies)
|
||||||
- [Restrictions](#restrictions)
|
- [Restrictions](#restrictions)
|
||||||
- [Projects](#projects)
|
- [Projects](#projects)
|
||||||
- [Compatibility](#compatibility)
|
- [Compatibility](#compatibility)
|
||||||
|
@ -264,6 +265,22 @@ const api = new ChatGPTAPIBrowser({
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Using Proxies
|
||||||
|
|
||||||
|
The browser implementation supports setting a proxy server. This is useful if you're running into rate limiting issues or if you want to use a proxy to hide your IP address.
|
||||||
|
|
||||||
|
To use a proxy, pass the `proxyServer` option to the `ChatGPTAPIBrowser` constructor, or simply set the `PROXY_SERVER` env var. For more information on the format, see [here](https://www.chromium.org/developers/design-documents/network-settings).
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const api = new ChatGPTAPIBrowser({
|
||||||
|
email: process.env.OPENAI_EMAIL,
|
||||||
|
password: process.env.OPENAI_PASSWORD,
|
||||||
|
proxyServer: '<ip>:<port>'
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also set the `PROXY_VALIDATE_IP` env var to your proxy's IP address. This will be used to validate that the proxy is working correctly, and will throw an error if it's not.
|
||||||
|
|
||||||
### Restrictions
|
### Restrictions
|
||||||
|
|
||||||
These restrictions are for the `getOpenAIAuth` + `ChatGPTAPI` solution, which uses the unofficial API. The browser-based solution, `ChatGPTAPIBrowser`, generally doesn't have any of these restrictions.
|
These restrictions are for the `getOpenAIAuth` + `ChatGPTAPI` solution, which uses the unofficial API. The browser-based solution, `ChatGPTAPIBrowser`, generally doesn't have any of these restrictions.
|
||||||
|
|
|
@ -29,6 +29,7 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI {
|
||||||
protected _executablePath: string
|
protected _executablePath: string
|
||||||
protected _browser: Browser
|
protected _browser: Browser
|
||||||
protected _page: Page
|
protected _page: Page
|
||||||
|
protected _proxyServer: string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new client for automating the ChatGPT webapp.
|
* Creates a new client for automating the ChatGPT webapp.
|
||||||
|
@ -54,6 +55,9 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI {
|
||||||
|
|
||||||
/** @defaultValue `undefined` **/
|
/** @defaultValue `undefined` **/
|
||||||
executablePath?: string
|
executablePath?: string
|
||||||
|
|
||||||
|
/** @defaultValue `undefined` **/
|
||||||
|
proxyServer?: string
|
||||||
}) {
|
}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
@ -65,7 +69,8 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI {
|
||||||
isGoogleLogin = false,
|
isGoogleLogin = false,
|
||||||
minimize = true,
|
minimize = true,
|
||||||
captchaToken,
|
captchaToken,
|
||||||
executablePath
|
executablePath,
|
||||||
|
proxyServer
|
||||||
} = opts
|
} = opts
|
||||||
|
|
||||||
this._email = email
|
this._email = email
|
||||||
|
@ -77,6 +82,7 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI {
|
||||||
this._minimize = !!minimize
|
this._minimize = !!minimize
|
||||||
this._captchaToken = captchaToken
|
this._captchaToken = captchaToken
|
||||||
this._executablePath = executablePath
|
this._executablePath = executablePath
|
||||||
|
this._proxyServer = proxyServer
|
||||||
|
|
||||||
if (!this._email) {
|
if (!this._email) {
|
||||||
const error = new types.ChatGPTError('ChatGPT invalid email')
|
const error = new types.ChatGPTError('ChatGPT invalid email')
|
||||||
|
@ -99,7 +105,8 @@ export class ChatGPTAPIBrowser extends AChatGPTAPI {
|
||||||
try {
|
try {
|
||||||
this._browser = await getBrowser({
|
this._browser = await getBrowser({
|
||||||
captchaToken: this._captchaToken,
|
captchaToken: this._captchaToken,
|
||||||
executablePath: this._executablePath
|
executablePath: this._executablePath,
|
||||||
|
proxyServer: this._proxyServer
|
||||||
})
|
})
|
||||||
this._page =
|
this._page =
|
||||||
(await this._browser.pages())[0] || (await this._browser.newPage())
|
(await this._browser.pages())[0] || (await this._browser.newPage())
|
||||||
|
|
|
@ -55,7 +55,8 @@ export async function getOpenAIAuth({
|
||||||
isGoogleLogin = false,
|
isGoogleLogin = false,
|
||||||
captchaToken = process.env.CAPTCHA_TOKEN,
|
captchaToken = process.env.CAPTCHA_TOKEN,
|
||||||
nopechaKey = process.env.NOPECHA_KEY,
|
nopechaKey = process.env.NOPECHA_KEY,
|
||||||
executablePath
|
executablePath,
|
||||||
|
proxyServer = process.env.PROXY_SERVER
|
||||||
}: {
|
}: {
|
||||||
email?: string
|
email?: string
|
||||||
password?: string
|
password?: string
|
||||||
|
@ -66,13 +67,19 @@ export async function getOpenAIAuth({
|
||||||
captchaToken?: string
|
captchaToken?: string
|
||||||
nopechaKey?: string
|
nopechaKey?: string
|
||||||
executablePath?: string
|
executablePath?: string
|
||||||
|
proxyServer?: string
|
||||||
}): Promise<OpenAIAuth> {
|
}): Promise<OpenAIAuth> {
|
||||||
const origBrowser = browser
|
const origBrowser = browser
|
||||||
const origPage = page
|
const origPage = page
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!browser) {
|
if (!browser) {
|
||||||
browser = await getBrowser({ captchaToken, nopechaKey, executablePath })
|
browser = await getBrowser({
|
||||||
|
captchaToken,
|
||||||
|
nopechaKey,
|
||||||
|
executablePath,
|
||||||
|
proxyServer
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const userAgent = await browser.userAgent()
|
const userAgent = await browser.userAgent()
|
||||||
|
@ -216,12 +223,14 @@ export async function getBrowser(
|
||||||
opts: PuppeteerLaunchOptions & {
|
opts: PuppeteerLaunchOptions & {
|
||||||
captchaToken?: string
|
captchaToken?: string
|
||||||
nopechaKey?: string
|
nopechaKey?: string
|
||||||
|
proxyServer?: string
|
||||||
} = {}
|
} = {}
|
||||||
) {
|
) {
|
||||||
const {
|
const {
|
||||||
captchaToken = process.env.CAPTCHA_TOKEN,
|
captchaToken = process.env.CAPTCHA_TOKEN,
|
||||||
nopechaKey = process.env.NOPECHA_KEY,
|
nopechaKey = process.env.NOPECHA_KEY,
|
||||||
executablePath = defaultChromeExecutablePath(),
|
executablePath = defaultChromeExecutablePath(),
|
||||||
|
proxyServer = process.env.PROXY_SERVER,
|
||||||
...launchOptions
|
...launchOptions
|
||||||
} = opts
|
} = opts
|
||||||
|
|
||||||
|
@ -274,6 +283,10 @@ export async function getBrowser(
|
||||||
hasNopechaExtension = true
|
hasNopechaExtension = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxyServer) {
|
||||||
|
puppeteerArgs.push(`--proxy-server=${proxyServer}`)
|
||||||
|
}
|
||||||
|
|
||||||
const browser = await puppeteer.launch({
|
const browser = await puppeteer.launch({
|
||||||
headless: false,
|
headless: false,
|
||||||
// https://peter.sh/experiments/chromium-command-line-switches/
|
// https://peter.sh/experiments/chromium-command-line-switches/
|
||||||
|
@ -288,6 +301,28 @@ export async function getBrowser(
|
||||||
...launchOptions
|
...launchOptions
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (process.env.PROXY_VALIDATE_IP) {
|
||||||
|
const page = (await browser.pages())[0] || (await browser.newPage())
|
||||||
|
// send a fetch request to https://ifconfig.co using page.evaluate() and verify the IP matches
|
||||||
|
let ip
|
||||||
|
try {
|
||||||
|
;({ ip } = await page.evaluate(() => {
|
||||||
|
return fetch('https://ifconfig.co', {
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json'
|
||||||
|
}
|
||||||
|
}).then((res) => res.json())
|
||||||
|
}))
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`Proxy IP validation failed: ${err.message}`)
|
||||||
|
}
|
||||||
|
if (ip !== process.env.PROXY_VALIDATE_IP) {
|
||||||
|
throw new Error(
|
||||||
|
`Proxy IP mismatch: ${ip} !== ${process.env.PROXY_VALIDATE_IP}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TOdO: this is a really hackity hack way of setting the API key...
|
// TOdO: this is a really hackity hack way of setting the API key...
|
||||||
if (hasNopechaExtension) {
|
if (hasNopechaExtension) {
|
||||||
const page = (await browser.pages())[0] || (await browser.newPage())
|
const page = (await browser.pages())[0] || (await browser.newPage())
|
||||||
|
|
Ładowanie…
Reference in New Issue