Commit b8a3fe0d authored by Joel's avatar Joel Committed by GitHub

Merge branch 'feature/improve-robustness' into feature/improve-robustness

parents 16d144ad 7ddac692
...@@ -16,7 +16,7 @@ async function main() { ...@@ -16,7 +16,7 @@ async function main() {
const email = process.env.OPENAI_EMAIL const email = process.env.OPENAI_EMAIL
const password = process.env.OPENAI_PASSWORD const password = process.env.OPENAI_PASSWORD
const api = new ChatGPTAPIBrowser({ email, password }) const api = new ChatGPTAPIBrowser({ email, password, debug: true })
const res = await api.init() const res = await api.init()
console.log('init result', res) console.log('init result', res)
......
import delay from 'delay' import delay from 'delay'
import html2md from 'html-to-md' import html2md from 'html-to-md'
import { type Browser, type HTTPResponse, type Page } from 'puppeteer' import type { Browser, HTTPRequest, HTTPResponse, Page } from 'puppeteer'
import * as types from './types' import * as types from './types'
import { getBrowser, getOpenAIAuth } from './openai-auth' import { getBrowser, getOpenAIAuth } from './openai-auth'
import { isRelevantRequest, minimizePage } from './utils'
export class ChatGPTAPIBrowser { export class ChatGPTAPIBrowser {
protected _markdown: boolean protected _markdown: boolean
...@@ -102,25 +103,93 @@ export class ChatGPTAPIBrowser { ...@@ -102,25 +103,93 @@ export class ChatGPTAPIBrowser {
return false return false
} }
// this._page.on('response', this._onResponse.bind(this)) // await minimizePage(this._page)
this._page.on('request', this._onRequest.bind(this))
this._page.on('response', this._onResponse.bind(this))
return true return true
} }
// _onResponse = (response: HTTPResponse) => { _onRequest = (request: HTTPRequest) => {
// const request = response.request() if (!this._debug) return
// console.log('response', { const url = request.url()
// url: response.url(), if (!isRelevantRequest(url)) {
// ok: response.ok(), return
// status: response.status(), }
// statusText: response.statusText(),
// headers: response.headers(), const method = request.method()
// request: { let body: any
// method: request.method(),
// headers: request.headers() if (method === 'POST') {
// } body = request.postData()
// })
// } try {
body = JSON.parse(body)
} catch (_) {}
// if (url.endsWith('/conversation') && typeof body === 'object') {
// const conversationBody: types.ConversationJSONBody = body
// const conversationId = conversationBody.conversation_id
// const parentMessageId = conversationBody.parent_message_id
// const messageId = conversationBody.messages?.[0]?.id
// const prompt = conversationBody.messages?.[0]?.content?.parts?.[0]
// // TODO: store this info for the current sendMessage request
// }
}
console.log('\nrequest', {
url,
method,
headers: request.headers(),
body
})
}
_onResponse = async (response: HTTPResponse) => {
if (!this._debug) return
const request = response.request()
const url = response.url()
if (!isRelevantRequest(url)) {
return
}
let body: any
try {
body = await response.json()
} catch (_) {}
if (url.endsWith('/conversation')) {
// const parser = createParser((event) => {
// if (event.type === 'event') {
// onMessage(event.data)
// }
// })
// await response.buffer()
// for await (const chunk of streamAsyncIterable(response.body)) {
// const str = new TextDecoder().decode(chunk)
// parser.feed(str)
// }
}
console.log('\nresponse', {
url,
ok: response.ok(),
status: response.status(),
statusText: response.statusText(),
headers: response.headers(),
body,
request: {
method: request.method(),
headers: request.headers(),
body: request.postData()
}
})
}
async getIsAuthenticated() { async getIsAuthenticated() {
try { try {
...@@ -198,7 +267,7 @@ export class ChatGPTAPIBrowser { ...@@ -198,7 +267,7 @@ export class ChatGPTAPIBrowser {
const lastMessage = await this.getLastMessage() const lastMessage = await this.getLastMessage()
await inputBox.click() await inputBox.focus()
const paragraphs = message.split('\n') const paragraphs = message.split('\n')
for (let i = 0; i < paragraphs.length; i++) { for (let i = 0; i < paragraphs.length; i++) {
await inputBox.type(paragraphs[i], { delay: 0 }) await inputBox.type(paragraphs[i], { delay: 0 })
...@@ -220,6 +289,7 @@ export class ChatGPTAPIBrowser { ...@@ -220,6 +289,7 @@ export class ChatGPTAPIBrowser {
newLastMessage && newLastMessage &&
lastMessage?.toLowerCase() !== newLastMessage?.toLowerCase() lastMessage?.toLowerCase() !== newLastMessage?.toLowerCase()
) { ) {
await delay(5000)
return newLastMessage return newLastMessage
} }
} while (true) } while (true)
......
...@@ -2,12 +2,12 @@ import * as fs from 'node:fs' ...@@ -2,12 +2,12 @@ import * as fs from 'node:fs'
import * as os from 'node:os' import * as os from 'node:os'
import delay from 'delay' import delay from 'delay'
import { import type {
type Browser, Browser,
type ElementHandle, ElementHandle,
type Page, Page,
type Protocol, Protocol,
type PuppeteerLaunchOptions PuppeteerLaunchOptions
} from 'puppeteer' } from 'puppeteer'
import puppeteer from 'puppeteer-extra' import puppeteer from 'puppeteer-extra'
import RecaptchaPlugin from 'puppeteer-extra-plugin-recaptcha' import RecaptchaPlugin from 'puppeteer-extra-plugin-recaptcha'
......
import type { Page } from 'puppeteer'
import { remark } from 'remark' import { remark } from 'remark'
import stripMarkdown from 'strip-markdown' import stripMarkdown from 'strip-markdown'
...@@ -7,3 +8,49 @@ export function markdownToText(markdown?: string): string { ...@@ -7,3 +8,49 @@ export function markdownToText(markdown?: string): string {
.processSync(markdown ?? '') .processSync(markdown ?? '')
.toString() .toString()
} }
export async function minimizePage(page: Page) {
const session = await page.target().createCDPSession()
const goods = await session.send('Browser.getWindowForTarget')
const { windowId } = goods
await session.send('Browser.setWindowBounds', {
windowId,
bounds: { windowState: 'minimized' }
})
}
export async function maximizePage(page: Page) {
const session = await page.target().createCDPSession()
const goods = await session.send('Browser.getWindowForTarget')
const { windowId } = goods
await session.send('Browser.setWindowBounds', {
windowId,
bounds: { windowState: 'normal' }
})
}
export function isRelevantRequest(url: string): boolean {
let pathname
try {
const parsedUrl = new URL(url)
pathname = parsedUrl.pathname
url = parsedUrl.toString()
} catch (_) {
return false
}
if (!url.startsWith('https://chat.openai.com')) {
return false
}
if (pathname.startsWith('/_next')) {
return false
}
if (pathname.endsWith('backend-api/moderations')) {
return false
}
return true
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment