UNPKG

chatgpt-lib

Version:

Simple javascript wrapper for ChatGPT's unofficial web API

137 lines (115 loc) 4.55 kB
const uuid = require('uuid'); const axios = require('axios'); const cliPrompt = require('prompt-sync')(); const USER_AGENT = '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'; function isValidJson(text) { try{ JSON.parse(text); return true; } catch { return false; } } class ChatGPT { constructor(config, conversationId = null) { this.config = config; this.conversationId = conversationId; this.parentId = uuid.v4(); } async ask(prompt) { if (!this.config.Authorization || !this.validateToken(this.config.Authorization)) await this.getTokens(); let response = await axios.request({ method: 'POST', url: 'https://chat.openai.com/backend-api/conversation', data: { action: 'next', messages: [ { id: uuid.v4(), role: 'user', content: { content_type: 'text', parts: [prompt], }, }, ], model: 'text-davinci-002-render', conversation_id: this.conversationId, parent_message_id: this.parentId, }, headers: { 'User-Agent': USER_AGENT, 'Accept': 'text/event-stream;application/json', 'Authorization': `Bearer ${this.config.Authorization}`, 'Content-Type': 'application/json', } }).catch(err => { if (err.response.status.toString()[0] === '5') return 'ChatGPT failed to respond due to internal error. Please try again.'; console.log(`ERROR: ChatGPT failed to respond due to :${err}`); return 'ChatGPT failed to respond. Possibly because "chatgpt-lib" flow broke, please report to the developer.'; }); response = response.data.split('\n\n'); response = response[response.length-3].slice(6); try { if (isValidJson(response)) response = JSON.parse(response); else return 'ChatGPT failed to respond. Please try again.'; this.parentId = response.message.id; this.conversationId = response.conversation_id; return response.message.content.parts[0]; } catch (err) { console.log(`ERROR: Could not find or parse actual response text due to: ${err}`); return 'ChatGPT failed to respond. Please try again.'; } } resetThread() { this.conversationId = null; this.parentId = uuid.v4(); } validateToken(token) { if (!token) return false; const parsed = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()); return Date.now() <= parsed.exp * 1000; } async getTokens() { if (!this.config.hasOwnProperty('SessionToken')) { throw new Error('No session token provided'); } const response = await axios.request({ method: 'GET', url: 'https://chat.openai.com/api/auth/session', headers: { 'User-Agent': USER_AGENT, 'Cookie': `__Secure-next-auth.session-token=${this.config.SessionToken}` } }); try { const cookies = response.headers['set-cookie']; const sessionCookie = cookies.find(cookie => cookie.startsWith('__Secure-next-auth.session-token')); this.config.SessionToken = sessionCookie.split('=')[1]; this.config.Authorization = response.data.accessToken; } catch (err) { throw new Error(`Failed to fetch new session tokens due to: ${err}`); } } async initCliConversation() { console.log('You can start prompting ChatGPT now.\nIf you want to reset thread type "\\r". To exit type "\\q" or press ctrl+c.'); while (true) { const input = cliPrompt('You: '); if (['\\q', null].includes(input)) break; if (input === '\\r') { this.resetThread(); console.log('Thread was reset.'); continue; } const answer = await this.ask(input); console.log(`ChatGPT: ${answer}`); } } } module.exports = { ChatGPT };