UNPKG

chatgpt-browser-api

Version:

Node.js client for the unofficial ChatGPT API.

601 lines (593 loc) 19.3 kB
import * as puppeteer from 'puppeteer'; import { Browser, Page, HTTPRequest, HTTPResponse, PuppeteerNodeLaunchOptions } from 'puppeteer'; type ContentType = 'text'; type Role = 'user' | 'assistant' | 'tool'; /** * https://chat.openapi.com/api/auth/session */ type SessionResult = { /** * Authenticated user */ user: User; /** * ISO date of the expiration date of the access token */ expires: string; /** * The access token */ accessToken: string; /** * If there was an error associated with this request */ error?: string | null; }; type User = { /** * ID of the user */ id: string; /** * Name of the user */ name: string; /** * Email of the user */ email?: string; /** * Image of the user */ image: string; /** * Picture of the user */ picture: string; /** * Groups the user is in */ groups: string[]; /** * Features the user is in */ features: string[]; }; /** * https://chat.openapi.com/backend-api/models */ type ModelsResult = { /** * Array of models */ models: Model[]; }; type Model = { /** * Name of the model */ slug: string; /** * Max tokens of the model */ max_tokens: number; /** * Whether or not the model is special */ is_special: boolean; }; /** * https://chat.openapi.com/backend-api/moderations */ type ModerationsJSONBody = { /** * Input for the moderation decision */ input: string; /** * The model to use in the decision */ model: AvailableModerationModels; }; type AvailableModerationModels = 'text-moderation-playground'; /** * https://chat.openapi.com/backend-api/moderations */ type ModerationsJSONResult = { /** * Whether or not the input is flagged */ flagged: boolean; /** * Whether or not the input is blocked */ blocked: boolean; /** * The ID of the decision */ moderation_id: string; }; /** * https://chat.openapi.com/backend-api/conversation */ type ConversationJSONBody = { /** * The action to take */ action: string; /** * The ID of the conversation */ conversation_id?: string; /** * Prompts to provide */ messages: Prompt[]; /** * The model to use */ model: string; /** * The parent message ID */ parent_message_id: string; timezone_offset_min?: number; suggestions?: []; history_and_training_disabled?: boolean; conversation_mode?: { kind: string; }; force_paragen?: boolean; force_paragen_model_slug?: string; force_nulligen?: boolean; force_rate_limit?: boolean; reset_rate_limits?: boolean; force_use_sse: boolean; websocket_request_id?: string; variant_purpose?: string; }; type Prompt = { /** * The content of the prompt */ content: PromptContent; metadata?: PromptMetaData; /** * The ID of the prompt */ id: string; /** * The role played in the prompt */ author: author; }; type author = { role: Role; }; type PromptContent = { /** * The content type of the prompt */ content_type: ContentType; /** * The parts to the prompt */ parts: string[]; }; type PromptMetaData = { attachments: { name: string; id: string; size?: number; mimeType: string; fileTokenSize?: number; }[]; }; /** * https://chat.openapi.com/backend-api/conversation/message_feedback */ type MessageFeedbackJSONBody = { /** * The ID of the conversation */ conversation_id: string; /** * The message ID */ message_id: string; /** * The rating */ rating: MessageFeedbackRating; /** * Tags to give the rating */ tags?: MessageFeedbackTags[]; /** * The text to include */ text?: string; }; type MessageFeedbackTags = 'harmful' | 'false' | 'not-helpful'; type MessageFeedbackResult = { /** * The message ID */ message_id: string; /** * The ID of the conversation */ conversation_id: string; /** * The ID of the user */ user_id: string; /** * The rating */ rating: MessageFeedbackRating; /** * The text the server received, including tags */ text?: string; }; type MessageFeedbackRating = 'thumbsUp' | 'thumbsDown'; type ConversationResponseEvent = { message?: Message; conversation_id?: string; error?: string | null; }; type Message = { id: string; content: MessageContent; author: author; role: string; user: string | null; create_time: string | null; update_time: string | null; end_turn: null; weight: number; recipient: string; metadata: MessageMetadata; }; type MessageContent = { content_type: string; parts: string[]; }; type MessageMetadata = any; type MessageActionType = 'next' | 'variant'; type SendMessages = { model: string; stream: boolean; frequency_penalty: number; presence_penalty: number; temperature: number; top_p: number; messages: Messages; }; type Messages = { content: string | content; role: string; }[]; type content = { type: string; text?: string; image_url?: FileUrl; }[]; type FileUrl = { url: string; detail?: string; }; type SendMessageOptions = { accessToken?: string; action?: MessageActionType; timeoutMs?: number; onProgress?: (partialResponse: ChatResponse) => void; abortSignal?: AbortSignal; }; type SendConversationMessageOptions = Omit<SendMessageOptions, 'conversationId' | 'parentMessageId'>; declare class ChatGPTError extends Error { statusCode?: number; statusText?: string; response?: Response; originalError?: Error; } type ChatError = { error: { message: string; statusCode?: number; statusText?: string; }; conversationId?: string; messageId?: string; }; type ChatResponse = { response: string; messageId: string; }; declare abstract class AChatGPTAPI { /** * Performs any async initialization work required to ensure that this API is * properly authenticated. * * @throws An error if the session failed to initialize properly. */ abstract initSession(): Promise<void>; /** * Sends a message to ChatGPT, waits for the response to resolve, and returns * the response. * * If you want to receive a stream of partial responses, use `opts.onProgress`. * * @param message - The prompt message to send * @param opts.conversationId - Optional ID of a conversation to continue * @param opts.parentMessageId - Optional ID of the previous message in the conversation * @param opts.messageId - Optional ID of the message to send (defaults to a random UUID) * @param opts.action - Optional ChatGPT `action` (either `next` or `variant`) * @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout) * @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated * @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) * * @returns The response from ChatGPT, including `conversationId`, `messageId`, and * the `response` text. */ abstract sendMessage(messages: SendMessages, opts?: SendMessageOptions): Promise<ChatResponse>; /** * @returns `true` if the client is authenticated with a valid session or `false` * otherwise. */ abstract getIsAuthenticated(): Promise<boolean>; /** * Refreshes the current ChatGPT session. * * Useful for bypassing 403 errors when Cloudflare clearance tokens expire. * * @returns Access credentials for the new session. * @throws An error if it fails. */ abstract refreshSession(): Promise<any>; /** * Closes the current ChatGPT session and starts a new one. * * Useful for bypassing 401 errors when sessions expire. * * @returns Access credentials for the new session. * @throws An error if it fails. */ resetSession(): Promise<any>; /** * Closes the active session. * * @throws An error if it fails. */ abstract closeSession(): Promise<void>; } declare class ChatGPTAPI extends AChatGPTAPI { getIsAuthenticated(): Promise<boolean>; refreshSession(): Promise<any>; protected _markdown: boolean; protected _debug: boolean; protected _apiBaseUrl: string; protected _backendApiBaseUrl: string; protected _headers: Record<string, string>; protected _browser: Browser; protected _page: Page; protected _minimize: boolean; protected _capsolverKey: string; protected _nopechaKey: string; protected _funObj: { pkey: string; bda: string; aev: string; userAgent: string; surl: string; }; protected _messageOnProgressHandlers: Record<string, (partialResponse: ChatResponse) => void>; /** * Creates a new client wrapper around the unofficial ChatGPT REST API. * * Note that your IP address and `userAgent` must match the same values that you used * to obtain your `clearanceToken`. * @param apiBaseUrl - Optional override; the base URL for ChatGPT webapp's API (`/api`) * @param backendApiBaseUrl - Optional override; the base URL for the ChatGPT backend API (`/backend-api`) * @param heaaders - Optional additional HTTP headers to be added to each `fetch` request * @param debug - Optional enables logging debugging into to stdout */ constructor(opts: { /** @defaultValue `true` **/ minimize?: boolean; /** @defaultValue `true` **/ markdown?: boolean; /** @defaultValue `'https://chat.openai.com/api'` **/ apiBaseUrl?: string; /** @defaultValue `'https://chat.openai.com/backend-api'` **/ backendApiBaseUrl?: string; /** @defaultValue `false` **/ debug?: boolean; /** @defaultValue `capsolverKey` **/ capsolverKey?: string; nopechaKey?: string; }); /** * Refreshes the client's access token which will succeed only if the session * is valid. */ initSession(): Promise<void>; /** * Sends a message to ChatGPT, waits for the response to resolve, and returns * the response. * * If you want to receive a stream of partial responses, use `opts.onProgress`. * If you want to receive the full response, including message and conversation IDs, * you can use `opts.onConversationResponse` or use the `ChatGPTAPI.getConversation` * helper. * * @param message - The prompt message to send * @param opts.conversationId - Optional ID of a conversation to continue * @param opts.parentMessageId - Optional ID of the previous message in the conversation * @param opts.messageId - Optional ID of the message to send (defaults to a random UUID) * @param opts.action - Optional ChatGPT `action` (either `next` or `variant`) * @param opts.timeoutMs - Optional timeout in milliseconds (defaults to no timeout) * @param opts.onProgress - Optional callback which will be invoked every time the partial response is updated * @param opts.abortSignal - Optional callback used to abort the underlying `fetch` call using an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) * * @returns The response from ChatGPT */ sendMessage(messages: SendMessages, opts: SendMessageOptions): Promise<ChatResponse>; closeSession(): Promise<void>; } declare class ChatGPTAPIBrowser extends AChatGPTAPI { protected _markdown: boolean; protected _debug: boolean; protected _minimize: boolean; protected _isGoogleLogin: boolean; protected _isMicrosoftLogin: boolean; protected _nopechaKey: string; protected _capsolverKey: string; protected _accessToken: string; protected _email: string; protected _password: string; protected _isProAccount: boolean; protected _executablePath: string; protected _browser: Browser; protected _page: Page; protected _proxyServer: string; protected _isRefreshing: boolean; protected _messageOnProgressHandlers: Record<string, (partialResponse: ChatResponse) => void>; protected _userDataDir: string; protected _funObj: { pkey: string; bda: string; aev: string; userAgent: string; surl: string; }; /** * Creates a new client for automating the ChatGPT webapp. */ constructor(opts: { email?: string; password?: string; /** @defaultValue `false` **/ isProAccount?: boolean; /** @defaultValue `true` **/ markdown?: boolean; /** @defaultValue `false` **/ debug?: boolean; /** @defaultValue `false` **/ isGoogleLogin?: boolean; /** @defaultValue `false` **/ isMicrosoftLogin?: boolean; /** @defaultValue `true` **/ minimize?: boolean; /** @defaultValue `undefined` **/ nopechaKey?: string; /** @defaultValue `undefined` **/ capsolverKey?: string; /** @defaultValue `undefined` **/ executablePath?: string; /** @defaultValue `undefined` **/ proxyServer?: string; /** @defaultValue `random directory with email as prefix` **/ userDataDir?: string; }); initSession(): Promise<void>; _onRequest: (request: HTTPRequest) => void; _onResponse: (response: HTTPResponse) => Promise<void>; /** * Attempts to handle 401 errors by re-authenticating. */ resetSession(): Promise<void>; /** * Attempts to handle 403 errors by refreshing the page. */ refreshSession(): Promise<void>; getIsAuthenticated(): Promise<boolean>; sendMessage(messages: SendMessages, opts: SendMessageOptions): Promise<ChatResponse>; resetThread(): Promise<void>; closeSession(): Promise<void>; protected _getInputBox(): Promise<puppeteer.ElementHandle<Element>>; get isChatPage(): boolean; } declare global { function ChatGPTAPIBrowserOnProgress(partialChatResponse: ChatResponse): Promise<void>; } declare function markdownToText(markdown?: string): string; declare function minimizePage(page: Page): Promise<void>; declare function deleteFolderRecursive(path: string): Promise<void>; declare function maximizePage(page: Page): Promise<void>; declare function isRelevantRequest(url: string): boolean; declare function getAccessToken(): Promise<any>; declare function getRequirementToken(token: string, accessToken?: string): Promise<any>; declare function getWssUrl(accessToken: string): Promise<any>; declare function getGptMessages(messages: string | content, accessToken: string): Promise<{ parts: any[]; attachments: any; }>; /** * This function is injected into the ChatGPT webapp page using puppeteer. It * has to be fully self-contained, so we copied a few third-party sources and * included them in here. */ declare function browserPostEventStream(url: string, accessToken: string, body: ConversationJSONBody, requirement: any, powToken: string, wssUrl?: string, arkoseToken?: string, timeoutMs?: number): Promise<ChatError | ChatResponse>; /** * Represents everything that's required to pass into `ChatGPTAPI` in order * to authenticate with the unofficial ChatGPT API. */ type OpenAIAuth = { userAgent: string; accessToken: string; clearanceToken: string; sessionToken: string; }; /** * 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. */ declare function getOpenAIAuth({ email, password, browser, page, timeoutMs, isGoogleLogin, isMicrosoftLogin, nopechaKey, capsolverKey, executablePath, proxyServer, minimize }: { email?: string; password?: string; browser?: Browser; page?: Page; timeoutMs?: number; isGoogleLogin?: boolean; isMicrosoftLogin?: boolean; minimize?: boolean; nopechaKey?: string; capsolverKey?: string; executablePath?: string; proxyServer?: string; }): Promise<OpenAIAuth>; declare function getPage(browser: Browser, opts: { proxyServer?: string; }): Promise<Page>; /** * Launches a non-puppeteer instance of Chrome. Note that in my testing, I wasn't * able to use the built-in `puppeteer` version of Chromium because Cloudflare * recognizes it and blocks access. */ declare function getBrowser(opts?: PuppeteerNodeLaunchOptions & { nopechaKey?: string; capsolverKey?: string; proxyServer?: string; minimize?: boolean; debug?: boolean; timeoutMs?: number; }): Promise<Browser>; /** * Gets the default path to chrome's executable for the current platform. */ declare const defaultChromeExecutablePath: () => string; declare function solveSimpleCaptchas(page: Page): Promise<void>; export { AChatGPTAPI, AvailableModerationModels, ChatError, ChatGPTAPI, ChatGPTAPIBrowser, ChatGPTError, ChatResponse, ContentType, ConversationJSONBody, ConversationResponseEvent, FileUrl, Message, MessageActionType, MessageContent, MessageFeedbackJSONBody, MessageFeedbackRating, MessageFeedbackResult, MessageFeedbackTags, MessageMetadata, Messages, Model, ModelsResult, ModerationsJSONBody, ModerationsJSONResult, OpenAIAuth, Prompt, PromptContent, PromptMetaData, Role, SendConversationMessageOptions, SendMessageOptions, SendMessages, SessionResult, User, author, browserPostEventStream, content, defaultChromeExecutablePath, deleteFolderRecursive, getAccessToken, getBrowser, getGptMessages, getOpenAIAuth, getPage, getRequirementToken, getWssUrl, isRelevantRequest, markdownToText, maximizePage, minimizePage, solveSimpleCaptchas };