├── .gitignore ├── package.json ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "freegptjs", 3 | "version": "0.0.2", 4 | "description": "This library provides Free access to the OpenAI ChatGPT 3.5 API from JavaScript", 5 | "main": "index.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/Dalufishe/freegpt-js.git" 9 | }, 10 | "scripts": { 11 | "start": "node --experimental-specifier-resolution=node index.js", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "keywords": [ 15 | "freegptjs", 16 | "gpt", 17 | "openai", 18 | "free" 19 | ], 20 | "author": "Dalufishe", 21 | "license": "MIT", 22 | "bin": "./index.js", 23 | "dependencies": { 24 | "axios": "^1.6.8" 25 | } 26 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node.js Free GPT 3.5 API Library 2 | 3 | This library provides Free access to the OpenAI ChatGPT 3.5 API from JavaScript. 4 | 5 | > No API key required. 6 | 7 | The API is almost the same as [openai-node](https://github.com/openai/openai-node/tree/master). 8 | 9 | ```bash 10 | npm install freegptjs 11 | ``` 12 | 13 | ### Usage 14 | 15 | ```js 16 | import FreeGPT3 from "freegptjs"; 17 | 18 | // No API key required. 19 | const openai = new FreeGPT3(); 20 | 21 | async function main() { 22 | const chatCompletion = await openai.chat.completions.create({ 23 | messages: [{ role: "user", content: "Hello, Free GPT !" }], 24 | model: "gpt-3.5-turbo", 25 | }); 26 | console.log(chatCompletion.choices[0].message.content); 27 | } 28 | 29 | main(); 30 | ``` 31 | 32 | ### Streaming responses 33 | 34 | ```js 35 | import FreeGPT3 from "freegptjs"; 36 | 37 | const openai = new FreeGPT3(); 38 | 39 | async function main() { 40 | const stream = await openai.chat.completions.create({ 41 | model: "gpt-3.5-turbo", 42 | messages: [{ role: "user", content: "Hello, Free GPT !" }], 43 | stream: true, 44 | }); 45 | for await (const chunk of stream) { 46 | console.log(chunk.choices[0]?.delta?.content || ""); 47 | } 48 | } 49 | 50 | main(); 51 | ``` 52 | 53 | ### Special Thanks 54 | 55 | https://github.com/skzhengkai/free-chatgpt-api 56 | https://github.com/missuo/FreeGPT35 57 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const axios = require("axios"); 2 | const https = require("https"); 3 | const { randomUUID } = require("crypto"); 4 | 5 | const baseUrl = "https://chat.openai.com"; 6 | const apiUrl = `${baseUrl}/backend-api/conversation`; 7 | 8 | let token; 9 | let oaiDeviceId; 10 | 11 | async function getNewSessionId() { 12 | let newDeviceId = randomUUID(); 13 | const response = await axiosInstance.post( 14 | `${baseUrl}/backend-anon/sentinel/chat-requirements`, 15 | {}, 16 | { 17 | headers: { "oai-device-id": newDeviceId }, 18 | } 19 | ); 20 | // console.log( 21 | // `System: Successfully refreshed session ID and token. ${ 22 | // !token ? "(Now it's ready to process requests)" : "" 23 | // }` 24 | // ); 25 | oaiDeviceId = newDeviceId; 26 | token = response.data.token; 27 | 28 | // console.log("New Token:", token); 29 | // console.log("New Device ID:", oaiDeviceId); 30 | } 31 | 32 | function GenerateCompletionId(prefix = "cmpl-") { 33 | const characters = 34 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 35 | const length = 28; 36 | 37 | for (let i = 0; i < length; i++) { 38 | prefix += characters.charAt(Math.floor(Math.random() * characters.length)); 39 | } 40 | 41 | return prefix; 42 | } 43 | 44 | async function* chunksToLines(chunksAsync) { 45 | let previous = ""; 46 | for await (const chunk of chunksAsync) { 47 | const bufferChunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk); 48 | previous += bufferChunk; 49 | let eolIndex; 50 | while ((eolIndex = previous.indexOf("\n")) >= 0) { 51 | // line includes the EOL 52 | const line = previous.slice(0, eolIndex + 1).trimEnd(); 53 | if (line === "data: [DONE]") break; 54 | if (line.startsWith("data: ")) yield line; 55 | previous = previous.slice(eolIndex + 1); 56 | } 57 | } 58 | } 59 | 60 | async function* linesToMessages(linesAsync) { 61 | for await (const line of linesAsync) { 62 | const message = line.substring("data :".length); 63 | 64 | yield message; 65 | } 66 | } 67 | 68 | async function* messagesToRes(messagesAsync) { 69 | for await (const message of messagesAsync) { 70 | let requestId = GenerateCompletionId("chatcmpl-"); 71 | let created = Date.now(); 72 | let response = { 73 | id: requestId, 74 | created: created, 75 | object: "chat.completion.chunk", 76 | model: "gpt-3.5-turbo", 77 | choices: [ 78 | { 79 | delta: { 80 | content: JSON.parse(message)?.message?.content?.parts[0] || "", 81 | }, 82 | index: 0, 83 | finish_reason: null, 84 | }, 85 | ], 86 | }; 87 | yield response; 88 | } 89 | } 90 | 91 | async function* StreamCompletion(data) { 92 | yield* linesToMessages(chunksToLines(data)); 93 | } 94 | 95 | async function* StreamFinalReturn(data) { 96 | yield* messagesToRes(linesToMessages(chunksToLines(data))); 97 | } 98 | 99 | // Setup axios instance for API requests with predefined configurations 100 | const axiosInstance = axios.create({ 101 | httpsAgent: new https.Agent({ rejectUnauthorized: false }), 102 | headers: { 103 | accept: "*/*", 104 | "accept-language": "en-US,en;q=0.9", 105 | "cache-control": "no-cache", 106 | "content-type": "application/json", 107 | "oai-language": "en-US", 108 | origin: baseUrl, 109 | pragma: "no-cache", 110 | referer: baseUrl, 111 | "sec-ch-ua": 112 | '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"', 113 | "sec-ch-ua-mobile": "?0", 114 | "sec-ch-ua-platform": '"Windows"', 115 | "sec-fetch-dest": "empty", 116 | "sec-fetch-mode": "cors", 117 | "sec-fetch-site": "same-origin", 118 | "user-agent": 119 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", 120 | }, 121 | }); 122 | 123 | // Middleware to handle chat completions 124 | async function handleChatCompletion(data, res) { 125 | try { 126 | await getNewSessionId(); 127 | 128 | const body = { 129 | action: "next", 130 | messages: data.messages.map((message) => ({ 131 | author: { role: message.role }, 132 | content: { content_type: "text", parts: [message.content] }, 133 | })), 134 | parent_message_id: randomUUID(), 135 | model: "text-davinci-002-render-sha", 136 | timezone_offset_min: -180, 137 | suggestions: [], 138 | history_and_training_disabled: true, 139 | conversation_mode: { kind: "primary_assistant" }, 140 | websocket_request_id: randomUUID(), 141 | }; 142 | 143 | const response = await axiosInstance.post(apiUrl, body, { 144 | responseType: "stream", 145 | headers: { 146 | "oai-device-id": oaiDeviceId, 147 | "openai-sentinel-chat-requirements-token": token, 148 | }, 149 | }); 150 | 151 | if (data.stream) return StreamFinalReturn(response.data); 152 | 153 | let fullContent = ""; 154 | let requestId = GenerateCompletionId("chatcmpl-"); 155 | let created = Date.now(); 156 | 157 | for await (const message of StreamCompletion(response.data)) { 158 | const parsed = JSON.parse(message); 159 | 160 | let content = parsed?.message?.content?.parts[0] || ""; 161 | 162 | for (let message of data.messages) { 163 | if (message.content === content) { 164 | content = ""; 165 | break; 166 | } 167 | } 168 | 169 | if (content === "") continue; 170 | 171 | if (data.stream) { 172 | let response = { 173 | id: requestId, 174 | created: created, 175 | object: "chat.completion.chunk", 176 | model: "gpt-3.5-turbo", 177 | choices: [ 178 | { 179 | delta: { 180 | content: content.replace(fullContent, ""), 181 | }, 182 | index: 0, 183 | finish_reason: null, 184 | }, 185 | ], 186 | }; 187 | 188 | res.write(`data: ${JSON.stringify(response)}\n\n`); 189 | } 190 | 191 | fullContent = content.length > fullContent.length ? content : fullContent; 192 | } 193 | if (data.stream) { 194 | res.write( 195 | `data: ${JSON.stringify({ 196 | id: requestId, 197 | created: created, 198 | object: "chat.completion.chunk", 199 | model: "gpt-3.5-turbo", 200 | choices: [ 201 | { 202 | delta: { 203 | content: "", 204 | }, 205 | index: 0, 206 | finish_reason: "stop", 207 | }, 208 | ], 209 | })}\n\n` 210 | ); 211 | } else { 212 | return { 213 | id: requestId, 214 | created: created, 215 | model: "gpt-3.5-turbo", 216 | object: "chat.completion", 217 | choices: [ 218 | { 219 | finish_reason: "stop", 220 | index: 0, 221 | message: { 222 | content: fullContent, 223 | role: "assistant", 224 | }, 225 | }, 226 | ], 227 | usage: { 228 | prompt_tokens: 0, 229 | completion_tokens: 0, 230 | total_tokens: 0, 231 | }, 232 | }; 233 | } 234 | 235 | res.end(); 236 | } catch (error) { 237 | // console.log(error.message); 238 | } 239 | } 240 | module.exports = class FreeGPT35 { 241 | chat = { 242 | completions: { 243 | async create(data) { 244 | return handleChatCompletion(data); 245 | }, 246 | }, 247 | }; 248 | constructor() {} 249 | }; 250 | --------------------------------------------------------------------------------