From 5fc2a8883a4baf56023421a0b8c3bd7d5a0e1ec7 Mon Sep 17 00:00:00 2001 From: Travis Fischer Date: Thu, 15 Dec 2022 00:22:31 -0600 Subject: [PATCH] feat: more WIP.. --- legacy/demos/demo.ts | 2 +- legacy/src/chatgpt-api-browser.ts | 105 +++++++++++++++++++++++++----- legacy/src/openai-auth.ts | 12 ++-- legacy/src/utils.ts | 47 +++++++++++++ 4 files changed, 142 insertions(+), 24 deletions(-) diff --git a/legacy/demos/demo.ts b/legacy/demos/demo.ts index 0c18173e..bdd59dbe 100644 --- a/legacy/demos/demo.ts +++ b/legacy/demos/demo.ts @@ -16,7 +16,7 @@ async function main() { const email = process.env.OPENAI_EMAIL 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() console.log('init result', res) diff --git a/legacy/src/chatgpt-api-browser.ts b/legacy/src/chatgpt-api-browser.ts index 377bf7ac..f88b95ca 100644 --- a/legacy/src/chatgpt-api-browser.ts +++ b/legacy/src/chatgpt-api-browser.ts @@ -1,9 +1,10 @@ import delay from 'delay' 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 { getBrowser, getOpenAIAuth } from './openai-auth' +import { isRelevantRequest, minimizePage } from './utils' export class ChatGPTAPIBrowser { protected _markdown: boolean @@ -102,25 +103,93 @@ export class ChatGPTAPIBrowser { 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 } - // _onResponse = (response: HTTPResponse) => { - // const request = response.request() + _onRequest = (request: HTTPRequest) => { + if (!this._debug) return - // console.log('response', { - // url: response.url(), - // ok: response.ok(), - // status: response.status(), - // statusText: response.statusText(), - // headers: response.headers(), - // request: { - // method: request.method(), - // headers: request.headers() - // } - // }) - // } + const url = request.url() + if (!isRelevantRequest(url)) { + return + } + + const method = request.method() + let body: any + + 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() { try { @@ -198,7 +267,8 @@ export class ChatGPTAPIBrowser { const lastMessage = await this.getLastMessage() - await inputBox.click() + message = message.replace('\n', '\t') + await inputBox.focus() await inputBox.type(message, { delay: 0 }) await inputBox.press('Enter') @@ -211,6 +281,7 @@ export class ChatGPTAPIBrowser { newLastMessage && lastMessage?.toLowerCase() !== newLastMessage?.toLowerCase() ) { + await delay(5000) return newLastMessage } } while (true) diff --git a/legacy/src/openai-auth.ts b/legacy/src/openai-auth.ts index 7ece9b05..1006d55d 100644 --- a/legacy/src/openai-auth.ts +++ b/legacy/src/openai-auth.ts @@ -2,12 +2,12 @@ import * as fs from 'node:fs' import * as os from 'node:os' import delay from 'delay' -import { - type Browser, - type ElementHandle, - type Page, - type Protocol, - type PuppeteerLaunchOptions +import type { + Browser, + ElementHandle, + Page, + Protocol, + PuppeteerLaunchOptions } from 'puppeteer' import puppeteer from 'puppeteer-extra' import RecaptchaPlugin from 'puppeteer-extra-plugin-recaptcha' diff --git a/legacy/src/utils.ts b/legacy/src/utils.ts index 724f3b2a..bb650ce7 100644 --- a/legacy/src/utils.ts +++ b/legacy/src/utils.ts @@ -1,3 +1,4 @@ +import type { Page } from 'puppeteer' import { remark } from 'remark' import stripMarkdown from 'strip-markdown' @@ -7,3 +8,49 @@ export function markdownToText(markdown?: string): string { .processSync(markdown ?? '') .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 +}