kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: fix capacity error
rodzic
61e9148805
commit
0385b8d7df
|
@ -40,7 +40,6 @@
|
|||
"expiry-map": "^2.0.0",
|
||||
"p-timeout": "^6.0.0",
|
||||
"puppeteer-extra": "^3.3.4",
|
||||
"puppeteer-extra-plugin-recaptcha": "^3.6.6",
|
||||
"puppeteer-extra-plugin-stealth": "^2.11.1",
|
||||
"remark": "^14.0.2",
|
||||
"strip-markdown": "^5.0.0",
|
||||
|
|
|
@ -18,7 +18,6 @@ specifiers:
|
|||
prettier: ^2.8.0
|
||||
puppeteer: ^19.4.0
|
||||
puppeteer-extra: ^3.3.4
|
||||
puppeteer-extra-plugin-recaptcha: ^3.6.6
|
||||
puppeteer-extra-plugin-stealth: ^2.11.1
|
||||
remark: ^14.0.2
|
||||
strip-markdown: ^5.0.0
|
||||
|
@ -35,7 +34,6 @@ dependencies:
|
|||
expiry-map: 2.0.0
|
||||
p-timeout: 6.0.0
|
||||
puppeteer-extra: 3.3.4_puppeteer@19.4.0
|
||||
puppeteer-extra-plugin-recaptcha: 3.6.6_puppeteer-extra@3.3.4
|
||||
puppeteer-extra-plugin-stealth: 2.11.1_puppeteer-extra@3.3.4
|
||||
remark: 14.0.2
|
||||
strip-markdown: 5.0.0
|
||||
|
@ -3067,26 +3065,6 @@ packages:
|
|||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
/puppeteer-extra-plugin-recaptcha/3.6.6_puppeteer-extra@3.3.4:
|
||||
resolution: {integrity: sha512-SVbmL+igGX8m0Qg9dn85trWDghbfUCTG/QUHYscYx5XgMZVVb0/v0a6MqbPdHoKmBx5BS2kLd6rorMlncMcXdw==}
|
||||
engines: {node: '>=9.11.2'}
|
||||
peerDependencies:
|
||||
playwright-extra: '*'
|
||||
puppeteer-extra: '*'
|
||||
peerDependenciesMeta:
|
||||
playwright-extra:
|
||||
optional: true
|
||||
puppeteer-extra:
|
||||
optional: true
|
||||
dependencies:
|
||||
debug: 4.3.4
|
||||
merge-deep: 3.0.3
|
||||
puppeteer-extra: 3.3.4_puppeteer@19.4.0
|
||||
puppeteer-extra-plugin: 3.2.2_puppeteer-extra@3.3.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/puppeteer-extra-plugin-stealth/2.11.1_puppeteer-extra@3.3.4:
|
||||
resolution: {integrity: sha512-n0wdC0Ilc9tk5L6FWLyd0P2gT8b2fp+2NuB+KB0oTSw3wXaZ0D6WNakjJsayJ4waGzIJFCUHkmK9zgx5NKMoFw==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
|
@ -3,5 +3,3 @@ export * from './chatgpt-conversation'
|
|||
export * from './types'
|
||||
export * from './utils'
|
||||
export * from './openai-auth'
|
||||
export * from './openai-auth-2captcha'
|
||||
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
import delay from 'delay'
|
||||
import {
|
||||
type Browser,
|
||||
type Page,
|
||||
type Protocol,
|
||||
type PuppeteerLaunchOptions
|
||||
} from 'puppeteer'
|
||||
import puppeteer from 'puppeteer-extra'
|
||||
import RecaptchaPlugin from 'puppeteer-extra-plugin-recaptcha'
|
||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||
|
||||
import { OpenAIAuth, getBrowser } from './openai-auth'
|
||||
|
||||
puppeteer.use(StealthPlugin())
|
||||
|
||||
/**
|
||||
* Bypasses OpenAI's use of Cloudflare to get the cookies required to use
|
||||
* ChatGPT. Uses Puppeteer with a stealth plugin under the hood.
|
||||
*
|
||||
* If you pass `email` and `password`, then it will log into the account and
|
||||
* include a `sessionToken` in the response.
|
||||
*
|
||||
* If you don't pass `email` and `password`, then it will just return a valid
|
||||
* `clearanceToken`.
|
||||
*
|
||||
* This can be useful because `clearanceToken` expires after ~2 hours, whereas
|
||||
* `sessionToken` generally lasts much longer. We recommend renewing your
|
||||
* `clearanceToken` every hour or so and creating a new instance of `ChatGPTAPI`
|
||||
* with your updated credentials.
|
||||
*/
|
||||
export async function getOpenAIAuth2Captcha({
|
||||
email,
|
||||
password,
|
||||
timeoutMs = 2 * 60 * 1000,
|
||||
browser,
|
||||
captchaToken
|
||||
}: {
|
||||
email?: string
|
||||
password?: string
|
||||
timeoutMs?: number
|
||||
browser?: Browser
|
||||
captchaToken?: string
|
||||
}): Promise<OpenAIAuth> {
|
||||
let page: Page
|
||||
let origBrowser = browser
|
||||
puppeteer.use(
|
||||
RecaptchaPlugin({
|
||||
provider: {
|
||||
id: '2captcha',
|
||||
token: captchaToken
|
||||
},
|
||||
visualFeedback: true // colorize reCAPTCHAs (violet = detected, green = solved)
|
||||
})
|
||||
)
|
||||
|
||||
try {
|
||||
if (!browser) {
|
||||
browser = await getBrowser()
|
||||
}
|
||||
|
||||
const userAgent = await browser.userAgent()
|
||||
page = (await browser.pages())[0] || (await browser.newPage())
|
||||
page.setDefaultTimeout(timeoutMs)
|
||||
|
||||
await page.goto('https://chat.openai.com/auth/login')
|
||||
|
||||
// NOTE: this is where you may encounter a CAPTCHA
|
||||
await page.solveRecaptchas()
|
||||
|
||||
var capacityLimit = await page.$('[role="alert"]')
|
||||
if (capacityLimit) {
|
||||
throw `ChatGPT is at capacity right now`
|
||||
}
|
||||
|
||||
await page.waitForSelector('#__next .btn-primary', { timeout: timeoutMs })
|
||||
|
||||
// once we get to this point, the Cloudflare cookies are available
|
||||
await delay(1000)
|
||||
|
||||
// login as well (optional)
|
||||
if (email && password) {
|
||||
await Promise.all([
|
||||
page.click('#__next .btn-primary'),
|
||||
page.waitForNavigation({
|
||||
waitUntil: 'networkidle0'
|
||||
})
|
||||
])
|
||||
await page.type('#username', email, { delay: 10 })
|
||||
await page.solveRecaptchas()
|
||||
await page.click('button[type="submit"]')
|
||||
await page.waitForSelector('#password')
|
||||
await page.type('#password', password, { delay: 10 })
|
||||
await Promise.all([
|
||||
page.click('button[type="submit"]'),
|
||||
page.waitForNavigation({
|
||||
waitUntil: 'networkidle0'
|
||||
})
|
||||
])
|
||||
}
|
||||
|
||||
const pageCookies = await page.cookies()
|
||||
const cookies = pageCookies.reduce(
|
||||
(map, cookie) => ({ ...map, [cookie.name]: cookie }),
|
||||
{}
|
||||
)
|
||||
|
||||
const authInfo: OpenAIAuth = {
|
||||
userAgent,
|
||||
clearanceToken: cookies['cf_clearance']?.value,
|
||||
sessionToken: cookies['__Secure-next-auth.session-token']?.value,
|
||||
cookies
|
||||
}
|
||||
|
||||
return authInfo
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
throw err
|
||||
} finally {
|
||||
if (origBrowser) {
|
||||
if (page) {
|
||||
await page.close()
|
||||
}
|
||||
} else if (browser) {
|
||||
await browser.close()
|
||||
}
|
||||
|
||||
page = null
|
||||
browser = null
|
||||
}
|
||||
}
|
|
@ -69,13 +69,8 @@ export async function getOpenAIAuth({
|
|||
|
||||
await page.goto('https://chat.openai.com/auth/login')
|
||||
|
||||
await checkForChatGPTAtCapacity(page)
|
||||
|
||||
// NOTE: this is where you may encounter a CAPTCHA
|
||||
var capacityLimit = await page.$('[role="alert"]')
|
||||
if (capacityLimit) {
|
||||
throw `ChatGPT is at capacity right now`
|
||||
}
|
||||
await checkForChatGPTAtCapacity(page)
|
||||
|
||||
await page.waitForSelector('#__next .btn-primary', { timeout: timeoutMs })
|
||||
|
||||
|
@ -231,15 +226,15 @@ export const defaultChromeExecutablePath = (): string => {
|
|||
}
|
||||
|
||||
async function checkForChatGPTAtCapacity(page: Page) {
|
||||
let res: ElementHandle<Element> | null
|
||||
let res: ElementHandle<Node>[]
|
||||
|
||||
try {
|
||||
res = await page.$('[role="alert"]')
|
||||
res = await page.$x("//div[contains(., 'ChatGPT is at capacity')]")
|
||||
} catch (err) {
|
||||
// ignore errors likely due to navigation
|
||||
}
|
||||
|
||||
if (res) {
|
||||
if (res?.length) {
|
||||
const error = new types.ChatGPTError(`ChatGPT is at capacity: ${res}`)
|
||||
error.statusCode = 503
|
||||
throw error
|
||||
|
|
Ładowanie…
Reference in New Issue