diff --git a/README.md b/README.md
index d0ca06a9ca..754dc0b844 100644
--- a/README.md
+++ b/README.md
@@ -55,21 +55,27 @@ Currently, this project is only functional with the `text-davinci-003` model.
# Table of Contents
- * [Roadmap](#roadmap)
- * [Features](#features)
- * [Tech Stack](#tech-stack)
- * [Getting Started](#getting-started)
- * [Prerequisites](#prerequisites)
- * [Usage](#usage)
- * [Local (npm)](#npm)
- * [Docker](#docker)
- * [Access Tokens](#access-tokens)
- * [Updating](#updating)
- * [Use Cases](#use-cases)
- * [Origin](#origin)
- * [Caveats](#caveats)
- * [Contributing](#contributing)
- * [License](#license)
+- [ChatGPT Clone](#chatgpt-clone)
+ - [All AI Conversations under One Roof.](#all-ai-conversations-under-one-roof)
+ - [Updates](#updates)
+- [Table of Contents](#table-of-contents)
+ - [Roadmap](#roadmap)
+ - [Features](#features)
+ - [Tech Stack](#tech-stack)
+ - [Getting Started](#getting-started)
+ - [Prerequisites](#prerequisites)
+ - [Usage](#usage)
+ - [Local](#local)
+ - [Docker](#docker)
+ - [Access Tokens](#access-tokens)
+ - [Proxy](#proxy)
+ - [Updating](#updating)
+ - [Use Cases](#use-cases)
+ - [Origin](#origin)
+ - [Caveats](#caveats)
+ - [Regarding use of Official ChatGPT API](#regarding-use-of-official-chatgpt-api)
+ - [Contributing](#contributing)
+ - [License](#license)
## Roadmap
@@ -143,6 +149,8 @@ Here are my recently completed and planned features:
- **Run** `npm run build` in /client/ dir, `npm start` in /api/ dir
- **Visit** http://localhost:3080 (default port) & enjoy
+By default, only local machine can access this server. To share within network or serve as a public server, set `HOST` to `0.0.0.0` in `.env` file
+
### Docker
- **Provide** all credentials, (API keys, access tokens, and Mongo Connection String) in [docker-compose.yml](docker-compose.yml) under api service
@@ -180,6 +188,42 @@ The Bing Access Token is the "_U" cookie from bing.com. Use dev tools or an exte
**Note:** Specific error handling and styling for this model is still in progress.
+### Proxy
+
+If your server cannot connect to the chatGPT API server by some reason, (eg in China). You can set a environment variable `PROXY`. This will be transmitted to `node-chatgpt-api` interface.
+
+**Warning:** `PROXY` is not `reverseProxyUrl` in `node-chatgpt-api`
+
+
+Set up proxy in local environment
+
+Here is two ways to set proxy.
+- Option 1: system level environment
+`export PROXY="http://127.0.0.1:7890"`
+- Option 2: set in .env file
+`PROXY="http://127.0.0.1:7890"`
+
+**Change `http://127.0.0.1:7890` to your proxy server**
+
+
+
+Set up proxy in docker environment
+
+set in docker-compose.yml file, under services - api - environment
+
+```
+ api:
+ ...
+ environment:
+ ...
+ - "PROXY=http://127.0.0.1:7890"
+ # add this line ↑
+```
+
+**Change `http://127.0.0.1:7890` to your proxy server**
+
+
+
### Updating
- As the project is still a work-in-progress, you should pull the latest and run the steps over. Reset your browser cache/clear site data.
diff --git a/api/.env.example b/api/.env.example
index 14209cff03..e679f6a0e0 100644
--- a/api/.env.example
+++ b/api/.env.example
@@ -1,13 +1,22 @@
-OPENAI_KEY=
-HOST=
+# Server configuration.
+# The server will listen to localhost:3080 request by default. You can set the target ip as you want.
+# If you want this server can be used outside your local machine, for example to share with other
+# machine or expose this from a docker container, set HOST=0.0.0.0 or your external ip interface.
+#
+# Tips: HOST=0.0.0.0 means listening on all interface. It's not a real ip. Use localhost:port rather
+# than 0.0.0.0:port to open it.
+HOST=localhost
PORT=3080
NODE_ENV=development
+# Change this to proxy any API request. It's useful if your machine have difficulty calling the original API server.
+# PROXY="http://YOUR_PROXY_SERVER"
+
# Change this to your MongoDB URI if different and I recommend appending chatgpt-clone
MONGO_URI="mongodb://127.0.0.1:27017/chatgpt-clone"
-# Change this to proxy any request.
-PROXY=
-
-CHATGPT_TOKEN=""
-BING_TOKEN=""
\ No newline at end of file
+# API key configuration.
+# Leave blank if you don't want them.
+OPENAI_KEY=
+CHATGPT_TOKEN=
+BING_TOKEN=
\ No newline at end of file
diff --git a/api/Dockerfile b/api/Dockerfile
index fd21cf4d1a..b861217beb 100644
--- a/api/Dockerfile
+++ b/api/Dockerfile
@@ -8,6 +8,8 @@ RUN npm install
COPY . /api/
# Make port 3080 available to the world outside this container
EXPOSE 3080
+# Expose the server to 0.0.0.0
+ENV HOST=0.0.0.0
# Run the app when the container launches
CMD ["npm", "start"]
diff --git a/api/app/bingai.js b/api/app/bingai.js
index 4dfa8a71d5..d1175c0bfc 100644
--- a/api/app/bingai.js
+++ b/api/app/bingai.js
@@ -10,7 +10,8 @@ const askBing = async ({ text, progressCallback, convo }) => {
// If the above doesn't work, provide all your cookies as a string instead
// cookies: '',
debug: false,
- cache: { store: new KeyvFile({ filename: './data/cache.json' }) }
+ cache: { store: new KeyvFile({ filename: './data/cache.json' }) },
+ proxy: process.env.PROXY || null,
});
let options = {
diff --git a/api/app/chatgpt-browser.js b/api/app/chatgpt-browser.js
index 442d2a731d..a17f277822 100644
--- a/api/app/chatgpt-browser.js
+++ b/api/app/chatgpt-browser.js
@@ -7,6 +7,7 @@ const clientOptions = {
// Access token from https://chat.openai.com/api/auth/session
accessToken: process.env.CHATGPT_TOKEN,
// debug: true
+ proxy: process.env.PROXY || null,
};
const browserClient = async ({ text, progressCallback, convo }) => {
diff --git a/api/app/chatgpt-client.js b/api/app/chatgpt-client.js
index ce3c0e2271..afd31e0a81 100644
--- a/api/app/chatgpt-client.js
+++ b/api/app/chatgpt-client.js
@@ -5,6 +5,7 @@ const clientOptions = {
modelOptions: {
model: 'gpt-3.5-turbo'
},
+ proxy: process.env.PROXY || null,
debug: false
};
diff --git a/api/app/chatgpt-custom.js b/api/app/chatgpt-custom.js
index d31901c75f..a356ba4b1a 100644
--- a/api/app/chatgpt-custom.js
+++ b/api/app/chatgpt-custom.js
@@ -5,6 +5,7 @@ const clientOptions = {
modelOptions: {
model: 'gpt-3.5-turbo'
},
+ proxy: process.env.PROXY || null,
debug: false
};
diff --git a/api/server/index.js b/api/server/index.js
index 347491f0af..b380932531 100644
--- a/api/server/index.js
+++ b/api/server/index.js
@@ -1,28 +1,32 @@
-const express = require('express');
-const dbConnect = require('../models/dbConnect');
-const path = require('path');
-const cors = require('cors');
-const routes = require('./routes');
-const app = express();
-const port = process.env.PORT || 3080;
-const projectPath = path.join(__dirname, '..', '..', 'client');
-dbConnect().then(() => console.log('Connected to MongoDB'));
-
-app.use(cors());
-app.use(express.json());
-app.use(express.static(path.join(projectPath, 'public')));
-
-app.get('/', function (req, res) {
- console.log(path.join(projectPath, 'public', 'index.html'));
- res.sendFile(path.join(projectPath, 'public', 'index.html'));
-});
-
-app.use('/api/ask', routes.ask);
-app.use('/api/messages', routes.messages);
-app.use('/api/convos', routes.convos);
-app.use('/api/customGpts', routes.customGpts);
-app.use('/api/prompts', routes.prompts);
-
-app.listen(port, () => {
- console.log(`Server listening at http://localhost:${port}`);
-});
\ No newline at end of file
+const express = require('express');
+const dbConnect = require('../models/dbConnect');
+const path = require('path');
+const cors = require('cors');
+const routes = require('./routes');
+const app = express();
+const port = process.env.PORT || 3080;
+const host = process.env.HOST || 'localhost'
+const projectPath = path.join(__dirname, '..', '..', 'client');
+dbConnect().then(() => console.log('Connected to MongoDB'));
+
+app.use(cors());
+app.use(express.json());
+app.use(express.static(path.join(projectPath, 'public')));
+
+app.get('/', function (req, res) {
+ console.log(path.join(projectPath, 'public', 'index.html'));
+ res.sendFile(path.join(projectPath, 'public', 'index.html'));
+});
+
+app.use('/api/ask', routes.ask);
+app.use('/api/messages', routes.messages);
+app.use('/api/convos', routes.convos);
+app.use('/api/customGpts', routes.customGpts);
+app.use('/api/prompts', routes.prompts);
+
+app.listen(port, host, () => {
+ if (host=='0.0.0.0')
+ console.log(`Server listening on all interface at port ${port}. Use http://localhost:${port} to access it`);
+ else
+ console.log(`Server listening at http://${host=='0.0.0.0'?'localhost':host}:${port}`);
+});
\ No newline at end of file
diff --git a/client/src/components/Conversations/Conversation.jsx b/client/src/components/Conversations/Conversation.jsx
index 745671e1cc..ce4cf3c6be 100644
--- a/client/src/components/Conversations/Conversation.jsx
+++ b/client/src/components/Conversations/Conversation.jsx
@@ -23,8 +23,8 @@ export default function Conversation({
const { modelMap } = useSelector((state) => state.models);
const inputRef = useRef(null);
const dispatch = useDispatch();
- const { trigger } = manualSWR(`http://localhost:3080/api/messages/${id}`, 'get');
- const rename = manualSWR(`http://localhost:3080/api/convos/update`, 'post');
+ const { trigger } = manualSWR(`/api/messages/${id}`, 'get');
+ const rename = manualSWR(`/api/convos/update`, 'post');
const clickHandler = async () => {
if (conversationId === id) {
diff --git a/client/src/components/Conversations/DeleteButton.jsx b/client/src/components/Conversations/DeleteButton.jsx
index 03c9f47f81..9b8e688cd0 100644
--- a/client/src/components/Conversations/DeleteButton.jsx
+++ b/client/src/components/Conversations/DeleteButton.jsx
@@ -9,7 +9,7 @@ import { setMessages } from '~/store/messageSlice';
export default function DeleteButton({ conversationId, renaming, cancelHandler }) {
const dispatch = useDispatch();
const { trigger } = manualSWR(
- `http://localhost:3080/api/convos/clear`,
+ `/api/convos/clear`,
'post',
() => {
dispatch(setMessages([]));
diff --git a/client/src/components/Models/ModelDialog.jsx b/client/src/components/Models/ModelDialog.jsx
index 47592d8a93..a1b05dfcdd 100644
--- a/client/src/components/Models/ModelDialog.jsx
+++ b/client/src/components/Models/ModelDialog.jsx
@@ -25,7 +25,7 @@ export default function ModelDialog({ mutate, setModelSave, handleSaveState }) {
const [saveText, setSaveText] = useState('Save');
const [required, setRequired] = useState(false);
const inputRef = useRef(null);
- const updateCustomGpt = manualSWR(`http://localhost:3080/api/customGpts/`, 'post');
+ const updateCustomGpt = manualSWR(`/api/customGpts/`, 'post');
const submitHandler = (e) => {
if (chatGptLabel.length === 0) {
diff --git a/client/src/components/Models/ModelItem.jsx b/client/src/components/Models/ModelItem.jsx
index 8b7d8d082d..494b20a2ac 100644
--- a/client/src/components/Models/ModelItem.jsx
+++ b/client/src/components/Models/ModelItem.jsx
@@ -15,8 +15,8 @@ export default function ModelItem({ modelName, value, onSelect }) {
const [currentName, setCurrentName] = useState(modelName);
const [modelInput, setModelInput] = useState(modelName);
const inputRef = useRef(null);
- const rename = manualSWR(`http://localhost:3080/api/customGpts`, 'post');
- const deleteCustom = manualSWR(`http://localhost:3080/api/customGpts/delete`, 'post');
+ const rename = manualSWR(`/api/customGpts`, 'post');
+ const deleteCustom = manualSWR(`/api/customGpts/delete`, 'post');
if (value === 'chatgptCustom') {
return (
diff --git a/client/src/components/Models/ModelMenu.jsx b/client/src/components/Models/ModelMenu.jsx
index 607b48921f..94e9dd5c86 100644
--- a/client/src/components/Models/ModelMenu.jsx
+++ b/client/src/components/Models/ModelMenu.jsx
@@ -27,7 +27,7 @@ export default function ModelMenu() {
const [menuOpen, setMenuOpen] = useState(false);
const { model, customModel } = useSelector((state) => state.submit);
const { models, modelMap, initial } = useSelector((state) => state.models);
- const { trigger } = manualSWR(`http://localhost:3080/api/customGpts`, 'get', (res) => {
+ const { trigger } = manualSWR(`/api/customGpts`, 'get', (res) => {
const fetchedModels = res.map((modelItem) => ({
...modelItem,
name: modelItem.chatGptLabel
diff --git a/client/src/components/Nav/ClearConvos.jsx b/client/src/components/Nav/ClearConvos.jsx
index d262226bb9..e6402b0c40 100644
--- a/client/src/components/Nav/ClearConvos.jsx
+++ b/client/src/components/Nav/ClearConvos.jsx
@@ -10,10 +10,10 @@ export default function ClearConvos() {
const dispatch = useDispatch();
const { mutate } = useSWRConfig();
- const { trigger } = manualSWR(`http://localhost:3080/api/convos/clear`, 'post', () => {
+ const { trigger } = manualSWR(`/api/convos/clear`, 'post', () => {
dispatch(setMessages([]));
dispatch(setNewConvo());
- mutate(`http://localhost:3080/api/convos`);
+ mutate(`/api/convos`);
});
const clickHandler = () => {
diff --git a/client/src/components/Nav/index.jsx b/client/src/components/Nav/index.jsx
index 2ae96d22cc..fa74e069e9 100644
--- a/client/src/components/Nav/index.jsx
+++ b/client/src/components/Nav/index.jsx
@@ -17,7 +17,7 @@ export default function Nav() {
};
const { data, isLoading, mutate } = swr(
- `http://localhost:3080/api/convos?pageNumber=${pageNumber}`,
+ `/api/convos?pageNumber=${pageNumber}`,
onSuccess
);
const containerRef = useRef(null);
diff --git a/client/src/utils/handleSubmit.js b/client/src/utils/handleSubmit.js
index 09e1aa52b6..4ba262ac08 100644
--- a/client/src/utils/handleSubmit.js
+++ b/client/src/utils/handleSubmit.js
@@ -11,7 +11,7 @@ export default function handleSubmit({
chatGptLabel,
promptPrefix
}) {
- const endpoint = `http://localhost:3080/api/ask`;
+ const endpoint = `/api/ask`;
let payload = { model, text, chatGptLabel, promptPrefix };
if (convo.conversationId && convo.parentMessageId) {
payload = {
diff --git a/docker-compose.yml b/docker-compose.yml
index 83fa98fd21..f20d03c1e4 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -17,11 +17,11 @@ services:
image: node-api
restart: always
environment:
- - PORT=3080
- - MONGO_URI=mongodb://mongodb:27017/chatgpt-clone
- - OPENAI_KEY=""
- - CHATGPT_TOKEN=""
- - BING_TOKEN=""
+ - "PORT=3080"
+ - "MONGO_URI=mongodb://mongodb:27017/chatgpt-clone"
+ - "OPENAI_KEY="
+ - "CHATGPT_TOKEN="
+ - "BING_TOKEN="
ports:
- "9000:3080"
volumes: