Compare commits

...

32 Commits

Author SHA1 Message Date
Danny Avila
e8e512a451 Merge pull request #126 from danny-avila/minor-updates
chore: minor updates
2023-03-25 10:21:41 -04:00
Daniel Avila
c2967eafa4 chore: update docker-compose for interchangeable env for search, uninstalled unused deps 2023-03-25 10:20:39 -04:00
Danny Avila
853b4dfd49 Merge pull request #125 from danny-avila/upgrade-node
Upgrade node
2023-03-25 10:02:17 -04:00
Danny Avila
e49adaa314 Merge pull request #124 from danny-avila/bing-styles
Bing styles
2023-03-25 10:01:19 -04:00
Daniel Avila
394cdcd9f4 fix: remove 'class=' error 2023-03-25 09:55:33 -04:00
Daniel Avila
c5561434c8 lift node-api library 2023-03-25 09:53:39 -04:00
Daniel Avila
26e7a715e0 feat: complete bing styles (bing is passed tone style) 2023-03-25 09:40:36 -04:00
Daniel Avila
b07b74ba54 feat: complete bing styles (view) 2023-03-25 09:34:00 -04:00
Danny Avila
70152174b9 Merge pull request #123 from HyunggyuJang/fix/unknown-lang
Fix Unknown language bug
2023-03-25 08:39:10 -04:00
Hyunggyu Jang
8bd29f6d98 Fix Unknown language bug 2023-03-25 18:40:12 +09:00
Daniel Avila
b8720eec3d feat: dark mode for style tabs 2023-03-24 19:02:42 -04:00
Daniel Avila
ad0f2408c8 Merge branch 'main' into bing-styles 2023-03-24 18:50:56 -04:00
Danny Avila
e2ad9accbe Merge pull request #122 from danny-avila/fix-search
Fix search
2023-03-24 18:45:03 -04:00
Daniel Avila
b496174b4c fix: correctly escapes user content in search results 2023-03-24 18:44:12 -04:00
Daniel Avila
3295eb806c chore: expose mongodb on port 27018 2023-03-24 18:27:51 -04:00
Daniel Avila
34bef48e84 fix: correctly searches bing messages 2023-03-24 18:26:59 -04:00
Danny Avila
a6c93ad681 dark mode in progress 2023-03-24 16:31:27 -04:00
Danny Avila
89ab74a913 feat: complete frontend/backend tone handling 2023-03-24 16:21:10 -04:00
Danny Avila
a46ec62532 Update README.md 2023-03-24 16:19:42 -04:00
Danny Avila
22a967927f Update README.md 2023-03-24 16:19:16 -04:00
Danny Avila
0aa7581358 Add files via upload
in-depth local instructions thanks to @fuegovic
2023-03-24 16:17:04 -04:00
Danny Avila
513cd28528 Update README.md 2023-03-24 16:16:06 -04:00
Danny Avila
83b88bd759 feat: complete view for styles 2023-03-24 14:46:07 -04:00
Danny Avila
4f18a471b0 Merge pull request #121 from danny-avila/fix-clear-mobile
fix: clear convos on mobile now has top z-index
2023-03-24 08:20:30 -04:00
Danny Avila
737abd54ac Merge pull request #120 from HyunggyuJang/refactor/sydney
Refactor sydney & fix error
2023-03-24 08:19:06 -04:00
Hyunggyu Jang
1de51467ec Fix forgetfulness for bing/sydney 2023-03-24 12:48:20 +09:00
Hyunggyu Jang
dcc0ab98e1 refactor: Remove verbose user message update for sydney 2023-03-24 12:27:46 +09:00
Daniel Avila
730256dcda fix: clear convos on mobile now has top z-index 2023-03-23 23:18:36 -04:00
Danny Avila
40e793477b Update README.md 2023-03-23 16:30:58 -04:00
Danny Avila
b856db4772 Update .env.example
fix typo
2023-03-23 16:26:22 -04:00
Danny Avila
cab1cbceab Merge pull request #118 from danny-avila/fix-auth
fix: auth env var must have no value, as well as assigned sample_user in route
2023-03-23 15:41:58 -04:00
Danny Avila
b73be0dcfa fix: auth env var must have no value, as well as assigned username incase a falsy value is set 2023-03-23 15:37:25 -04:00
36 changed files with 655 additions and 765 deletions

87
LOCAL_INSTALL.md Normal file
View File

@@ -0,0 +1,87 @@
### Local
- **Install the prerequisites**
- **Download chatgpt-clone**
- Download the latest release here: https://github.com/danny-avila/chatgpt-clone/releases/
- Or by clicking on the green code button in the top of the page and selecting "Download ZIP"
- Or (Recommended if you have Git installed) pull the latest release from the main branch
- If you downloaded a zip file, extract the content in "C:/chatgpt-clone/"
-**IMPORTANT : If you install the files somewhere else modify the instructions accordingly**
- **To enable the Conversation search feature:**
-IF YOU DON'T WANT THIS FEATURE YOU CAN SKIP THIS STEP
- Download MeileSearch latest release from : https://github.com/meilisearch/meilisearch/releases
- Copy it to "C:/chatgpt-clone/"
- Rename the file to "meilisearch.exe"
- Open it by double clicking on it
- Copy the generated Master Key and save it somewhere (You will need it later)
- **Download and Install Node.js**
- Navigate to https://nodejs.org/en/download and to download the latest Node.js version for your OS (The Node.js installer includes the NPM package manager.)
- **Create a MongoDB database**
- Navigate to https://www.mongodb.com/ and Sign In or Create an account
- Create a new project
- Build a Database using the free plan and name the cluster (example: chatgpt-clone)
- Use the "Username and Password" method for authentication
- Add your current IP to the access list
- Then in the Database Deployment tab click on Connect
- In "Choose a connection method" select "Connect your application"
- Driver = Node.js / Version = 4.1 or later
- Copy the connection string and save it somewhere(you will need it later)
- **Get your OpenAI API key** here: https://platform.openai.com/account/api-keys and save it somewhere safe (you will need it later)
- **Get your Bing Access Token**
- Using MS Edge, navigate to bing.com
- Make sure you are logged in
- Open the DevTools by pressing F12 on your keyboard
- Click on the tab "Application" (On the left of the DevTools)
- Expand the "Cookies" (Under "Storage")
- You need to copy the value of the "_U" cookie, save it somewhere, you will need it later
- **Create the ".env" File** You will need all your credentials, (API keys, access tokens, and Mongo Connection String, MeileSearch Master Key)
- Open "C:/chatgpt-clone/api/.env.example" in a text editor
- At this line **MONGO_URI="mongodb://127.0.0.1:27017/chatgpt-clone"**
Replace mongodb://127.0.0.1:27017/chatgpt-clone with the MondoDB connection string you saved earlier, **remove "&w=majority" at the end**
- It should look something like this: "MONGO_URI="mongodb+srv://username:password@chatgpt-clone.lfbcwz3.mongodb.net/?retryWrites=true"
- At this line **OPENAI_KEY=** you need to add your openai API key
- Add your Bing token to this line **BING_TOKEN=** (needed for BingChat & Sydney)
- If you want to enable Search, **SEARCH=TRUE** if you do not want to enable search **SEARCH=FALSE**
- Add your previously saved MeiliSearch Master key to this line **MEILI_MASTER_KEY=** (the key is needed if search is enabled even on local install or you may encounter errors)
- Save the file as **"C:/chatgpt-clone/api/.env"**
**DO THIS ONCE AFTER EVERY UPDATE**
- **Run** `npm ci` in the "C:/chatgpt-clone/api" directory
- **Run** `npm ci` in the "C:/chatgpt-clone/client" directory
- **Run** `npm run build` in the "C:/chatgpt-clone/client"
**DO THIS EVERY TIME YOU WANT TO START CHATGPT-CLONE**
- **Run** `"meilisearch --master-key put_your_meilesearch_Master_Key_here"` in the "C:/chatgpt-clone" directory (Only if SEARCH=TRUE)
- **Run** `npm start` in the "C:/chatgpt-clone/api" directory
- **Visit** http://localhost:3080 (default port) & enjoy
OPTIONAL BUT RECOMMENDED
- **Make a batch file to automate the starting process**
- Open a text editor
- Paste the following code in a new document
- Put your MeiliSearch master key instead of "your_master_key_goes_here"
- Save the file as "C:/chatgpt-clone/chatgpt-clone.bat"
- you can make a shortcut of this batch file and put it anywhere
```
REM the meilisearch executable needs to be at the root of the chatgpt-clone directory
start "MeiliSearch" cmd /k "meilisearch --master-key your_master_key_goes_here
REM ↑↑↑ meilisearch is the name of the meilisearch executable, put your own master key there
start "ChatGPT-Clone" cmd /k "cd api && npm start"
REM this batch file goes at the root of the chatgpt-clone directory (C:/chatgpt-clone/)
```
If you update the chatgpt-clone project files, mannually redo the `npm ci` and `npm run build` steps
To share within network or serve as a public server, set `HOST` to `0.0.0.0` in `.env` file.

View File

@@ -8,6 +8,18 @@ https://user-images.githubusercontent.com/110412045/223754183-8b7f45ce-6517-4bd5
## Updates
<details open>
<summary><strong>2023-03-23</strong></summary>
**Released [v0.1.0](https://github.com/danny-avila/chatgpt-clone/releases/tag/v0.1.0)**, **searching messages/conversations is live!** Up next is more custom parameters for customGpt's. Join the discord server for more immediate assistance and update: **[community discord server](https://discord.gg/NGaa9RPCft)**
</details>
<details>
<summary><strong>Previous Updates</strong></summary>
<details>
<summary><strong>2023-03-22</strong></summary>
@@ -15,12 +27,7 @@ https://user-images.githubusercontent.com/110412045/223754183-8b7f45ce-6517-4bd5
**Released [v0.0.6](https://github.com/danny-avila/chatgpt-clone/releases/tag/v0.0.6)**, the latest stable release before **Searching messages** goes live tomorrow. See exact updates to date in the tag link. By request, there is now also a **[community discord server](https://discord.gg/NGaa9RPCft)**
</details>
<details>
<summary><strong>Previous Updates</strong></summary>
<details>
<summary><strong>2023-03-20</strong></summary>
@@ -165,8 +172,9 @@ Currently, this project is only functional with the `text-davinci-003` model.
- UI from original ChatGPT, including Dark mode
- AI model selection (official ChatGPT API, BingAI, ChatGPT Free)
- Create and Save custom ChatGPTs*
- **3/23/23** - Search all messages/conversations - [see details here](https://github.com/danny-avila/chatgpt-clone/releases/tag/v0.1.0)
^* ChatGPT can be 'customized' by setting a system message or prompt prefix and alternate 'role' to the API request
^* ChatGPT can be 'customized' by setting a system message or prompt prefix and alternate 'role' to the API request^
[More info here](https://platform.openai.com/docs/guides/chat/instructing-chat-models). Here's an [example from this app.]()
@@ -206,12 +214,8 @@ Currently, this project is only functional with the `text-davinci-003` model.
- If using MongoDB Atlas, remove `&w=majority` from default connection string.
### Local
- **Run npm** ci in both the api and client directories
- **Provide** all credentials, (API keys, access tokens, and Mongo Connection String) in api/.env [(see .env example)](api/.env.example)
- **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
### **[In-depth instructions here!](https://github.com/danny-avila/chatgpt-clone/blob/0d4f0f74c04337aaf51b9a3eef898165a7009156/LOCAL_INSTALL.md)**
- thank you [@fuegovic](https://github.com/fuegovic)!
### Docker

View File

@@ -40,20 +40,20 @@ SEARCH=TRUE
# REQUIRED FOR SEARCH: MeiliSearch Host, mainly for api server to connect to the search server.
# must replace '0.0.0.0' with 'meilisearch' if serving meilisearch with docker-compose
# MEILI_HOST='http://0.0.0.0:7700' # <-- local/remote
MEILI_HOST='http://meilisearch:7700' # <-- docker-compose
# MEILI_HOST='http://meilisearch:7700' # <-- docker-compose (should already be setup on docker-compose.yml)
MEILI_HOST='http://0.0.0.0:7700' # <-- local/remote
# REQUIRED FOR SEARCH: MeiliSearch HTTP Address, mainly for docker-compose to expose the search server.
# must replace '0.0.0.0' with 'meilisearch' if serving meilisearch with docker-compose
# MEILI_HTTP_ADDR='0.0.0.0:7700' # <-- local/remote
MEILI_HTTP_ADDR='meilisearch:7700' # <-- docker-compose
# MEILI_HTTP_ADDR='meilisearch:7700' # <-- docker-compose (should already be setup on docker-compose.yml)
MEILI_HTTP_ADDR='0.0.0.0:7700' # <-- local/remote
# REQUIRED FOR SEARCH: In production env., needs a secure key, feel free to generate your own.
# This master key must be at least 16 bytes, composed of valid UTF-8 characters.
# Meilisearch will throw an error and refuse to launch if no master key is provided or if it is under 16 bytes,
# Meilisearch will suggest a secure autogenerated master key.
# Using docker, it seems recognized as production so use a secure key.
# MEILI_MASTER_KEY= # <-- no/insecure key for local/remote
# MEILI_MASTER_KEY= # <-- empty/insecure key works for local/remote
MEILI_MASTER_KEY=JKMW-hGc7v_D1FkJVdbRSDNFLZcUv3S75yrxXP0SmcU # <-- ready made secure key for docker-compose
@@ -61,4 +61,4 @@ MEILI_MASTER_KEY=JKMW-hGc7v_D1FkJVdbRSDNFLZcUv3S75yrxXP0SmcU # <-- ready made se
# global enable/disable the sample user system.
# this is not a ready to use user system.
# dont't use it, unless you can write your own code.
ENABLE_USER_SYSTEM=FALSE
# ENABLE_USER_SYSTEM= # <-- make sure you don't comment this back in if you're not using your own user system

View File

@@ -2,7 +2,7 @@ require('dotenv').config();
const { KeyvFile } = require('keyv-file');
const askBing = async ({ text, onProgress, convo }) => {
const { BingAIClient } = (await import('@waylaidwanderer/chatgpt-api'));
const { BingAIClient } = await import('@waylaidwanderer/chatgpt-api');
const bingAIClient = new BingAIClient({
// "_U" cookie from bing.com
@@ -11,7 +11,7 @@ const askBing = async ({ text, onProgress, convo }) => {
// cookies: '',
debug: false,
cache: { store: new KeyvFile({ filename: './data/cache.json' }) },
proxy: process.env.PROXY || null,
proxy: process.env.PROXY || null
});
let options = { onProgress };
@@ -19,8 +19,15 @@ const askBing = async ({ text, onProgress, convo }) => {
options = { ...options, ...convo };
}
if (options?.jailbreakConversationId == 'false')
options.jailbreakConversationId = false
if (options?.jailbreakConversationId == 'false') {
options.jailbreakConversationId = false;
}
if (convo.toneStyle) {
options.toneStyle = convo.toneStyle;
}
console.log('bing options', options);
const res = await bingAIClient.sendMessage(text, options);

View File

@@ -22,6 +22,10 @@ const askSydney = async ({ text, onProgress, convo }) => {
options = { ...options, jailbreakConversationId: convo.jailbreakConversationId, parentMessageId: convo.parentMessageId };
}
if (convo.toneStyle) {
options.toneStyle = convo.toneStyle;
}
console.log('sydney options', options);
const res = await sydneyClient.sendMessage(text, options

View File

@@ -1,6 +1,6 @@
const cleanUpPrimaryKeyValue = (value) => {
// For Bing convoId handling
return value.replace(/--/g, '-');
return value.replace(/--/g, '|');
};
function replaceSup(text) {

View File

@@ -1,4 +1,5 @@
const mergeSort = require('./mergeSort');
const { cleanUpPrimaryKeyValue } = require('./misc');
function reduceMessages(hits) {
const counts = {};
@@ -29,15 +30,16 @@ function reduceHits(hits, titles = []) {
const convos = [...hits, ...titles];
for (const convo of convos) {
if (!counts[convo.conversationId]) {
counts[convo.conversationId] = 1;
const currentId = cleanUpPrimaryKeyValue(convo.conversationId);
if (!counts[currentId]) {
counts[currentId] = 1;
} else {
counts[convo.conversationId]++;
counts[currentId]++;
}
if (convo.title) {
// titleMap[convo.conversationId] = convo._formatted.title;
titleMap[convo.conversationId] = convo.title;
// titleMap[currentId] = convo._formatted.title;
titleMap[currentId] = convo.title;
}
}

View File

@@ -1,6 +1,5 @@
// const { Conversation } = require('./plugins');
const Conversation = require('./schema/convoSchema');
const { cleanUpPrimaryKeyValue } = require('../lib/utils/misc');
const { getMessages, deleteMessages } = require('./Message');
const getConvo = async (user, conversationId) => {
@@ -90,7 +89,7 @@ module.exports = {
promises.push(
Conversation.findOne({
user,
conversationId: cleanUpPrimaryKeyValue(convo.conversationId)
conversationId: convo.conversationId,
}).exec()
)
);

View File

@@ -32,6 +32,10 @@ const convoSchema = mongoose.Schema(
invocationId: {
type: String
},
toneStyle: {
type: String,
default: null
},
chatGptLabel: {
type: String,
default: null

491
api/package-lock.json generated
View File

@@ -11,7 +11,7 @@
"dependencies": {
"@keyv/mongo": "^2.1.8",
"@vscode/vscode-languagedetection": "^1.0.22",
"@waylaidwanderer/chatgpt-api": "^1.31.6",
"@waylaidwanderer/chatgpt-api": "^1.32.8",
"axios": "^1.3.4",
"chatgpt-latest": "npm:@waylaidwanderer/chatgpt-api@^1.31.6",
"cors": "^2.8.5",
@@ -25,7 +25,6 @@
"keyv-file": "^0.2.0",
"lodash": "^4.17.21",
"meilisearch": "^0.31.1",
"mongomeili": "^0.1.8",
"mongoose": "^6.9.0",
"openai": "^3.1.0",
"sanitize": "^2.1.2"
@@ -1608,23 +1607,6 @@
"node": ">= 8"
}
},
"node_modules/@types/bson": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz",
"integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/mongodb": {
"version": "3.6.20",
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz",
"integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==",
"dependencies": {
"@types/bson": "*",
"@types/node": "*"
}
},
"node_modules/@types/node": {
"version": "18.14.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
@@ -1653,9 +1635,9 @@
}
},
"node_modules/@waylaidwanderer/chatgpt-api": {
"version": "1.31.6",
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.31.6.tgz",
"integrity": "sha512-Db6UK1FRvaUWbFRb6Lg8xnvjkSKjjt4iKYRKPvGNL8LdAiR9Th9e5rLVGHIbGeVBgWWiWH54ei3lQO+oGX9A6w==",
"version": "1.32.8",
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.32.8.tgz",
"integrity": "sha512-0PZTP+M8tyJa9fT0avDZjGcNVRy4glSKj1dWUIGosCySS2EdOyNt0BZ18zsQYDQP50p2FADtY3b3b6DTZCcldw==",
"dependencies": {
"@dqbd/tiktoken": "^1.0.2",
"@fastify/cors": "^8.2.0",
@@ -2011,11 +1993,6 @@
"readable-stream": "^3.4.0"
}
},
"node_modules/bluebird": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
},
"node_modules/body-parser": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
@@ -2541,14 +2518,6 @@
"node": ">=0.4.0"
}
},
"node_modules/denque": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==",
"engines": {
"node": ">=0.10"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -4044,202 +4013,6 @@
"whatwg-url": "^11.0.0"
}
},
"node_modules/mongomeili": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/mongomeili/-/mongomeili-0.1.8.tgz",
"integrity": "sha512-0km+/H0CtG5rJNzvF+L72LzXr+ZOBA3FQb4ze0ieT0siI1zAGp3VFd6vOvRB+ObM55eFVnbpCtWTYUcYD5/JQg==",
"deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
"dependencies": {
"lodash": "^4.17.20",
"meilisearch": "^0.14.0",
"mongoose": "^5.10.9"
}
},
"node_modules/mongomeili/node_modules/bl": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
"dependencies": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
}
},
"node_modules/mongomeili/node_modules/bson": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
"integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==",
"engines": {
"node": ">=0.6.19"
}
},
"node_modules/mongomeili/node_modules/debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/mongomeili/node_modules/debug/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/mongomeili/node_modules/kareem": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
},
"node_modules/mongomeili/node_modules/meilisearch": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.14.2.tgz",
"integrity": "sha512-0PbZxyuUPqaHRHSgIZIDzeMbf45JhE1ctmcRZnWp2NkUp8Ub4XiS+qhXSMYtXNzQq1cpBIed7EcCBgjbcSdGSg==",
"dependencies": {
"cross-fetch": "^3.0.5"
}
},
"node_modules/mongomeili/node_modules/mongodb": {
"version": "3.7.3",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz",
"integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==",
"dependencies": {
"bl": "^2.2.1",
"bson": "^1.1.4",
"denque": "^1.4.1",
"optional-require": "^1.1.8",
"safe-buffer": "^5.1.2"
},
"engines": {
"node": ">=4"
},
"optionalDependencies": {
"saslprep": "^1.0.0"
},
"peerDependenciesMeta": {
"aws4": {
"optional": true
},
"bson-ext": {
"optional": true
},
"kerberos": {
"optional": true
},
"mongodb-client-encryption": {
"optional": true
},
"mongodb-extjson": {
"optional": true
},
"snappy": {
"optional": true
}
}
},
"node_modules/mongomeili/node_modules/mongodb/node_modules/optional-require": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz",
"integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==",
"dependencies": {
"require-at": "^1.0.6"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mongomeili/node_modules/mongoose": {
"version": "5.13.16",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.16.tgz",
"integrity": "sha512-kBNB+BfaQjn3Jjh1SfdZZub70pde9dI0sA8VN6AnnCOeK4TzbLDyB0lBmPBOajppm6U9orde5YfTRyyVa1U45w==",
"dependencies": {
"@types/bson": "1.x || 4.0.x",
"@types/mongodb": "^3.5.27",
"bson": "^1.1.4",
"kareem": "2.3.2",
"mongodb": "3.7.3",
"mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.8.4",
"mquery": "3.2.5",
"ms": "2.1.2",
"optional-require": "1.0.x",
"regexp-clone": "1.0.0",
"safe-buffer": "5.2.1",
"sift": "13.5.2",
"sliced": "1.0.1"
},
"engines": {
"node": ">=4.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mongoose"
}
},
"node_modules/mongomeili/node_modules/mpath": {
"version": "0.8.4",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
"integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==",
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/mongomeili/node_modules/mquery": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz",
"integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==",
"dependencies": {
"bluebird": "3.5.1",
"debug": "3.1.0",
"regexp-clone": "^1.0.0",
"safe-buffer": "5.1.2",
"sliced": "1.0.1"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/mongomeili/node_modules/mquery/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/mongomeili/node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"node_modules/mongomeili/node_modules/readable-stream/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/mongomeili/node_modules/sift": {
"version": "13.5.2",
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
},
"node_modules/mongomeili/node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dependencies": {
"safe-buffer": "~5.1.0"
}
},
"node_modules/mongomeili/node_modules/string_decoder/node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/mongoose": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.1.tgz",
@@ -4261,14 +4034,6 @@
"url": "https://opencollective.com/mongoose"
}
},
"node_modules/mongoose-legacy-pluralize": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
"integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==",
"peerDependencies": {
"mongoose": "*"
}
},
"node_modules/mongoose/node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -4519,14 +4284,6 @@
"follow-redirects": "^1.14.8"
}
},
"node_modules/optional-require": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
"integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==",
"engines": {
"node": ">=4"
}
},
"node_modules/optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -4911,19 +4668,6 @@
"node": ">= 12.13.0"
}
},
"node_modules/regexp-clone": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
"integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
},
"node_modules/require-at": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz",
"integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==",
"engines": {
"node": ">=4"
}
},
"node_modules/require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -5242,11 +4986,6 @@
"semver": "bin/semver.js"
}
},
"node_modules/sliced": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
"integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA=="
},
"node_modules/smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
@@ -7219,23 +6958,6 @@
"fastq": "^1.6.0"
}
},
"@types/bson": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz",
"integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==",
"requires": {
"@types/node": "*"
}
},
"@types/mongodb": {
"version": "3.6.20",
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz",
"integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==",
"requires": {
"@types/bson": "*",
"@types/node": "*"
}
},
"@types/node": {
"version": "18.14.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz",
@@ -7261,9 +6983,9 @@
"integrity": "sha512-rQ/BgMyLuIXSmbA0MSkIPHtcOw14QkeDbAq19sjvaS9LTRr905yij0S8lsyqN5JgOsbtIx7pAcyOxFMzPmqhZQ=="
},
"@waylaidwanderer/chatgpt-api": {
"version": "1.31.6",
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.31.6.tgz",
"integrity": "sha512-Db6UK1FRvaUWbFRb6Lg8xnvjkSKjjt4iKYRKPvGNL8LdAiR9Th9e5rLVGHIbGeVBgWWiWH54ei3lQO+oGX9A6w==",
"version": "1.32.8",
"resolved": "https://registry.npmjs.org/@waylaidwanderer/chatgpt-api/-/chatgpt-api-1.32.8.tgz",
"integrity": "sha512-0PZTP+M8tyJa9fT0avDZjGcNVRy4glSKj1dWUIGosCySS2EdOyNt0BZ18zsQYDQP50p2FADtY3b3b6DTZCcldw==",
"requires": {
"@dqbd/tiktoken": "^1.0.2",
"@fastify/cors": "^8.2.0",
@@ -7514,11 +7236,6 @@
"readable-stream": "^3.4.0"
}
},
"bluebird": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
},
"body-parser": {
"version": "1.20.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
@@ -7897,11 +7614,6 @@
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"denque": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
},
"depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -9021,169 +8733,6 @@
"whatwg-url": "^11.0.0"
}
},
"mongomeili": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/mongomeili/-/mongomeili-0.1.8.tgz",
"integrity": "sha512-0km+/H0CtG5rJNzvF+L72LzXr+ZOBA3FQb4ze0ieT0siI1zAGp3VFd6vOvRB+ObM55eFVnbpCtWTYUcYD5/JQg==",
"requires": {
"lodash": "^4.17.20",
"meilisearch": "^0.14.0",
"mongoose": "^5.10.9"
},
"dependencies": {
"bl": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz",
"integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==",
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
}
},
"bson": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz",
"integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg=="
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
},
"dependencies": {
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}
}
},
"kareem": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz",
"integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ=="
},
"meilisearch": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.14.2.tgz",
"integrity": "sha512-0PbZxyuUPqaHRHSgIZIDzeMbf45JhE1ctmcRZnWp2NkUp8Ub4XiS+qhXSMYtXNzQq1cpBIed7EcCBgjbcSdGSg==",
"requires": {
"cross-fetch": "^3.0.5"
}
},
"mongodb": {
"version": "3.7.3",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz",
"integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==",
"requires": {
"bl": "^2.2.1",
"bson": "^1.1.4",
"denque": "^1.4.1",
"optional-require": "^1.1.8",
"safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
},
"dependencies": {
"optional-require": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz",
"integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==",
"requires": {
"require-at": "^1.0.6"
}
}
}
},
"mongoose": {
"version": "5.13.16",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.16.tgz",
"integrity": "sha512-kBNB+BfaQjn3Jjh1SfdZZub70pde9dI0sA8VN6AnnCOeK4TzbLDyB0lBmPBOajppm6U9orde5YfTRyyVa1U45w==",
"requires": {
"@types/bson": "1.x || 4.0.x",
"@types/mongodb": "^3.5.27",
"bson": "^1.1.4",
"kareem": "2.3.2",
"mongodb": "3.7.3",
"mongoose-legacy-pluralize": "1.0.2",
"mpath": "0.8.4",
"mquery": "3.2.5",
"ms": "2.1.2",
"optional-require": "1.0.x",
"regexp-clone": "1.0.0",
"safe-buffer": "5.2.1",
"sift": "13.5.2",
"sliced": "1.0.1"
}
},
"mpath": {
"version": "0.8.4",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz",
"integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g=="
},
"mquery": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz",
"integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==",
"requires": {
"bluebird": "3.5.1",
"debug": "3.1.0",
"regexp-clone": "^1.0.0",
"safe-buffer": "5.1.2",
"sliced": "1.0.1"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"sift": {
"version": "13.5.2",
"resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz",
"integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
},
"dependencies": {
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
}
}
},
"mongoose": {
"version": "6.10.1",
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.1.tgz",
@@ -9205,12 +8754,6 @@
}
}
},
"mongoose-legacy-pluralize": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
"integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==",
"requires": {}
},
"mpath": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
@@ -9399,11 +8942,6 @@
}
}
},
"optional-require": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz",
"integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA=="
},
"optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@@ -9680,16 +9218,6 @@
"resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz",
"integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="
},
"regexp-clone": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
"integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
},
"require-at": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz",
"integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g=="
},
"require-from-string": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
@@ -9927,11 +9455,6 @@
}
}
},
"sliced": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
"integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA=="
},
"smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",

View File

@@ -21,7 +21,7 @@
"dependencies": {
"@keyv/mongo": "^2.1.8",
"@vscode/vscode-languagedetection": "^1.0.22",
"@waylaidwanderer/chatgpt-api": "^1.31.6",
"@waylaidwanderer/chatgpt-api": "^1.32.8",
"axios": "^1.3.4",
"chatgpt-latest": "npm:@waylaidwanderer/chatgpt-api@^1.31.6",
"cors": "^2.8.5",
@@ -35,7 +35,6 @@
"keyv-file": "^0.2.0",
"lodash": "^4.17.21",
"meilisearch": "^0.31.1",
"mongomeili": "^0.1.8",
"mongoose": "^6.9.0",
"openai": "^3.1.0",
"sanitize": "^2.1.2"

View File

@@ -164,6 +164,8 @@ const ask = async ({
await saveConvo(
req?.session?.user?.username,
{
...convo,
...response,
conversationId,
title
}
@@ -185,4 +187,4 @@ const ask = async ({
}
};
module.exports = router;
module.exports = router;

View File

@@ -114,10 +114,8 @@ const ask = async ({
convo.conversationSignature || response.conversationSignature;
userMessage.conversationId = response.conversationId || conversationId;
userMessage.invocationId = response.invocationId;
userMessage.messageId = response.parentMessageId || userMessageId;
// Unlike gpt and bing, Sydney will never accept our given userMessage.messageId, it will generate its own one.
if (!overrideParentMessageId)
await saveBingMessage({ oldMessageId: userMessageId, ...userMessage });
userMessage.messageId = response.parentMessageId || userMessageId;
// Save sydney response
// response.id = response.messageId;
@@ -141,7 +139,7 @@ const ask = async ({
// Save user message
userMessage.conversationId = response.conversationId || conversationId;
if (!overrideParentMessageId)
await saveBingMessage(userMessage);
await saveBingMessage({ oldMessageId: userMessageId, ...userMessage });
// Bing API will not use our conversationId at the first time,
// so change the placeholder conversationId to the real one.
@@ -176,6 +174,8 @@ const ask = async ({
await saveConvo(
req?.session?.user?.username,
{
...convo,
...response,
conversationId,
title
}
@@ -197,4 +197,4 @@ const ask = async ({
}
};
module.exports = router;
module.exports = router;

View File

@@ -1,46 +1,57 @@
const express = require('express');
const router = express.Router();
const authYourLogin = require('./authYourLogin');
const userSystemEnabled = process.env.ENABLE_USER_SYSTEM || false
const userSystemEnabled = !!process.env.ENABLE_USER_SYSTEM || false;
router.get('/login', function (req, res) {
if (userSystemEnabled)
res.redirect('/auth/your_login_page')
else
res.redirect('/')
})
if (userSystemEnabled) {
res.redirect('/auth/your_login_page');
} else {
res.redirect('/');
}
});
router.get('/logout', function (req, res) {
// clear the session
req.session.user = null
req.session.user = null;
req.session.save(function (error) {
if (userSystemEnabled)
res.redirect('/auth/your_login_page/logout')
else
res.redirect('/')
})
})
req.session.save(function () {
if (userSystemEnabled) {
res.redirect('/auth/your_login_page/logout');
} else {
res.redirect('/');
}
});
});
const authenticatedOr401 = (req, res, next) => {
if (userSystemEnabled) {
const user = req?.session?.user;
if (user) next();
else res.status(401).end();
} else next();
}
if (user) {
next();
} else {
res.status(401).end();
}
} else {
next();
}
};
const authenticatedOrRedirect = (req, res, next) => {
if (userSystemEnabled) {
const user = req?.session?.user;
if (user) next();
else res.redirect('/auth/login').end();
if (user) {
next();
} else {
res.redirect('/auth/login').end();
}
} else next();
};
if (userSystemEnabled) {
router.use('/your_login_page', authYourLogin);
}
if (userSystemEnabled)
router.use('/your_login_page', authYourLogin);
module.exports = { router, authenticatedOr401, authenticatedOrRedirect };

View File

@@ -5,36 +5,40 @@ const router = express.Router();
// THIS IS NOT A READY TO USE USER SYSTEM
// PLEASE IMPLEMENT YOUR OWN USER SYSTEM
const userSystemEnabled = process.env.ENABLE_USER_SYSTEM || false
const userSystemEnabled = process.env.ENABLE_USER_SYSTEM || false;
// Logout
router.get('/logout', (req, res) => {
// Do anything you want
console.warn('logout not implemented!')
console.warn('logout not implemented!');
// finish
res.redirect('/')
res.redirect('/');
});
// Login
router.get('/', async (req, res) => {
// Do anything you want
console.warn('login not implemented! Automatic passed as sample user')
console.warn('login not implemented! Automatic passed as sample user');
// save the user info into session
// username will be used in db
// display will be used in UI
req.session.user = {
username: 'sample_user',
display: 'Sample User',
if (userSystemEnabled) {
req.session.user = {
username: null, // was 'sample_user', but would break previous relationship with previous conversations before v0.1.0
display: 'Sample User'
};
}
req.session.save(function (error) {
if (error) {
console.log(error);
res.send(`<h1>Login Failed. An error occurred. Please see the server logs for details.</h1>`);
} else res.redirect('/')
})
if (error) {
console.log(error);
res.send(`<h1>Login Failed. An error occurred. Please see the server logs for details.</h1>`);
} else {
res.redirect('/');
}
});
});
module.exports = router;

View File

@@ -2,7 +2,7 @@ const _ = require('lodash');
const citationRegex = /\[\^\d+?\^]/g;
const backtick = /(?<!`)[`](?!`)/g;
// const singleBacktick = /(?<!`)[`](?!`)/;
const cursorDefault = '<span class="result-streaming">█</span>';
const cursorDefault = '<span className="result-streaming">█</span>';
const { getCitations, citeText } = require('../../app/');
const handleError = (res, message) => {

View File

@@ -15,7 +15,8 @@ router.get('/sync', async function (req, res) {
router.get('/', async function (req, res) {
try {
const user = req?.session?.user?.username;
let user = req?.session?.user?.username;
user = user ?? null;
const { q } = req.query;
const pageNumber = req.query.pageNumber || 1;
const key = `${user || ''}${q}`;
@@ -50,8 +51,10 @@ router.get('/', async function (req, res) {
};
});
const titles = (await Conversation.meiliSearch(q)).hits;
console.log('message hits:', messages.length, 'convo hits:', titles.length);
const sortedHits = reduceHits(messages, titles);
// debugging:
// console.log('user:', user, 'message hits:', messages.length, 'convo hits:', titles.length);
// console.log('sorted hits:', sortedHits.length);
const result = await getConvosQueried(user, sortedHits, pageNumber);
const activeMessages = [];

123
client/package-lock.json generated
View File

@@ -13,7 +13,7 @@
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2",
"@radix-ui/react-label": "^2.0.0",
"@radix-ui/react-tabs": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.3",
"@reduxjs/toolkit": "^1.9.2",
"axios": "^1.3.4",
"class-variance-authority": "^0.4.0",
@@ -41,6 +41,7 @@
"swr": "^2.0.3",
"tailwind-merge": "^1.9.1",
"tailwindcss-animate": "^1.0.5",
"tailwindcss-radix": "^2.8.0",
"url": "^0.11.0",
"uuidv4": "^6.2.13"
},
@@ -2897,9 +2898,9 @@
}
},
"node_modules/@radix-ui/react-tabs": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.2.tgz",
"integrity": "sha512-gOUwh+HbjCuL0UCo8kZ+kdUEG8QtpdO4sMQduJ34ZEz0r4922g9REOBM+vIsfwtGxSug4Yb1msJMJYN2Bk8TpQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.3.tgz",
"integrity": "sha512-4CkF/Rx1GcrusI/JZ1Rvyx4okGUs6wEenWA0RG/N+CwkRhTy7t54y7BLsWUXrAz/GRbBfHQg/Odfs/RoW0CiRA==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
@@ -2907,8 +2908,58 @@
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-roving-focus": "1.0.2",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-roving-focus": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.0"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-collection": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.2.tgz",
"integrity": "sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz",
"integrity": "sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/@radix-ui/react-tabs/node_modules/@radix-ui/react-roving-focus": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz",
"integrity": "sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-collection": "1.0.2",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-controllable-state": "1.0.0"
},
"peerDependencies": {
@@ -11886,6 +11937,11 @@
"tailwindcss": ">=3.0.0 || insiders"
}
},
"node_modules/tailwindcss-radix": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tailwindcss-radix/-/tailwindcss-radix-2.8.0.tgz",
"integrity": "sha512-1k1UfoIYgVyBl13FKwwoKavjnJ5VEaUClCTAsgz3VLquN4ay/lyaMPzkbqD71sACDs2fRGImytAUlMb4TzOt1A=="
},
"node_modules/tailwindcss/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
@@ -15035,9 +15091,9 @@
}
},
"@radix-ui/react-tabs": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.2.tgz",
"integrity": "sha512-gOUwh+HbjCuL0UCo8kZ+kdUEG8QtpdO4sMQduJ34ZEz0r4922g9REOBM+vIsfwtGxSug4Yb1msJMJYN2Bk8TpQ==",
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.3.tgz",
"integrity": "sha512-4CkF/Rx1GcrusI/JZ1Rvyx4okGUs6wEenWA0RG/N+CwkRhTy7t54y7BLsWUXrAz/GRbBfHQg/Odfs/RoW0CiRA==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
@@ -15045,9 +15101,49 @@
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-presence": "1.0.0",
"@radix-ui/react-primitive": "1.0.1",
"@radix-ui/react-roving-focus": "1.0.2",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-roving-focus": "1.0.3",
"@radix-ui/react-use-controllable-state": "1.0.0"
},
"dependencies": {
"@radix-ui/react-collection": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.2.tgz",
"integrity": "sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-slot": "1.0.1"
}
},
"@radix-ui/react-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz",
"integrity": "sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/react-slot": "1.0.1"
}
},
"@radix-ui/react-roving-focus": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz",
"integrity": "sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==",
"requires": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.0",
"@radix-ui/react-collection": "1.0.2",
"@radix-ui/react-compose-refs": "1.0.0",
"@radix-ui/react-context": "1.0.0",
"@radix-ui/react-direction": "1.0.0",
"@radix-ui/react-id": "1.0.0",
"@radix-ui/react-primitive": "1.0.2",
"@radix-ui/react-use-callback-ref": "1.0.0",
"@radix-ui/react-use-controllable-state": "1.0.0"
}
}
}
},
"@radix-ui/react-use-callback-ref": {
@@ -21553,6 +21649,11 @@
"integrity": "sha512-UU3qrOJ4lFQABY+MVADmBm+0KW3xZyhMdRvejwtXqYOL7YjHYxmuREFAZdmVG5LPe5E9CAst846SLC4j5I3dcw==",
"requires": {}
},
"tailwindcss-radix": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/tailwindcss-radix/-/tailwindcss-radix-2.8.0.tgz",
"integrity": "sha512-1k1UfoIYgVyBl13FKwwoKavjnJ5VEaUClCTAsgz3VLquN4ay/lyaMPzkbqD71sACDs2fRGImytAUlMb4TzOt1A=="
},
"tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",

View File

@@ -23,7 +23,7 @@
"@radix-ui/react-dialog": "^1.0.2",
"@radix-ui/react-dropdown-menu": "^2.0.2",
"@radix-ui/react-label": "^2.0.0",
"@radix-ui/react-tabs": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.3",
"@reduxjs/toolkit": "^1.9.2",
"axios": "^1.3.4",
"class-variance-authority": "^0.4.0",
@@ -51,6 +51,7 @@
"swr": "^2.0.3",
"tailwind-merge": "^1.9.1",
"tailwindcss-animate": "^1.0.5",
"tailwindcss-radix": "^2.8.0",
"url": "^0.11.0",
"uuidv4": "^6.2.13"
},

View File

@@ -23,7 +23,6 @@ export default function Conversation({
}) {
const [renaming, setRenaming] = useState(false);
const [titleInput, setTitleInput] = useState(title);
const { modelMap } = useSelector((state) => state.models);
const { stopStream } = useSelector((state) => state.submit);
const inputRef = useRef(null);
const dispatch = useDispatch();
@@ -49,7 +48,8 @@ export default function Conversation({
conversationSignature,
jailbreakConversationId,
clientId,
invocationId
invocationId,
toneStyle,
} = bingData;
dispatch(
setConversation({
@@ -59,6 +59,7 @@ export default function Conversation({
conversationSignature,
clientId,
invocationId,
toneStyle,
latestMessage: null
})
);
@@ -71,6 +72,7 @@ export default function Conversation({
conversationSignature: null,
clientId: null,
invocationId: null,
toneStyle: null,
latestMessage: null
})
);
@@ -85,13 +87,6 @@ export default function Conversation({
dispatch(setCustomModel(null));
}
// if (modelMap[chatGptLabel.toLowerCase()]) {
// console.log('custom model', chatGptLabel);
// dispatch(setCustomModel(chatGptLabel.toLowerCase()));
// } else {
// dispatch(setCustomModel(null));
// }
dispatch(setMessages(data));
dispatch(setCustomGpt(convo));
dispatch(setText(''));

View File

@@ -14,7 +14,8 @@ export default function Conversations({ conversations, conversationId, moveToTop
conversationSignature: convo.conversationSignature,
parentMessageId: convo.parentMessageId || null,
clientId: convo.clientId,
invocationId: convo.invocationId
invocationId: convo.invocationId,
toneStyle: convo.toneStyle,
}
: null;

View File

@@ -0,0 +1,61 @@
import React, { useState, useEffect, forwardRef } from 'react';
import { Tabs, TabsList, TabsTrigger } from '../ui/Tabs.tsx';
import { useDispatch, useSelector } from 'react-redux';
import { setConversation } from '~/store/convoSlice';
function BingStyles(props, ref) {
const dispatch = useDispatch();
const [value, setValue] = useState('fast');
const { model } = useSelector((state) => state.submit);
const { conversationId } = useSelector((state) => state.convo);
const { messages } = useSelector((state) => state.messages);
const isBing = model === 'bingai' || model === 'sydney';
useEffect(() => {
if (isBing && !conversationId) {
dispatch(setConversation({ toneStyle: value }));
}
}, [isBing, conversationId, model, value, dispatch]);
const show = isBing && (!conversationId || messages?.length === 0);
const defaultClasses = 'p-2 rounded-md font-normal bg-white/[.60] dark:bg-gray-700 text-black';
const defaultSelected = defaultClasses + 'font-medium data-[state=active]:text-white';
const selectedClass = (val) => val + '-tab ' + defaultSelected;
const changeHandler = value => {
setValue(value);
dispatch(setConversation({ toneStyle: value }));
};
return (
<Tabs
defaultValue={value}
className={`shadow-md mb-1 bing-styles ${show ? 'show' : ''}`}
onValueChange={changeHandler}
ref={ref}
>
<TabsList className="bg-white/[.60] dark:bg-gray-700">
<TabsTrigger
value="creative"
className={`${value === 'creative' ? selectedClass(value) : defaultClasses}`}
>
{'Creative'}
</TabsTrigger>
<TabsTrigger
value="fast"
className={`${value === 'fast' ? selectedClass(value) : defaultClasses}`}
>
{'Balanced'}
</TabsTrigger>
<TabsTrigger
value="precise"
className={`${value === 'precise' ? selectedClass(value) : defaultClasses}`}
>
{'Precise'}
</TabsTrigger>
</TabsList>
</Tabs>
);
}
export default forwardRef(BingStyles);

View File

@@ -0,0 +1,16 @@
import React from 'react';
export default function RowButton({ onClick, children, text, className }) {
return (
<button
onClick={onClick}
className={`input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border ${className}`}
type="button"
>
{children}
<span className="hidden md:block">{text}</span>
{/* <RegenerateIcon />
<span className="hidden md:block">Regenerate response</span> */}
</button>
);
}

View File

@@ -1,38 +1,30 @@
import React, { useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { SSE } from '~/utils/sse';
import SubmitButton from './SubmitButton';
import Regenerate from './Regenerate';
// import Regenerate from './Regenerate'; // not used as of Wentao's update
import BingStyles from './BingStyles';
import ModelMenu from '../Models/ModelMenu';
import Footer from './Footer';
import TextareaAutosize from 'react-textarea-autosize';
import createPayload from '~/utils/createPayload';
import resetConvo from '~/utils/resetConvo';
import RegenerateIcon from '../svg/RegenerateIcon';
import StopGeneratingIcon from '../svg/StopGeneratingIcon';
import { useSelector, useDispatch } from 'react-redux';
import {
setConversation,
setNewConvo,
setError,
refreshConversation
} from '~/store/convoSlice';
import { setConversation, setError, refreshConversation } from '~/store/convoSlice';
import { setMessages } from '~/store/messageSlice';
import { setSubmitState, toggleCursor } from '~/store/submitSlice';
import { setText } from '~/store/textSlice';
import { useMessageHandler } from '../../utils/handleSubmit';
export default function TextChat({ messages }) {
const [errorMessage, setErrorMessage] = useState('');
const inputRef = useRef(null);
const bingStylesRef = useRef(null);
const isComposing = useRef(false);
const dispatch = useDispatch();
const { user } = useSelector((state) => state.user);
const convo = useSelector((state) => state.convo);
const { initial } = useSelector((state) => state.models);
const { isSubmitting, stopStream, submission, disabled, model, chatGptLabel, promptPrefix } =
useSelector((state) => state.submit);
const { text } = useSelector((state) => state.text);
const { error, latestMessage } = convo;
const convo = useSelector(state => state.convo);
const { isSubmitting, stopStream, submission, disabled } = useSelector(state => state.submit);
const { text } = useSelector(state => state.text);
const { latestMessage } = convo;
const { ask, regenerate, stopGenerating } = useMessageHandler();
const isNotAppendable = latestMessage?.cancelled || latestMessage?.error;
@@ -42,8 +34,24 @@ export default function TextChat({ messages }) {
inputRef.current?.focus();
}, [convo?.conversationId]);
// controls the height of Bing tone style tabs
useEffect(() => {
if (!inputRef.current) {
return; // wait for the ref to be available
}
const resizeObserver = new ResizeObserver(() => {
const newHeight = inputRef.current.clientHeight;
if (newHeight >= 24) { // 24 is the default height of the input
bingStylesRef.current.style.bottom = 15 + newHeight + 'px';
}
});
resizeObserver.observe(inputRef.current);
return () => resizeObserver.disconnect();
}, [inputRef]);
const messageHandler = (data, currentState, currentMsg) => {
const { messages, _currentMsg, message, sender, isRegenerate } = currentState;
const { messages, message, sender, isRegenerate } = currentState;
if (isRegenerate)
dispatch(
@@ -75,7 +83,7 @@ export default function TextChat({ messages }) {
};
const cancelHandler = (data, currentState, currentMsg) => {
const { messages, _currentMsg, message, sender, isRegenerate } = currentState;
const { messages, message, sender, isRegenerate } = currentState;
if (isRegenerate)
dispatch(
@@ -116,11 +124,9 @@ export default function TextChat({ messages }) {
);
};
const convoHandler = (data, currentState, currentMsg) => {
const convoHandler = (data, currentState) => {
const { requestMessage, responseMessage } = data;
const { conversationId } = requestMessage;
const { messages, _currentMsg, message, isCustomModel, sender, isRegenerate } =
currentState;
const { messages, message, isCustomModel, isRegenerate } = currentState;
const { model, chatGptLabel, promptPrefix } = message;
if (isRegenerate) dispatch(setMessages([...messages, responseMessage]));
else dispatch(setMessages([...messages, requestMessage, responseMessage]));
@@ -199,14 +205,13 @@ export default function TextChat({ messages }) {
};
const errorHandler = (data, currentState, currentMsg) => {
const { initialResponse, messages, _currentMsg, message } = currentState;
const { messages, message } = currentState;
console.log('Error:', data);
const errorResponse = {
...data,
error: true,
parentMessageId: currentMsg?.messageId
};
setErrorMessage(data?.text);
dispatch(setSubmitState(false));
dispatch(setMessages([...messages, currentMsg, errorResponse]));
dispatch(setText(message?.text));
@@ -229,7 +234,7 @@ export default function TextChat({ messages }) {
let latestResponseText = '';
const { server, payload } = createPayload(submission);
const onMessage = (e) => {
const onMessage = e => {
if (stopStream) {
return;
}
@@ -237,7 +242,7 @@ export default function TextChat({ messages }) {
const data = JSON.parse(e.data);
if (data.final) {
convoHandler(data, currentState, currentMsg);
convoHandler(data, currentState);
dispatch(toggleCursor());
console.log('final', data);
}
@@ -268,7 +273,7 @@ export default function TextChat({ messages }) {
events.onmessage = onMessage;
events.oncancel = (e) => {
events.oncancel = () => {
dispatch(toggleCursor(true));
cancelHandler(latestResponseText, currentState, currentMsg);
};
@@ -304,7 +309,7 @@ export default function TextChat({ messages }) {
stopGenerating();
};
const handleKeyDown = (e) => {
const handleKeyDown = e => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
}
@@ -314,7 +319,11 @@ export default function TextChat({ messages }) {
}
};
const handleKeyUp = (e) => {
const handleKeyUp = e => {
if (e.keyCode === 8 && e.target.value.trim() === '') {
dispatch(setText(e.target.value));
}
if (e.key === 'Enter' && e.shiftKey) {
return console.log('Enter + Shift');
}
@@ -324,15 +333,15 @@ export default function TextChat({ messages }) {
}
};
const handleCompositionStart = (e) => {
const handleCompositionStart = () => {
isComposing.current = true;
};
const handleCompositionEnd = (e) => {
const handleCompositionEnd = () => {
isComposing.current = false;
};
const changeHandler = (e) => {
const changeHandler = e => {
const { value } = e.target;
// if (isSubmitting && (value === '' || value === '\n')) {
@@ -341,85 +350,88 @@ export default function TextChat({ messages }) {
dispatch(setText(value));
};
const tryAgain = (e) => {
e.preventDefault();
dispatch(setError(false));
};
// const tryAgain = (e) => {
// e.preventDefault();
// dispatch(setError(false));
// };
const isSearchView = messages?.[0]?.searchResult === true;
const getPlaceholderText = () => {
if (isSearchView) {
return 'Click a message title to open its conversation.'
return 'Click a message title to open its conversation.';
}
if (disabled) {
return 'Choose another model or customize GPT again';
}
if (isNotAppendable) {
return 'Edit your message or Regenerate.'
return 'Edit your message or Regenerate.';
}
return '';
};
return (
<div className="input-panel md:bg-vert-light-gradient dark:md:bg-vert-dark-gradient fixed bottom-0 left-0 w-full border-t bg-white py-2 dark:border-white/20 dark:bg-gray-800 md:absolute md:border-t-0 md:border-transparent md:bg-transparent md:dark:border-transparent md:dark:bg-transparent">
<form className="stretch mx-2 flex flex-row gap-3 last:mb-2 md:pt-2 md:last:mb-6 lg:mx-auto lg:max-w-3xl lg:pt-6">
<div className="relative flex h-full flex-1 md:flex-col">
<span className="order-last ml-1 flex justify-center gap-0 md:order-none md:m-auto md:mb-2 md:w-full md:gap-2">
{isSubmitting && !isSearchView ? (
<button
onClick={handleStopGenerating}
className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border"
type="button"
>
<StopGeneratingIcon />
<span className="hidden md:block">Stop generating</span>
</button>
) : latestMessage && !latestMessage?.isCreatedByUser && !isSearchView ? (
<button
onClick={handleRegenerate}
className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border"
type="button"
>
<RegenerateIcon />
<span className="hidden md:block">Regenerate response</span>
</button>
) : null}
</span>
<div
className={`relative flex flex-grow flex-col rounded-md border border-black/10 ${
disabled ? 'bg-gray-100' : 'bg-white'
} py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 ${
disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700'
} dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] md:py-3 md:pl-4`}
>
<ModelMenu />
<TextareaAutosize
tabIndex="0"
autoFocus
ref={inputRef}
// style={{maxHeight: '200px', height: '24px', overflowY: 'hidden'}}
rows="1"
value={disabled || isNotAppendable ? '' : text}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
onChange={changeHandler}
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
placeholder={getPlaceholderText()}
disabled={disabled || isNotAppendable}
className="m-0 h-auto max-h-52 resize-none overflow-auto border-0 bg-transparent p-0 pl-12 pr-8 leading-6 placeholder:text-sm placeholder:text-gray-600 dark:placeholder:text-gray-500 focus:outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent md:pl-8"
/>
<SubmitButton
submitMessage={submitMessage}
disabled={disabled || isNotAppendable}
/>
<>
<div className="input-panel md:bg-vert-light-gradient dark:md:bg-vert-dark-gradient fixed bottom-0 left-0 w-full border-t bg-white py-2 dark:border-white/20 dark:bg-gray-800 md:absolute md:border-t-0 md:border-transparent md:bg-transparent md:dark:border-transparent md:dark:bg-transparent">
<form className="stretch mx-2 flex flex-row gap-3 last:mb-2 md:pt-2 md:last:mb-6 lg:mx-auto lg:max-w-3xl lg:pt-6">
<div className="relative flex h-full flex-1 md:flex-col">
<span className="order-last ml-1 flex justify-center gap-0 md:order-none md:m-auto md:mb-2 md:w-full md:gap-2">
<BingStyles ref={bingStylesRef}/>
{isSubmitting && !isSearchView ? (
<button
onClick={handleStopGenerating}
className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border"
type="button"
>
<StopGeneratingIcon />
<span className="hidden md:block">Stop generating</span>
</button>
) : latestMessage && !latestMessage?.isCreatedByUser && !isSearchView ? (
<button
onClick={handleRegenerate}
className="input-panel-button btn btn-neutral flex justify-center gap-2 border-0 md:border"
type="button"
>
<RegenerateIcon />
<span className="hidden md:block">Regenerate response</span>
</button>
) : null}
</span>
<div
className={`relative flex flex-grow flex-col rounded-md border border-black/10 ${
disabled ? 'bg-gray-100' : 'bg-white'
} py-2 shadow-[0_0_10px_rgba(0,0,0,0.10)] dark:border-gray-900/50 ${
disabled ? 'dark:bg-gray-900' : 'dark:bg-gray-700'
} dark:text-white dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] md:py-3 md:pl-4`}
>
<ModelMenu />
<TextareaAutosize
tabIndex="0"
autoFocus
ref={inputRef}
// style={{maxHeight: '200px', height: '24px', overflowY: 'hidden'}}
rows="1"
value={disabled || isNotAppendable ? '' : text}
onKeyUp={handleKeyUp}
onKeyDown={handleKeyDown}
onChange={changeHandler}
onCompositionStart={handleCompositionStart}
onCompositionEnd={handleCompositionEnd}
placeholder={getPlaceholderText()}
disabled={disabled || isNotAppendable}
className="m-0 h-auto max-h-52 resize-none overflow-auto border-0 bg-transparent p-0 pl-12 pr-8 leading-6 placeholder:text-sm placeholder:text-gray-600 focus:outline-none focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder:text-gray-500 md:pl-8"
/>
<SubmitButton
submitMessage={submitMessage}
disabled={disabled || isNotAppendable}
/>
</div>
</div>
</div>
</form>
<Footer />
</div>
</form>
<Footer />
</div>
</>
);
}

View File

@@ -8,8 +8,8 @@ import rehypeRaw from 'rehype-raw'
import CodeBlock from './CodeBlock';
import { langSubset } from '~/utils/languages';
const Content = React.memo(({ content, isCreatedByUser = false }) => {
const rehypePlugins = [
const Content = React.memo(({ content, isCreatedByUser = true }) => {
let rehypePlugins = [
[rehypeKatex, { output: 'mathml' }],
[
rehypeHighlight,
@@ -20,12 +20,15 @@ const Content = React.memo(({ content, isCreatedByUser = false }) => {
}
],
[rehypeRaw],
]
];
rehypePlugins = isCreatedByUser ? rehypePlugins.slice(0, -1) : rehypePlugins;
return (
<>
<ReactMarkdown
remarkPlugins={[remarkGfm, [remarkMath, { singleDollarTextMath: false }]]}
rehypePlugins={isCreatedByUser ? rehypePlugins.slice(-1) : rehypePlugins}
rehypePlugins={rehypePlugins}
linkTarget="_new"
components={{
code,

View File

@@ -5,7 +5,7 @@ import { languages } from '~/utils/languages';
const Highlight = React.memo(({ language, code }) => {
const [highlightedCode, setHighlightedCode] = useState(code);
const lang = language ? language : 'javascript';
const lang = languages.has(language) ? language : 'javascript';
useEffect(() => {
setHighlightedCode(hljs.highlight(code, { language: lang }).value);

View File

@@ -46,7 +46,7 @@ const inLineWrap = (parts) => {
});
};
export default function TextWrapper({ text, generateCursor }) {
function TextWrapper({ text, generateCursor }) {
let embedTest = false;
let result = null;
@@ -158,3 +158,5 @@ export default function TextWrapper({ text, generateCursor }) {
</>
);
}
export default React.memo(TextWrapper);

View File

@@ -14,7 +14,7 @@ const DialogPortal = ({
...props
}: DialogPrimitive.DialogPortalProps) => (
<DialogPrimitive.Portal className={cn(className)} {...props}>
<div className="fixed inset-0 z-50 flex items-start justify-center sm:items-center">
<div className="fixed inset-0 z-[999] flex items-start justify-center sm:items-center">
{children}
</div>
</DialogPrimitive.Portal>
@@ -27,7 +27,7 @@ const DialogOverlay = React.forwardRef<
>(({ className, children, ...props }, ref) => (
<DialogPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/50 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=open]:fade-in data-[state=closed]:fade-out",
"fixed inset-0 z-[999] bg-black/50 backdrop-blur-sm transition-all duration-100 data-[state=closed]:animate-out data-[state=open]:fade-in data-[state=closed]:fade-out",
className
)}
{...props}
@@ -45,7 +45,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed z-50 grid w-full gap-4 rounded-b-lg bg-white p-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
"fixed z-[999] grid w-full gap-4 rounded-b-lg bg-white p-6 animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
"dark:bg-slate-900",
className
)}

View File

@@ -14,7 +14,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex items-center justify-center rounded-md bg-slate-100 p-1 dark:bg-slate-800",
"inline-flex items-center justify-center rounded-md bg-gray-100 p-1 dark:bg-gray-800",
className
)}
{...props}
@@ -28,7 +28,7 @@ const TabsTrigger = React.forwardRef<
>(({ className, ...props }, ref) => (
<TabsPrimitive.Trigger
className={cn(
"inline-flex min-w-[100px] items-center justify-center rounded-[0.185rem] px-3 py-1.5 text-sm font-medium text-slate-700 transition-all disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-slate-900 data-[state=active]:shadow-sm dark:text-slate-200 dark:data-[state=active]:bg-slate-900 dark:data-[state=active]:text-slate-100",
"inline-flex min-w-[100px] items-center justify-center rounded-[0.185rem] px-3 py-1.5 text-sm font-medium text-gray-700 transition-all disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-gray-900 data-[state=active]:shadow-sm dark:text-gray-200 dark:data-[state=active]:bg-gray-700 dark:data-[state=active]:text-gray-100",
className
)}
{...props}
@@ -43,7 +43,7 @@ const TabsContent = React.forwardRef<
>(({ className, ...props }, ref) => (
<TabsPrimitive.Content
className={cn(
"mt-2 rounded-md border border-slate-200 p-6 dark:border-slate-700",
"mt-2 rounded-md border border-gray-200 p-6 dark:border-gray-700",
className
)}
{...props}

View File

@@ -1,6 +1,6 @@
.nav-mask {
position: fixed;
z-index: 998;
z-index: 996;
left: 0;
right: 0;
top: 0;

View File

@@ -9,6 +9,7 @@ const initialState = {
conversationSignature: null,
clientId: null,
invocationId: null,
toneStyle: null,
chatGptLabel: null,
promptPrefix: null,
convosLoading: false,
@@ -58,6 +59,7 @@ const currentSlice = createSlice({
state.conversationSignature = null;
state.clientId = null;
state.invocationId = null;
state.toneStyle = null;
state.chatGptLabel = null;
state.promptPrefix = null;
state.convosLoading = false;

View File

@@ -28,6 +28,41 @@
transition: all 1s ease-in-out;
} */
.bing-styles {
position: absolute;
left: 0;
right: 0;
opacity: 0;
bottom: 39px;
z-index: 995;
margin-left: auto;
margin-right: auto;
width: 308px; /* Need a specific value to work */
transition: all 0.5s ease-in-out;
pointer-events: none;
transform: translateY(-60px);
}
.bing-styles.show {
/* bottom: -20px; */
opacity: 1;
pointer-events: all;
transform: translateY(-20px);
}
.creative-tab {
/* background: linear-gradient(90deg, #904887 10.79%, #8B257E 87.08%); */
background: linear-gradient(90deg, #904887 10.79%, #8B257E 87.08%);
}
.fast-tab {
background: linear-gradient(90deg, #2870EA 10.79%, #1B4AEF 87.08%);
}
.precise-tab {
background: linear-gradient(90deg, #006880 10.79%, #005366 87.08%)
}
p > small {
opacity: 0;
animation: fadein 3s forwards;

View File

@@ -13,6 +13,10 @@ export default function createPayload({ convo, message }) {
}
const isBing = model === 'bingai' || model === 'sydney';
if (isBing && !convo?.conversationId) {
payload.toneStyle = convo.toneStyle || 'fast';
}
if (isBing && convo?.conversationId) {
payload = {
...payload,
@@ -20,7 +24,8 @@ export default function createPayload({ convo, message }) {
conversationId: convo.conversationId,
conversationSignature: convo.conversationSignature,
clientId: convo.clientId,
invocationId: convo.invocationId
invocationId: convo.invocationId,
toneStyle: convo.toneStyle,
};
}
@@ -28,4 +33,4 @@ export default function createPayload({ convo, message }) {
server = model === 'bingai' ? server + '/bing' : server;
server = model === 'sydney' ? server + '/sydney' : server;
return { server, payload };
};
}

View File

@@ -1,4 +1,3 @@
import { SSE } from './sse';
import resetConvo from './resetConvo';
import { useSelector, useDispatch } from 'react-redux';
import { setNewConvo } from '~/store/convoSlice';
@@ -14,7 +13,6 @@ const useMessageHandler = () => {
const { initial } = useSelector((state) => state.models);
const { messages } = useSelector((state) => state.messages);
const { model, chatGptLabel, promptPrefix, isSubmitting } = useSelector((state) => state.submit);
const { text } = useSelector((state) => state.text);
const { latestMessage, error } = convo;
const ask = ({ text, parentMessageId=null, conversationId=null, messageId=null}, { isRegenerate=false }={}) => {
@@ -76,7 +74,7 @@ const useMessageHandler = () => {
if (parentMessage && parentMessage.isCreatedByUser)
ask({ ...parentMessage }, { isRegenerate: true })
else
console.error('Failed to regenerate the message: parentMessage not found or not created by user.', message);
console.error('Failed to regenerate the message: parentMessage not found or not created by user.');
}
const stopGenerating = () => {
@@ -88,78 +86,79 @@ const useMessageHandler = () => {
export { useMessageHandler };
export default function handleSubmit({
model,
text,
convo,
messageHandler,
convoHandler,
errorHandler,
chatGptLabel,
promptPrefix
}) {
const endpoint = `/api/ask`;
let payload = { model, text, chatGptLabel, promptPrefix };
if (convo.conversationId && convo.parentMessageId) {
payload = {
...payload,
conversationId: convo.conversationId,
parentMessageId: convo.parentMessageId
};
}
// deprecated
// export default function handleSubmit({
// model,
// text,
// convo,
// messageHandler,
// convoHandler,
// errorHandler,
// chatGptLabel,
// promptPrefix
// }) {
// const endpoint = `/api/ask`;
// let payload = { model, text, chatGptLabel, promptPrefix };
// if (convo.conversationId && convo.parentMessageId) {
// payload = {
// ...payload,
// conversationId: convo.conversationId,
// parentMessageId: convo.parentMessageId
// };
// }
const isBing = model === 'bingai' || model === 'sydney';
if (isBing && convo.conversationId) {
// const isBing = model === 'bingai' || model === 'sydney';
// if (isBing && convo.conversationId) {
payload = {
...payload,
jailbreakConversationId: convo.jailbreakConversationId,
conversationId: convo.conversationId,
conversationSignature: convo.conversationSignature,
clientId: convo.clientId,
invocationId: convo.invocationId,
};
}
// payload = {
// ...payload,
// jailbreakConversationId: convo.jailbreakConversationId,
// conversationId: convo.conversationId,
// conversationSignature: convo.conversationSignature,
// clientId: convo.clientId,
// invocationId: convo.invocationId,
// };
// }
let server = endpoint;
server = model === 'bingai' ? server + '/bing' : server;
server = model === 'sydney' ? server + '/sydney' : server;
// let server = endpoint;
// server = model === 'bingai' ? server + '/bing' : server;
// server = model === 'sydney' ? server + '/sydney' : server;
const events = new SSE(server, {
payload: JSON.stringify(payload),
headers: { 'Content-Type': 'application/json' }
});
// const events = new SSE(server, {
// payload: JSON.stringify(payload),
// headers: { 'Content-Type': 'application/json' }
// });
events.onopen = function () {
console.log('connection is opened');
};
// events.onopen = function () {
// console.log('connection is opened');
// };
events.onmessage = function (e) {
const data = JSON.parse(e.data);
let text = data.text || data.response;
if (data.message) {
messageHandler(text, events);
}
// events.onmessage = function (e) {
// const data = JSON.parse(e.data);
// let text = data.text || data.response;
// if (data.message) {
// messageHandler(text, events);
// }
if (data.final) {
convoHandler(data);
console.log('final', data);
} else {
// console.log('dataStream', data);
}
};
// if (data.final) {
// convoHandler(data);
// console.log('final', data);
// } else {
// // console.log('dataStream', data);
// }
// };
events.onerror = function (e) {
console.log('error in opening conn.');
events.close();
errorHandler(e);
};
// events.onerror = function (e) {
// console.log('error in opening conn.');
// events.close();
// errorHandler(e);
// };
events.addEventListener('stop', () => {
// Close the SSE stream
console.log('stop event received');
events.close();
});
// events.addEventListener('stop', () => {
// // Close the SSE stream
// console.log('stop event received');
// events.close();
// });
events.stream();
}
// events.stream();
// }

View File

@@ -45,6 +45,7 @@ module.exports = {
},
plugins: [
require('tailwindcss-animate'),
require("tailwindcss-radix")(),
// require('@tailwindcss/typography'),
]
};

View File

@@ -29,11 +29,15 @@ services:
- HOST=0.0.0.0
- NODE_ENV=production
- MONGO_URI=mongodb://mongodb:27017/chatgpt-clone
- MEILI_HOST=http://meilisearch:7700
- MEILI_HTTP_ADDR=meilisearch:7700
volumes:
- /client/node_modules
- ./api:/api
- /api/node_modules
mongodb:
ports:
- 27018:27017
image: mongo
restart: always
container_name: mongodb
@@ -46,5 +50,8 @@ services:
- 7700:7700
env_file:
- ./api/.env
environment:
- MEILI_HOST=http://meilisearch:7700
- MEILI_HTTP_ADDR=meilisearch:7700
volumes:
- ./meili_data:/meili_data