kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/134/head
rodzic
bbd157d377
commit
38118a4a6e
|
@ -1,8 +1,10 @@
|
||||||
import * as fs from 'fs'
|
import fs from 'node:fs'
|
||||||
import * as os from 'os'
|
import os from 'node:os'
|
||||||
|
|
||||||
import delay from 'delay'
|
import delay from 'delay'
|
||||||
import {
|
import {
|
||||||
type Browser,
|
type Browser,
|
||||||
|
type ElementHandle,
|
||||||
type Page,
|
type Page,
|
||||||
type Protocol,
|
type Protocol,
|
||||||
type PuppeteerLaunchOptions
|
type PuppeteerLaunchOptions
|
||||||
|
@ -10,6 +12,8 @@ import {
|
||||||
import puppeteer from 'puppeteer-extra'
|
import puppeteer from 'puppeteer-extra'
|
||||||
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
import StealthPlugin from 'puppeteer-extra-plugin-stealth'
|
||||||
|
|
||||||
|
import * as types from './types'
|
||||||
|
|
||||||
puppeteer.use(StealthPlugin())
|
puppeteer.use(StealthPlugin())
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,14 +45,14 @@ export type OpenAIAuth = {
|
||||||
export async function getOpenAIAuth({
|
export async function getOpenAIAuth({
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
timeoutMs = 2 * 60 * 1000,
|
|
||||||
browser,
|
browser,
|
||||||
isGoogleLogin
|
timeoutMs = 2 * 60 * 1000,
|
||||||
|
isGoogleLogin = false
|
||||||
}: {
|
}: {
|
||||||
email?: string
|
email?: string
|
||||||
password?: string
|
password?: string
|
||||||
timeoutMs?: number
|
|
||||||
browser?: Browser
|
browser?: Browser
|
||||||
|
timeoutMs?: number
|
||||||
isGoogleLogin?: boolean
|
isGoogleLogin?: boolean
|
||||||
}): Promise<OpenAIAuth> {
|
}): Promise<OpenAIAuth> {
|
||||||
let page: Page
|
let page: Page
|
||||||
|
@ -65,6 +69,8 @@ export async function getOpenAIAuth({
|
||||||
|
|
||||||
await page.goto('https://chat.openai.com/auth/login')
|
await page.goto('https://chat.openai.com/auth/login')
|
||||||
|
|
||||||
|
await checkForChatGPTAtCapacity(page)
|
||||||
|
|
||||||
// NOTE: this is where you may encounter a CAPTCHA
|
// NOTE: this is where you may encounter a CAPTCHA
|
||||||
|
|
||||||
await page.waitForSelector('#__next .btn-primary', { timeout: timeoutMs })
|
await page.waitForSelector('#__next .btn-primary', { timeout: timeoutMs })
|
||||||
|
@ -80,6 +86,9 @@ export async function getOpenAIAuth({
|
||||||
waitUntil: 'networkidle0'
|
waitUntil: 'networkidle0'
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
|
||||||
|
let submitP: Promise<void>
|
||||||
|
|
||||||
if (isGoogleLogin) {
|
if (isGoogleLogin) {
|
||||||
await page.click('button[data-provider="google"]')
|
await page.click('button[data-provider="google"]')
|
||||||
await page.waitForSelector('input[type="email"]')
|
await page.waitForSelector('input[type="email"]')
|
||||||
|
@ -90,24 +99,61 @@ export async function getOpenAIAuth({
|
||||||
])
|
])
|
||||||
await page.waitForSelector('input[type="password"]', { visible: true })
|
await page.waitForSelector('input[type="password"]', { visible: true })
|
||||||
await page.type('input[type="password"]', password, { delay: 10 })
|
await page.type('input[type="password"]', password, { delay: 10 })
|
||||||
await page.keyboard.press('Enter')
|
submitP = page.keyboard.press('Enter')
|
||||||
await Promise.all([
|
|
||||||
page.waitForNavigation({
|
|
||||||
waitUntil: 'networkidle0'
|
|
||||||
})
|
|
||||||
])
|
|
||||||
} else {
|
} else {
|
||||||
|
await page.waitForSelector('#username')
|
||||||
await page.type('#username', email, { delay: 10 })
|
await page.type('#username', email, { delay: 10 })
|
||||||
await page.click('button[type="submit"]')
|
await page.click('button[type="submit"]')
|
||||||
await page.waitForSelector('#password')
|
await page.waitForSelector('#password')
|
||||||
await page.type('#password', password, { delay: 10 })
|
await page.type('#password', password, { delay: 10 })
|
||||||
|
submitP = page.click('button[type="submit"]')
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.click('button[type="submit"]'),
|
submitP,
|
||||||
page.waitForNavigation({
|
|
||||||
|
new Promise<void>((resolve, reject) => {
|
||||||
|
let resolved = false
|
||||||
|
|
||||||
|
async function waitForCapacityText() {
|
||||||
|
if (resolved) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await checkForChatGPTAtCapacity(page)
|
||||||
|
|
||||||
|
if (!resolved) {
|
||||||
|
setTimeout(waitForCapacityText, 500)
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
if (!resolved) {
|
||||||
|
resolved = true
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
page
|
||||||
|
.waitForNavigation({
|
||||||
waitUntil: 'networkidle0'
|
waitUntil: 'networkidle0'
|
||||||
})
|
})
|
||||||
])
|
.then(() => {
|
||||||
|
if (!resolved) {
|
||||||
|
resolved = true
|
||||||
|
resolve()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
if (!resolved) {
|
||||||
|
resolved = true
|
||||||
|
reject(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(waitForCapacityText, 500)
|
||||||
|
})
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageCookies = await page.cookies()
|
const pageCookies = await page.cookies()
|
||||||
|
@ -151,20 +197,22 @@ export async function getBrowser(launchOptions?: PuppeteerLaunchOptions) {
|
||||||
headless: false,
|
headless: false,
|
||||||
args: ['--no-sandbox', '--exclude-switches', 'enable-automation'],
|
args: ['--no-sandbox', '--exclude-switches', 'enable-automation'],
|
||||||
ignoreHTTPSErrors: true,
|
ignoreHTTPSErrors: true,
|
||||||
executablePath: executablePath(),
|
executablePath: defaultChromeExecutablePath(),
|
||||||
...launchOptions
|
...launchOptions
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the correct path to chrome's executable
|
* Gets the default path to chrome's executable for the current platform.
|
||||||
*/
|
*/
|
||||||
const executablePath = (): string => {
|
export const defaultChromeExecutablePath = (): string => {
|
||||||
switch (os.platform()) {
|
switch (os.platform()) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
return 'C:\\ProgramFiles\\Google\\Chrome\\Application\\chrome.exe'
|
return 'C:\\ProgramFiles\\Google\\Chrome\\Application\\chrome.exe'
|
||||||
|
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
|
return '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/**
|
/**
|
||||||
* Since two (2) separate chrome releases exists on linux
|
* Since two (2) separate chrome releases exists on linux
|
||||||
|
@ -177,3 +225,21 @@ const executablePath = (): string => {
|
||||||
: '/usr/bin/google-chrome-stable'
|
: '/usr/bin/google-chrome-stable'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function checkForChatGPTAtCapacity(page: Page) {
|
||||||
|
let res: ElementHandle<Node>[]
|
||||||
|
|
||||||
|
try {
|
||||||
|
res = await page.$x("//div[contains(., 'ChatGPT is at capacity')]")
|
||||||
|
console.log('capacity text', res)
|
||||||
|
} catch (err) {
|
||||||
|
// ignore errors likely due to navigation
|
||||||
|
console.warn(err.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res?.length) {
|
||||||
|
const error = new types.ChatGPTError('ChatGPT is at capacity')
|
||||||
|
error.statusCode = 503
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue