Rewrite the project

This commit is contained in:
Pawan Osman
2024-04-02 12:01:37 +03:00
parent 2ffe138f91
commit 7b78e3a1ca
15 changed files with 904 additions and 1200 deletions
-3
View File
@@ -1,3 +0,0 @@
.vscode
.idea
node_modules
+4
View File
@@ -3,8 +3,12 @@
.DS_Store
npm-debug.log
yarn.lock
yarn-error.log
node_modules/
dist/
*.tsbuildinfo
*.js
*.js.map
.parcel-cache
db.json
.env
-16
View File
@@ -1,16 +0,0 @@
# syntax=docker/dockerfile:1
FROM node:18-alpine
ENV NODE_ENV=production
WORKDIR /app
COPY ["package.json", "package-lock.json*", "./"]
RUN npm install --production
COPY . .
EXPOSE 3000 8080
CMD ["npm", "start"]
+92 -176
View File
@@ -1,229 +1,145 @@
## [Check the new Google Bard Chatbot!](https://github.com/PawanOsman/GoogleBard)
### If you have any questions or need assistance, please join [[Discord](https://discord.pawan.krd)]
# ChatGPT API Free Reverse Proxy
# Welcome to ChatGPT API _**FREE Reverse Proxy**_
Welcome to the **ChatGPT API Free Reverse Proxy** project, a complimentary resource allowing seamless access to OpenAI's API. This project mirrors the official OpenAI API endpoints, enabling users to leverage OpenAI functionalities without direct cost. Dive into our documentation to discover how to set up your reverse proxy or connect with our hosted service for an even smoother experience.
**ChatGPT API Free Reverse Proxy** is a free reverse proxy to OpenAI API that allows users to access OpenAI API for free.
## Quick Links
# Table of Contents
- [Join our Discord Community](https://discord.pawan.krd) for support and questions.
## Table of Contents
- [Features](#features)
- [How to use ChatGPT API Reverse Proxy](#how-to-use-chatgpt-api-reverse-proxy)
- [Self-Host Your Own API](#self-host-your-own-api)
- [Use Our Hosted API](#use-our-hosted-api-reverse-proxy)
- [Text Completion](#text-completion)
- [Chat Completion (ChatGPT)](#chat-completion-chatgpt)
- [Image Generation (DALL-E)](#image-generation-dall-e)
- [Examples using OpenAI libraries](#examples-using-openai-libraries)
- [Python](#python)
- [Node.js](#nodejs)
- Option 1: [Installing/Self-Hosting Guide](#self-hosting-guide) (Without using any API key)
- [Your PC/Server](#your-pcserver)
- [Termux on Android Phones](#termux-on-android-phones)
- Option 2: [Accessing Our Hosted API](#accessing-our-hosted-api) (Free)
- [Usage Examples](#usage-examples)
- [License](#license)
## Features
- **Multiple OpenAI Keys** - You can use multiple OpenAI keys. The API will randomly choose one of the keys to use.
- **Moderation** - The API has a built-in moderation system that will automatically check the prompt before sending it to OpenAI API (To prevent OpenAI terminate the account for violating OpenAI's policy).
- **Streaming Response** - The API supports streaming response, so you can get the response as soon as it's available.
- **Same as Official** - The API has the same endpoints as the official API, so you can use the same code to access the API (even the official OpenAI libraries)
- **Free** - The API is free to use through our [hosted API](#use-our-hosted-api) (You can also self-host the API if you want).
- **Streaming Response**: The API supports streaming response, so you can get the response as soon as it's available.
- **API Endpoint Compatibility**: Full alignment with official OpenAI API endpoints, ensuring hassle-free integration with existing OpenAI libraries.
- **Complimentary Access**: No charges for API usage, making advanced AI accessible to everyone even **without an API key**.
**Note:** Self-hosting it isn't free, you need to use your OpenAI Account credit.
## Installing/Self-Hosting Guide
## How to use ChatGPT API Reverse Proxy
### Your PC/Server
You can use ChatGPT API Reverse Proxy by choosing one of the following methods:
To install and run the ChatGPT API Reverse Proxy on your PC/Server by following these steps:
- [Self-Host Your Own API](#self-host-your-own-api)
- [Use Our Hosted API](#use-our-hosted-api-reverse-proxy)
Note: This option is not available to all countries yet. if you are from a country that is not supported, you can use a **U.S. VPN** or use **our hosted API**.
1. Ensure NodeJs (v19+) is installed: [Download NodeJs](https://nodejs.org/en/download)
2. Clone this repository:
```bash
git clone https://github.com/PawanOsman/ChatGPT.git
```
3. Open `start.bat` (Windows) or `start.sh` (Linux with `bash start.sh` command) to install dependencies and launch the server.
4. Done, you can connect to your local server's API at:
```
http://localhost:3040/v1/chat/completions
```
Note that the base url will be `http://localhost:3040/v1`
# Self-Host Your Own API
To include installation instructions for Termux on Android devices, you can add the following section right after the instructions for Linux in the **Installing/Self-Hosting Guide**:
To self-host your own ChatGPT API, you can use the following steps:
### Termux on Android Phones
1. [Create an OpenAI API Key](https://platform.openai.com/account/api-keys)
2. Clone this repository and install the dependencies:
To install and run the ChatGPT API Reverse Proxy on Android using Termux, follow these steps:
```bash
git clone https://github.com/PawanOsman/ChatGPT.git
cd ChatGPT
npm install
```
1. Install [Termux](https://play.google.com/store/apps/details?id=com.termux) from the Play Store.
2. Update Termux packages:
```bash
apt update
```
3. Upgrade Termux packages:
```bash
apt upgrade
```
4. Install git, Node.js, and npm:
```bash
apt install -y git nodejs
```
5. Clone the repository:
```bash
git clone https://github.com/PawanOsman/ChatGPT.git
```
6. Navigate to the cloned directory:
```bash
cd ChatGPT
```
7. Start the server with:
3. Set your OpenAI key and other configurations in the `config.js` file.
4. Start the server:
```bash
bash start.sh
```
```bash
npm start
```
8. Your local server will now be running and accessible at:
4. Use the API by sending an HTTP request to the API endpoints for example:
```
http://localhost:3040/v1/chat/completions
```
```txt
http://localhost:3000/v1/completions
http://localhost:3000/v1/chat/completions
```
Note that the base url will be `http://localhost:3040/v1`
# Use Our Hosted API Reverse Proxy
You can now use this address to connect to your self-hosted ChatGPT API Reverse Proxy from Android applications/websites that support reverse proxy configurations, on the same device.
To use our hosted ChatGPT API, you can use the following steps:
## Accessing Our Hosted API
1. Join our [Discord](https://discord.pawan.krd) server.
2. Get your API key from the `#Bot` channel by sending `/key` command.
3. Use the API Key in your requests to the following endpoints.
Utilize our pre-hosted ChatGPT-like API for free by:
## Text Completion:
1. Joining our [Discord server](https://discord.pawan.krd).
2. Obtaining an API key from the `#Bot` channel with the `/key` command.
3. Incorporating the API key into your requests to:
```
https://api.pawan.krd/v1/chat/completions
```
```txt
https://api.pawan.krd/v1/completions
```
## Usage Examples
### Example: [OpenAI Docs](https://platform.openai.com/docs/api-reference/completions)
Leverage the same integration code as OpenAI's official libraries by simply adjusting the API key and base URL in your requests. For self-hosted setups, ensure to switch the base URL to your local server's address as mentioned above.
```bash
curl --location 'https://api.pawan.krd/v1/completions' \
--header 'Authorization: Bearer pk-***[OUR_API_KEY]***' \
--header 'Content-Type: application/json' \
--data '{
"model": "text-davinci-003",
"prompt": "Human: Hello\\nAI:",
"temperature": 0.7,
"max_tokens": 256,
"stop": [
"Human:",
"AI:"
]
}'
```
### Example Usage with OpenAI Libraries
## Chat Completion (ChatGPT):
```txt
https://api.pawan.krd/v1/chat/completions
```
### Example: [OpenAI Docs](https://platform.openai.com/docs/api-reference/chat)
```bash
curl --location 'https://api.pawan.krd/v1/chat/completions' \
--header 'Authorization: Bearer pk-***[OUR_API_KEY]***' \
--header 'Content-Type: application/json' \
--data '{
"model": "gpt-3.5-turbo",
"max_tokens": 100,
"messages": [
{
"role": "system",
"content": "You are an helpful assistant."
},
{
"role": "user",
"content": "Who are you?"
}
]
}'
```
## Image Generation (DALL-E):
```txt
https://api.pawan.krd/v1/images/generations
```
### Example: [OpenAI Docs](https://platform.openai.com/docs/api-reference/images)
```bash
curl --location 'https://api.pawan.krd/v1/images/generations' \
--header 'Authorization: Bearer pk-***[OUR_API_KEY]***' \
--header 'Content-Type: application/json' \
--data '{
"prompt": "a photo of a happy corgi puppy sitting and facing forward, studio light, longshot.",
"n": 1,
"size": "1024x1024"
}'
```
## Examples using OpenAI libraries
You can use the same code to access the API using the official OpenAI libraries, the only difference is that you need to change the API key and the API base URL.
Examples are for text completion, but you can use the same code for chat completion and image generation.
### Python
You need to add the following lines before your code to use the API:
#### Python Example
```python
import openai
openai.api_key = 'pk-**********************************************'
openai.api_base = 'https://api.pawan.krd/v1'
```
openai.api_key = 'pk-**********************************************' # For self-hosted version you can leave it empty
openai.base_url = "https://api.pawan.krd/v1" # For self-hosted version, use "http://localhost:3040/v1"
Example code:
```python
import openai
openai.api_key = 'pk-**********************************************'
openai.api_base = 'https://api.pawan.krd/v1'
response = openai.Completion.create(
model="text-davinci-003",
prompt="Human: Hello\nAI:",
temperature=0.7,
max_tokens=256,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
stop=["Human: ", "AI: "]
completion = openai.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "user", "content": "How do I list all files in a directory using Python?"},
],
)
print(response.choices[0].text)
print(completion.choices[0].message.content)
```
### Node.js
You need to add the following lines before your code to use the API:
#### Node.js Example
```js
import { Configuration, OpenAIApi } from "openai";
const configuration = new Configuration({
apiKey: "pk-**********************************************",
basePath: "https://api.pawan.krd/v1",
});
```
Example code:
```js
import { Configuration, OpenAIApi } from "openai";
const configuration = new Configuration({
apiKey: "pk-**********************************************",
basePath: "https://api.pawan.krd/v1",
apiKey: "pk-**********************************************", // For self-hosted version you can leave it empty
basePath: "https://api.pawan.krd/v1", // For self-hosted version, use "http://localhost:3040/v1"
});
const openai = new OpenAIApi(configuration);
const response = await openai.createCompletion({
model: "text-davinci-003",
prompt: "Human: Hello\nAI:",
temperature: 0.7,
max_tokens: 256,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0,
stop: ["Human: ", "AI: "],
const chatCompletion = await openai.chat.completions.create({
messages: [{ role: "user", content: "Initiate a test message" }],
model: "gpt-3.5-turbo",
});
console.log(response.data.choices[0].text);
console.log(chatCompletion.choices[0].message.content);
```
# License
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
This project is under the AGPL-3.0 License. Refer to the [LICENSE](LICENSE) file for detailed information.
-23
View File
@@ -1,23 +0,0 @@
// Server configuration
export const SERVER_PORT = 3000; // Server port
export const DEBUG = false; // Debug mode
// Prompt Moderation before sending to OpenAI
export const MODERATION = true; // Moderation mode
// Rate limit
export const PRIOD = 15 * 1000; // 15 seconds
export const RATE_LIMIT = 50; // 50 requests per 15 seconds
// Whitelisted IPs
export const WHITELISTED_IPS = [
// "127.0.0.1"
];
// OpenAI API Keys
export let OPENAI_KEYS = [
"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
];
-45
View File
@@ -1,45 +0,0 @@
import { OPENAI_KEYS } from "./config.js";
async function* chunksToLines(chunksAsync) {
let previous = "";
for await (const chunk of chunksAsync) {
const bufferChunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
previous += bufferChunk;
let eolIndex;
while ((eolIndex = previous.indexOf("\n")) >= 0) {
// line includes the EOL
const line = previous.slice(0, eolIndex + 1).trimEnd();
if (line === "data: [DONE]") break;
if (line.startsWith("data: ")) yield line;
previous = previous.slice(eolIndex + 1);
}
}
}
async function* linesToMessages(linesAsync) {
for await (const line of linesAsync) {
const message = line.substring("data :".length);
yield message;
}
}
async function* streamCompletion(data) {
yield* linesToMessages(chunksToLines(data));
}
function generateId() {
const chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
let id = "org-";
for (let i = 0; i < 24; i++) {
id += chars.charAt(Math.floor(Math.random() * chars.length));
}
return id;
}
function getOpenAIKey() {
return OPENAI_KEYS[Math.floor(Math.random() * OPENAI_KEYS.length)];
}
export { generateId, getOpenAIKey, streamCompletion }
-33
View File
@@ -1,33 +0,0 @@
import express, { json, urlencoded } from 'express';
import { completions, chatCompletions } from './routes.js';
import { corsMiddleware, rateLimitMiddleware } from './middlewares.js';
import { DEBUG, SERVER_PORT } from './config.js';
let app = express();
process.on("uncaughtException", function (err) {
if (DEBUG) console.error(`Caught exception: ${err}`);
});
// Middlewares
app.use(corsMiddleware);
app.use(rateLimitMiddleware);
app.use(json());
app.use(urlencoded({ extended: true }));
// Register routes
app.all("/", async function (req, res) {
res.set("Content-Type", "application/json");
return res.status(200).send({
status: true,
github: "https://github.com/PawanOsman/ChatGPT",
discord: "https://discord.pawan.krd"
});
});
app.post("/v1/completions", completions);
app.post("/v1/chat/completions", chatCompletions);
// Start server
app.listen(SERVER_PORT, () => {
console.log(`Listening on ${SERVER_PORT} ...`);
});
-46
View File
@@ -1,46 +0,0 @@
import { RATE_LIMIT, PRIOD, WHITELISTED_IPS } from "./config.js";
const rateLimit = new Map();
function corsMiddleware(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Methods", "*");
next();
};
async function rateLimitMiddleware(req, res, next) {
let ip = req.headers["CF-Connecting-IP"] ?? req.headers["cf-connecting-ip"] ?? req.headers["X-Forwarded-For"] ?? req.headers["x-forwarded-for"] ?? req.ip;
if (WHITELISTED_IPS.includes(ip)) return next();
if (!rateLimit.has(ip)) {
rateLimit.set(ip, {
requests: 1,
lastRequestTime: Date.now()
});
} else {
const currentTime = Date.now();
const timeSinceLastRequest = currentTime - rateLimit.get(ip).lastRequestTime;
if (timeSinceLastRequest > PRIOD) {
rateLimit.set(ip, {
requests: 1,
lastRequestTime: currentTime
});
} else {
let updatedCount = rateLimit.get(ip).requests + 1;
if (updatedCount > RATE_LIMIT) {
return res.status(429).send({
status: false,
error: "Too many requests, please try again later"
});
}
rateLimit.set(ip, {
requests: updatedCount,
lastRequestTime: rateLimit.get(ip).lastRequestTime
});
}
}
next();
};
export { corsMiddleware, rateLimitMiddleware }
+446 -566
View File
File diff suppressed because it is too large Load Diff
+17 -15
View File
@@ -1,26 +1,28 @@
{
"name": "chatgpt",
"version": "1.0.0",
"description": "## If you have any questions or need assistance, please join [[Discord](https://discord.pawan.krd)]",
"description": "OpenAI API Free Reverse Proxy",
"type": "module",
"main": "index.js",
"main": "app.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
"start": "tsc && node dist/app.js",
"watch": "tsc-watch --onSuccess \"node dist/app.js\"",
"build": "tsc"
},
"author": "Pawan Osman",
"license": "AGPL-3.0",
"repository": {
"type": "git",
"url": "git+https://github.com/PawanOsman/ChatGPT.git"
"url": "https://github.com/PawanOsman/ChatGPT.git"
},
"author": "PawanOsman <contact@pawan.krd> (https://pawan.krd/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/PawanOsman/ChatGPT/issues"
},
"homepage": "https://github.com/PawanOsman/ChatGPT#readme",
"dependencies": {
"axios": "1.3.4",
"express": "4.18.2",
"openai": "3.2.1"
"axios": "^1.6.7",
"body-parser": "^1.20.2",
"express": "^4.18.3"
},
"devDependencies": {
"@types/express": "^4.17.21",
"ts-node": "^10.9.2",
"typescript": "^5.3.3"
}
}
}
-277
View File
@@ -1,277 +0,0 @@
import axios from "axios";
import { Configuration, OpenAIApi } from "openai";
import { streamCompletion, generateId, getOpenAIKey } from "./functions.js"
import { DEBUG, MODERATION } from "./config.js";
async function completions(req, res) {
let orgId = generateId();
let key = getOpenAIKey();
if (!req.body.prompt) {
res.set("Content-Type", "application/json");
return res.status(400).send({
status: false,
error: "No prompt provided"
});
}
if (DEBUG) console.log(`[Text] [MAX-TOKENS:${req.body.max_tokens ?? "unset"}] ${req.body.prompt}`);
if (MODERATION) {
try {
let openAi = new OpenAIApi(new Configuration({ apiKey: key }));
let response = await openAi.createModeration({
input: req.body.prompt,
});
if (response.data.results[0].flagged) {
res.set("Content-Type", "application/json");
return res.status(400).send({
status: false,
error: "Your prompt contains content that is not allowed",
reason: response.data.results[0].reason,
contact: "https://discord.pawan.krd"
});
}
}
catch (e) {
}
}
if (req.body.stream) {
try {
const response = await axios.post(
`https://api.openai.com/v1/completions`, req.body,
{
responseType: "stream",
headers: {
Accept: "text/event-stream",
"Content-Type": "application/json",
Authorization: `Bearer ${key}`,
},
},
);
res.setHeader("content-type", "text/event-stream");
for await (const message of streamCompletion(response.data)) {
try {
const parsed = JSON.parse(message);
delete parsed.id;
delete parsed.created;
res.write(`data: ${JSON.stringify(parsed)}\n\n`);
} catch (error) {
if (DEBUG) console.error("Could not JSON parse stream message", message, error);
}
}
res.write(`data: [DONE]`);
res.end();
} catch (error) {
try {
if (error.response && error.response.data) {
let errorResponseStr = "";
for await (const message of error.response.data) {
errorResponseStr += message;
}
errorResponseStr = errorResponseStr.replace(/org-[a-zA-Z0-9]+/, orgId);
const errorResponseJson = JSON.parse(errorResponseStr);
return res.status(error.response.status).send(errorResponseJson);
} else {
if (DEBUG) console.error("Could not JSON parse stream message", error);
return res.status(500).send({
status: false,
error: "something went wrong!"
});
}
}
catch (e) {
console.log(e);
return res.status(500).send({
status: false,
error: "something went wrong!"
});
}
}
}
else {
try {
const response = await axios.post(
`https://api.openai.com/v1/completions`, req.body,
{
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${key}`,
},
},
);
delete response.data.id;
delete response.data.created;
return res.status(200).send(response.data);
} catch (error) {
try {
error.response.data.error.message = error.response.data.error.message.replace(/org-[a-zA-Z0-9]+/, orgId);
return res.status(error.response.status).send(error.response.data);
}
catch (e) {
if (DEBUG) console.log(e);
return res.status(500).send({
status: false,
error: "something went wrong!"
});
}
}
}
}
async function chatCompletions(req, res) {
let orgId = generateId();
let key = getOpenAIKey();
if (MODERATION) {
try {
let prompt = [];
try {
req.body.messages.forEach(element => {
prompt.push(element.content);
});
}
catch (e) {
return res.status(400).send({
status: false,
error: "messages is required! and must be an array of objects with content and author properties"
});
}
if (DEBUG) console.log(`[CHAT] [MAX-TOKENS:${req.body.max_tokens ?? "unset"}] ${prompt}`);
let openAi = new OpenAIApi(new Configuration({ apiKey: key }));
let response = await openAi.createModeration({
input: prompt,
});
if (response.data.results[0].flagged) {
res.set("Content-Type", "application/json");
return res.status(400).send({
status: false,
error: "Your prompt contains content that is not allowed",
reason: response.data.results[0].reason,
support: "https://discord.pawan.krd"
});
}
}
catch (e) {
if (DEBUG) console.log(e);
return res.status(500).send({
status: false,
error: "something went wrong!"
});
}
}
else {
if (DEBUG) console.log(`[CHAT] [MAX-TOKENS:${req.body.max_tokens ?? "unset"}]`);
}
if (req.body.stream) {
try {
const response = await axios.post(
`https://api.openai.com/v1/chat/completions`, req.body,
{
responseType: "stream",
headers: {
Accept: "text/event-stream",
"Content-Type": "application/json",
Authorization: `Bearer ${key}`,
},
},
);
res.setHeader("content-type", "text/event-stream");
for await (const message of streamCompletion(response.data)) {
try {
const parsed = JSON.parse(message);
delete parsed.id;
delete parsed.created;
const { content } = parsed.choices[0].delta;
if (content) {
res.write(`data: ${JSON.stringify(parsed)}\n\n`);
}
} catch (error) {
if (DEBUG) console.error("Could not JSON parse stream message", message, error);
}
}
res.write(`data: [DONE]`);
res.end();
} catch (error) {
try {
if (error.response && error.response.data) {
let errorResponseStr = "";
for await (const message of error.response.data) {
errorResponseStr += message;
}
errorResponseStr = errorResponseStr.replace(/org-[a-zA-Z0-9]+/, orgId);
const errorResponseJson = JSON.parse(errorResponseStr);
return res.status(error.response.status).send(errorResponseJson);
} else {
if (DEBUG) console.error("Could not JSON parse stream message", error);
return res.status(500).send({
status: false,
error: "something went wrong!"
});
}
}
catch (e) {
if (DEBUG) console.log(e);
return res.status(500).send({
status: false,
error: "something went wrong!"
});
}
}
}
else {
try {
const response = await axios.post(
`https://api.openai.com/v1/chat/completions`, req.body,
{
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Authorization: `Bearer ${key}`,
},
},
);
delete response.data.id;
delete response.data.created;
return res.status(200).send(response.data);
} catch (error) {
try {
error.response.data.error.message = error.response.data.error.message.replace(/org-[a-zA-Z0-9]+/, orgId);
return res.status(error.response.status).send(error.response.data);
}
catch (e) {
if (DEBUG) console.log(e);
return res.status(500).send({
status: false,
error: "something went wrong!"
});
}
}
}
}
export { completions, chatCompletions };
+297
View File
@@ -0,0 +1,297 @@
import express, { Request, Response, NextFunction } from "express";
import bodyParser from "body-parser";
import axios from "axios";
import https from "https";
import { randomUUID } from "crypto";
// Constants for the server and API configuration
const port = 3040;
const baseUrl = "https://chat.openai.com";
const apiUrl = `${baseUrl}/backend-api/conversation`;
const refreshInterval = 60000; // Interval to refresh token in ms
const errorWait = 120000; // Wait time in ms after an error
// Initialize global variables to store the session token and device ID
let token: string;
let oaiDeviceId: string;
// Function to wait for a specified duration
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
function GenerateCompletionId(prefix: string = "cmpl-") {
const characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
const length = 28;
for (let i = 0; i < length; i++) {
prefix += characters.charAt(Math.floor(Math.random() * characters.length));
}
return prefix;
}
async function* chunksToLines(chunksAsync: any) {
let previous = "";
for await (const chunk of chunksAsync) {
const bufferChunk = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
previous += bufferChunk;
let eolIndex: number;
while ((eolIndex = previous.indexOf("\n")) >= 0) {
// line includes the EOL
const line = previous.slice(0, eolIndex + 1).trimEnd();
if (line === "data: [DONE]") break;
if (line.startsWith("data: ")) yield line;
previous = previous.slice(eolIndex + 1);
}
}
}
async function* linesToMessages(linesAsync: any) {
for await (const line of linesAsync) {
const message = line.substring("data :".length);
yield message;
}
}
async function* StreamCompletion(data: any) {
yield* linesToMessages(chunksToLines(data));
}
// Setup axios instance for API requests with predefined configurations
const axiosInstance = axios.create({
httpsAgent: new https.Agent({ rejectUnauthorized: false }),
headers: {
accept: "*/*",
"accept-language": "en-US,en;q=0.9",
"cache-control": "no-cache",
"content-type": "application/json",
"oai-language": "en-US",
origin: baseUrl,
pragma: "no-cache",
referer: baseUrl,
"sec-ch-ua": '"Google Chrome";v="123", "Not:A-Brand";v="8", "Chromium";v="123"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36",
},
});
// Function to get a new session ID and token from the OpenAI API
async function getNewSessionId() {
let newDeviceId = randomUUID();
const response = await axiosInstance.post(
`${baseUrl}/backend-anon/sentinel/chat-requirements`,
{},
{
headers: { "oai-device-id": newDeviceId },
}
);
console.log(`System: Successfully refreshed session ID and token. ${!token ? "(Now it's ready to process requests)" : ""}`);
oaiDeviceId = newDeviceId;
token = response.data.token;
// console.log("New Token:", token);
// console.log("New Device ID:", oaiDeviceId);
}
// Middleware to enable CORS and handle pre-flight requests
function enableCORS(req: Request, res: Response, next: NextFunction) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "*");
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
if (req.method === "OPTIONS") {
return res.status(200).end();
}
next();
}
// Middleware to handle chat completions
async function handleChatCompletion(req: Request, res: Response) {
console.log("Request:", `${req.method} ${req.originalUrl}`, `${req.body?.messages?.length ?? 0} messages`, req.body.stream ? "(stream-enabled)" : "(stream-disabled)");
try {
const body = {
action: "next",
messages: req.body.messages.map((message) => ({
author: { role: message.role },
content: { content_type: "text", parts: [message.content] },
})),
parent_message_id: randomUUID(),
model: "text-davinci-002-render-sha",
timezone_offset_min: -180,
suggestions: [],
history_and_training_disabled: true,
conversation_mode: { kind: "primary_assistant" },
websocket_request_id: randomUUID(),
};
const response = await axiosInstance.post(apiUrl, body, {
responseType: "stream",
headers: {
"oai-device-id": oaiDeviceId,
"openai-sentinel-chat-requirements-token": token,
},
});
// Set the response headers based on the request type
if (req.body.stream) {
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
} else {
res.setHeader("Content-Type", "application/json");
}
let fullContent = "";
let requestId = GenerateCompletionId("chatcmpl-");
let created = Date.now();
for await (const message of StreamCompletion(response.data)) {
const parsed = JSON.parse(message);
let content = parsed?.message?.content?.parts[0] ?? "";
for (let message of req.body.messages) {
if (message.content === content) {
content = "";
break;
}
}
if (content === "") continue;
if (req.body.stream) {
let response = {
id: requestId,
created: created,
object: "chat.completion.chunk",
model: "gpt-3.5-turbo",
choices: [
{
delta: {
content: content.replace(fullContent, ""),
},
index: 0,
finish_reason: null,
},
],
};
res.write(`data: ${JSON.stringify(response)}\n\n`);
}
fullContent = content.length > fullContent.length ? content : fullContent;
}
if (req.body.stream) {
res.write(
`data: ${JSON.stringify({
id: requestId,
created: created,
object: "chat.completion.chunk",
model: "gpt-3.5-turbo",
choices: [
{
delta: {
content: "",
},
index: 0,
finish_reason: "stop",
},
],
})}\n\n`
);
} else {
res.write(
JSON.stringify({
id: requestId,
created: created,
model: "gpt-3.5-turbo",
object: "chat.completion",
choices: [
{
finish_reason: "stop",
index: 0,
message: {
content: fullContent,
role: "assistant",
},
},
],
usage: {
prompt_tokens: 0,
completion_tokens: 0,
total_tokens: 0,
},
})
);
}
res.end();
} catch (error: any) {
// console.log('Error:', error.response?.data ?? error.message);
if (!res.headersSent) res.setHeader("Content-Type", "application/json");
// console.error('Error handling chat completion:', error);
res.write(
JSON.stringify({
status: false,
error: {
message: "An error happened, please make sure your request is SFW, or use a jailbreak to bypass the filter.",
type: "invalid_request_error",
},
support: "https://discord.pawan.krd",
})
);
res.end();
}
}
// Initialize Express app and use middlewares
const app = express();
app.use(bodyParser.json());
app.use(enableCORS);
// Route to handle POST requests for chat completions
app.post("/v1/chat/completions", handleChatCompletion);
// 404 handler for unmatched routes
app.use((req, res) =>
res.status(404).send({
status: false,
error: {
message: `The requested endpoint was not found. please make sure to use "http://localhost:3040/v1" as the base URL.`,
type: "invalid_request_error",
},
support: "https://discord.pawan.krd",
})
);
// Start the server and the session ID refresh loop
app.listen(port, () => {
console.log(`💡 Server is running at http://localhost:${port}`);
console.log();
console.log(`🔗 Base URL: http://localhost:${port}/v1`);
console.log(`🔗 ChatCompletion Endpoint: http://localhost:${port}/v1/chat/completions`);
console.log();
console.log("📝 Author: Pawan.Krd");
console.log(`🌐 Discord server: https://discord.gg/pawan`);
console.log("🌍 GitHub Repository: https://github.com/PawanOsman/ChatGPT");
console.log(`Don't forget to ⭐ star the repository if you like this project!`);
console.log();
setTimeout(async () => {
while (true) {
try {
await getNewSessionId();
await wait(refreshInterval);
} catch (error) {
console.error("Error refreshing session ID, retrying in 1 minute...");
console.error("If this error persists, your country may not be supported yet.");
console.error("If your country was the issue, please consider using a U.S. VPN.");
await wait(errorWait);
}
}
}, 0);
});
+10
View File
@@ -0,0 +1,10 @@
@echo off
IF NOT EXIST node_modules (
echo Installing npm packages...
call npm install
)
cls
echo Starting the application...
call npm start
+10
View File
@@ -0,0 +1,10 @@
#!/bin/bash
if [ ! -d "node_modules" ]; then
echo "Installing npm packages..."
npm install
fi
clear
echo "Starting the application..."
npm start
+28
View File
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "es2022",
"module": "ESNext",
"strict": true,
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"outDir": "./dist",
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
},
"incremental": true,
"moduleResolution": "node",
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}