kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add additional options to better control debugging; add some inline docs
rodzic
93663efbe9
commit
e158146aab
|
@ -16,27 +16,32 @@ export class ChatGPTAPI {
|
||||||
protected _sessionToken: string
|
protected _sessionToken: string
|
||||||
protected _clearanceToken: string
|
protected _clearanceToken: string
|
||||||
protected _markdown: boolean
|
protected _markdown: boolean
|
||||||
|
protected _debug: boolean
|
||||||
protected _apiBaseUrl: string
|
protected _apiBaseUrl: string
|
||||||
protected _backendApiBaseUrl: string
|
protected _backendApiBaseUrl: string
|
||||||
protected _userAgent: string
|
protected _userAgent: string
|
||||||
protected _headers: Record<string, string>
|
protected _headers: Record<string, string>
|
||||||
|
protected _user: types.User | null = null
|
||||||
|
|
||||||
// Stores access tokens for `accessTokenTTL` milliseconds before needing to refresh
|
// Stores access tokens for `accessTokenTTL` milliseconds before needing to refresh
|
||||||
protected _accessTokenCache: ExpiryMap<string, string>
|
protected _accessTokenCache: ExpiryMap<string, string>
|
||||||
|
|
||||||
protected _user: types.User | null = null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new client wrapper around the unofficial ChatGPT REST API.
|
* Creates a new client wrapper around the unofficial ChatGPT REST API.
|
||||||
*
|
*
|
||||||
* @param opts.sessionToken = **Required** OpenAI session token which can be found in a valid session's cookies (see readme for instructions)
|
* @param opts.sessionToken = **Required** OpenAI session token which can be found in a valid session's cookies (see readme for instructions)
|
||||||
|
* @param opts.clearanceToken = **Required** Cloudflare `cf_clearance` cookie value (see readme for instructions)
|
||||||
* @param apiBaseUrl - Optional override; the base URL for ChatGPT webapp's API (`/api`)
|
* @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 backendApiBaseUrl - Optional override; the base URL for the ChatGPT backend API (`/backend-api`)
|
||||||
* @param userAgent - Optional override; the `user-agent` header to use with ChatGPT requests
|
* @param userAgent - Optional override; the `user-agent` header to use with ChatGPT requests
|
||||||
* @param accessTokenTTL - Optional override; how long in milliseconds access tokens should last before being forcefully refreshed
|
* @param accessTokenTTL - Optional override; how long in milliseconds access tokens should last before being forcefully refreshed
|
||||||
|
* @param accessToken - Optional default access token if you already have a valid one generated
|
||||||
|
* @param heaaders - Optional additional HTTP headers to be added to each `fetch` request
|
||||||
|
* @param debug - Optional enables logging debugging into to stdout
|
||||||
*/
|
*/
|
||||||
constructor(opts: {
|
constructor(opts: {
|
||||||
sessionToken: string
|
sessionToken: string
|
||||||
|
|
||||||
clearanceToken: string
|
clearanceToken: string
|
||||||
|
|
||||||
/** @defaultValue `true` **/
|
/** @defaultValue `true` **/
|
||||||
|
@ -48,15 +53,20 @@ export class ChatGPTAPI {
|
||||||
/** @defaultValue `'https://chat.openai.com/backend-api'` **/
|
/** @defaultValue `'https://chat.openai.com/backend-api'` **/
|
||||||
backendApiBaseUrl?: string
|
backendApiBaseUrl?: string
|
||||||
|
|
||||||
/** @defaultValue `'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'` **/
|
/** @defaultValue `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'` **/
|
||||||
userAgent?: string
|
userAgent?: string
|
||||||
|
|
||||||
/** @defaultValue 1 hour */
|
/** @defaultValue 1 hour **/
|
||||||
accessTokenTTL?: number
|
accessTokenTTL?: number
|
||||||
|
|
||||||
|
/** @defaultValue `undefined` **/
|
||||||
accessToken?: string
|
accessToken?: string
|
||||||
|
|
||||||
|
/** @defaultValue `undefined` **/
|
||||||
headers?: Record<string, string>
|
headers?: Record<string, string>
|
||||||
|
|
||||||
|
/** @defaultValue `false` **/
|
||||||
|
debug?: boolean
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
sessionToken,
|
sessionToken,
|
||||||
|
@ -67,12 +77,14 @@ export class ChatGPTAPI {
|
||||||
userAgent = USER_AGENT,
|
userAgent = USER_AGENT,
|
||||||
accessTokenTTL = 60 * 60000, // 1 hour
|
accessTokenTTL = 60 * 60000, // 1 hour
|
||||||
accessToken,
|
accessToken,
|
||||||
headers
|
headers,
|
||||||
|
debug = false
|
||||||
} = opts
|
} = opts
|
||||||
|
|
||||||
this._sessionToken = sessionToken
|
this._sessionToken = sessionToken
|
||||||
this._clearanceToken = clearanceToken
|
this._clearanceToken = clearanceToken
|
||||||
this._markdown = !!markdown
|
this._markdown = !!markdown
|
||||||
|
this._debug = !!debug
|
||||||
this._apiBaseUrl = apiBaseUrl
|
this._apiBaseUrl = apiBaseUrl
|
||||||
this._backendApiBaseUrl = backendApiBaseUrl
|
this._backendApiBaseUrl = backendApiBaseUrl
|
||||||
this._userAgent = userAgent
|
this._userAgent = userAgent
|
||||||
|
@ -124,6 +136,8 @@ export class ChatGPTAPI {
|
||||||
* @param message - The prompt message to send
|
* @param message - The prompt message to send
|
||||||
* @param opts.conversationId - Optional ID of a conversation to continue
|
* @param opts.conversationId - Optional ID of a conversation to continue
|
||||||
* @param opts.parentMessageId - Optional ID of the previous message in the conversation
|
* @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.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.onProgress - Optional callback which will be invoked every time the partial response is updated
|
||||||
* @param opts.onConversationResponse - Optional callback which will be invoked every time the partial response is updated with the full conversation response
|
* @param opts.onConversationResponse - Optional callback which will be invoked every time the partial response is updated with the full conversation response
|
||||||
|
@ -138,6 +152,8 @@ export class ChatGPTAPI {
|
||||||
const {
|
const {
|
||||||
conversationId,
|
conversationId,
|
||||||
parentMessageId = uuidv4(),
|
parentMessageId = uuidv4(),
|
||||||
|
messageId = uuidv4(),
|
||||||
|
action = 'next',
|
||||||
timeoutMs,
|
timeoutMs,
|
||||||
onProgress,
|
onProgress,
|
||||||
onConversationResponse
|
onConversationResponse
|
||||||
|
@ -154,10 +170,10 @@ export class ChatGPTAPI {
|
||||||
const accessToken = await this.refreshAccessToken()
|
const accessToken = await this.refreshAccessToken()
|
||||||
|
|
||||||
const body: types.ConversationJSONBody = {
|
const body: types.ConversationJSONBody = {
|
||||||
action: 'next',
|
action,
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
id: uuidv4(),
|
id: messageId,
|
||||||
role: 'user',
|
role: 'user',
|
||||||
content: {
|
content: {
|
||||||
content_type: 'text',
|
content_type: 'text',
|
||||||
|
@ -173,19 +189,25 @@ export class ChatGPTAPI {
|
||||||
body.conversation_id = conversationId
|
body.conversation_id = conversationId
|
||||||
}
|
}
|
||||||
|
|
||||||
const url = `${this._backendApiBaseUrl}/conversation`
|
|
||||||
let response = ''
|
let response = ''
|
||||||
|
|
||||||
const responseP = new Promise<string>((resolve, reject) => {
|
const responseP = new Promise<string>((resolve, reject) => {
|
||||||
|
const url = `${this._backendApiBaseUrl}/conversation`
|
||||||
|
const headers = {
|
||||||
|
...this._headers,
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
Accept: 'text/event-stream',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Cookie: `cf_clearance=${this._clearanceToken}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._debug) {
|
||||||
|
console.log('POST', url, { body, headers })
|
||||||
|
}
|
||||||
|
|
||||||
fetchSSE(url, {
|
fetchSSE(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers,
|
||||||
...this._headers,
|
|
||||||
Authorization: `Bearer ${accessToken}`,
|
|
||||||
Accept: 'text/event-stream',
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Cookie: `cf_clearance=${this._clearanceToken}`
|
|
||||||
},
|
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
signal: abortSignal,
|
signal: abortSignal,
|
||||||
onMessage: (data: string) => {
|
onMessage: (data: string) => {
|
||||||
|
@ -282,14 +304,18 @@ export class ChatGPTAPI {
|
||||||
|
|
||||||
let response: Response
|
let response: Response
|
||||||
try {
|
try {
|
||||||
|
const url = `${this._apiBaseUrl}/auth/session`
|
||||||
const headers = {
|
const headers = {
|
||||||
...this._headers,
|
...this._headers,
|
||||||
cookie: `cf_clearance=${this._clearanceToken}; __Secure-next-auth.session-token=${this._sessionToken}`,
|
cookie: `cf_clearance=${this._clearanceToken}; __Secure-next-auth.session-token=${this._sessionToken}`,
|
||||||
accept: '*/*'
|
accept: '*/*'
|
||||||
}
|
}
|
||||||
console.log(`${this._apiBaseUrl}/auth/session`, headers)
|
|
||||||
|
|
||||||
const res = await fetch(`${this._apiBaseUrl}/auth/session`, {
|
if (this._debug) {
|
||||||
|
console.log('GET', url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await fetch(url, {
|
||||||
headers
|
headers
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
response = r
|
response = r
|
||||||
|
@ -339,6 +365,10 @@ export class ChatGPTAPI {
|
||||||
this._accessTokenCache.set(KEY_ACCESS_TOKEN, accessToken)
|
this._accessTokenCache.set(KEY_ACCESS_TOKEN, accessToken)
|
||||||
return accessToken
|
return accessToken
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
if (this._debug) {
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
|
||||||
const error = new types.ChatGPTError(
|
const error = new types.ChatGPTError(
|
||||||
`ChatGPT failed to refresh auth token. ${err.toString()}`
|
`ChatGPT failed to refresh auth token. ${err.toString()}`
|
||||||
)
|
)
|
||||||
|
|
|
@ -273,10 +273,13 @@ export type MessageContent = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageMetadata = any
|
export type MessageMetadata = any
|
||||||
|
export type MessageActionType = 'next' | 'variant'
|
||||||
|
|
||||||
export type SendMessageOptions = {
|
export type SendMessageOptions = {
|
||||||
conversationId?: string
|
conversationId?: string
|
||||||
parentMessageId?: string
|
parentMessageId?: string
|
||||||
|
messageId?: string
|
||||||
|
action?: MessageActionType
|
||||||
timeoutMs?: number
|
timeoutMs?: number
|
||||||
onProgress?: (partialResponse: string) => void
|
onProgress?: (partialResponse: string) => void
|
||||||
onConversationResponse?: (response: ConversationResponseEvent) => void
|
onConversationResponse?: (response: ConversationResponseEvent) => void
|
||||||
|
|
Ładowanie…
Reference in New Issue