From 9c3a78f96b82d8609d98a8758ef04690e4dfc4e7 Mon Sep 17 00:00:00 2001 From: Daniel Avila Date: Sat, 4 Mar 2023 17:39:06 -0500 Subject: [PATCH] customGpts persist through localStorage --- README.md | 6 +- models/Conversation.js | 6 + models/CustomGpt.js | 85 ++++++++ models/index.js | 6 +- server/index.js | 1 + server/routes/ask.js | 9 + server/routes/customGpts.js | 56 +++++ server/routes/index.js | 3 +- src/App.jsx | 4 +- src/components/Conversations/Conversation.jsx | 15 +- src/components/Conversations/index.jsx | 2 + src/components/Messages/Message.jsx | 2 +- src/components/Nav/ClearConvos.jsx | 2 +- src/components/main/MenuItems.jsx | 20 ++ src/components/main/ModelDialog.jsx | 135 +++++++++++++ src/components/main/ModelMenu.jsx | 191 +++++------------- src/components/main/TextChat.jsx | 4 +- src/store/convoSlice.js | 4 +- src/store/modelSlice.js | 7 +- src/style.css | 61 ------ src/utils/fetchers.js | 4 +- webpack.config.js | 2 +- 22 files changed, 405 insertions(+), 220 deletions(-) create mode 100644 models/CustomGpt.js create mode 100644 server/routes/customGpts.js create mode 100644 src/components/main/MenuItems.jsx create mode 100644 src/components/main/ModelDialog.jsx diff --git a/README.md b/README.md index 49f750cf1a..588972cbfd 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ ## Updates
+2023-03-04 + +
+
2023-03-01 Official ChatGPT API is out! Removed davinci since the official API is extremely fast and 10x less expensive. Since user labeling and prompt prefixing is officially supported, I will add a View feature so you can set this within chat, which gives the UI an added use case. I've kept the BrowserClient, since it's free to use like the official site. @@ -43,7 +47,7 @@ Here are my planned/recently finished features. - [x] Markdown handling - [x] Language Detection for code blocks - [x] 'Copy to clipboard' button for code blocks -- [ ] Customize prompt prefix/label (custom ChatGPT using official API) +- [x] Customize prompt prefix/label (custom ChatGPT using official API) - [ ] AI model change handling (whether to pseudo-persist convos or start new convos within existing convo) - [ ] Server convo pagination (limit fetch and load more with 'show more' button) - [ ] Bing AI Styling (for suggested responses, convo end, etc.) diff --git a/models/Conversation.js b/models/Conversation.js index 5a7f59e909..111204aab3 100644 --- a/models/Conversation.js +++ b/models/Conversation.js @@ -24,6 +24,12 @@ const convoSchema = mongoose.Schema({ invocationId: { type: String }, + chatGptLabel: { + type: String + }, + promptPrefix: { + type: String + }, model: { type: String }, diff --git a/models/CustomGpt.js b/models/CustomGpt.js new file mode 100644 index 0000000000..8fce957af2 --- /dev/null +++ b/models/CustomGpt.js @@ -0,0 +1,85 @@ +const mongoose = require('mongoose'); + +const customGptSchema = mongoose.Schema({ + chatGptLabel: { + type: String, + required: true + }, + promptPrefix: { + type: String + }, + value: { + type: String, + required: true + }, + created: { + type: Date, + default: Date.now + } +}); + +const CustomGpt = mongoose.models.CustomGpt || mongoose.model('CustomGpt', customGptSchema); + +const createCustomGpt = async ({ chatGptLabel, promptPrefix, value }) => { + try { + await CustomGpt.create({ + chatGptLabel, + promptPrefix, + value + }); + return { chatGptLabel, promptPrefix, value }; + } catch (error) { + console.error(error); + return { customGpt: 'Error saving customGpt' }; + } +}; + +module.exports = { + getCustomGpts: async (filter) => { + try { + return await CustomGpt.find(filter).exec(); + } catch (error) { + console.error(error); + return { customGpt: 'Error getting customGpts' }; + } + }, + // updateCustomGpt: async ({ _id, ...update }) => { + // try { + // console.log('updateCustomGpt', _id, update); + // return await CustomGpt.findOneAndUpdate({ _id }, update, { + // new: true, + // upsert: true + // }).exec(); + // } catch (error) { + // console.log(error); + // return { message: 'Error updating customGpt' }; + // } + // }, + updateCustomGpt: async ({ value, ...update }) => { + try { + console.log('updateCustomGpt', value, update); + + const customGpt = await CustomGpt.findOne({ value }).exec(); + + if (!customGpt) { + return await createCustomGpt({ value, ...update }); + } else { + return await CustomGpt.findOneAndUpdate({ value }, update, { + new: true, + upsert: true + }).exec(); + } + } catch (error) { + console.log(error); + return { message: 'Error updating customGpt' }; + } + }, + deleteCustomGpts: async (filter) => { + try { + return await CustomGpt.deleteMany(filter).exec(); + } catch (error) { + console.error(error); + return { customGpt: 'Error deleting customGpts' }; + } + } +}; diff --git a/models/index.js b/models/index.js index 6c48dec6d3..7b77a7c79e 100644 --- a/models/index.js +++ b/models/index.js @@ -1,8 +1,12 @@ const { saveMessage, deleteMessages } = require('./Message'); +const { getCustomGpts, updateCustomGpt, deleteCustomGpts } = require('./CustomGpt'); const { saveConvo } = require('./Conversation'); module.exports = { saveMessage, deleteMessages, saveConvo, -}; \ No newline at end of file + getCustomGpts, + updateCustomGpt, + deleteCustomGpts +}; diff --git a/server/index.js b/server/index.js index 9ad7b3ec82..069a699720 100644 --- a/server/index.js +++ b/server/index.js @@ -20,6 +20,7 @@ app.get('/', function (req, res) { app.use('/ask', routes.ask); app.use('/messages', routes.messages); app.use('/convos', routes.convos); +app.use('/customGpts', routes.customGpts); app.use('/prompts', routes.prompts); app.listen(port, () => { diff --git a/server/routes/ask.js b/server/routes/ask.js index d78bba90a1..b3422cd785 100644 --- a/server/routes/ask.js +++ b/server/routes/ask.js @@ -120,6 +120,15 @@ router.post('/', async (req, res) => { gptResponse.sender = model === 'chatgptCustom' ? chatGptLabel : model; gptResponse.final = true; gptResponse.text = await detectCode(gptResponse.text); + + if (chatGptLabel?.length > 0 && model === 'chatgptCustom') { + gptResponse.chatGptLabel = chatGptLabel; + } + + if (promptPrefix?.length > 0 && model === 'chatgptCustom') { + gptResponse.promptPrefix = promptPrefix; + } + await saveMessage(gptResponse); await saveConvo(gptResponse); sendMessage(res, gptResponse); diff --git a/server/routes/customGpts.js b/server/routes/customGpts.js new file mode 100644 index 0000000000..d99ecb9062 --- /dev/null +++ b/server/routes/customGpts.js @@ -0,0 +1,56 @@ +const express = require('express'); +const router = express.Router(); +const { getCustomGpts, updateCustomGpt, deleteCustomGpts } = require('../../models'); + +router.get('/', async (req, res) => { + const models = (await getCustomGpts()).map(model => { + model = model.toObject(); + model._id = model._id.toString(); + return model; + }); + // console.log(models); + res.status(200).send(models); +}); + +router.post('/delete/:_id', async (req, res) => { + const { _id } = req.params; + let filter = {}; + + if (_id) { + filter = { _id }; + } + + try { + const dbResponse = await deleteCustomGpts(filter); + res.status(201).send(dbResponse); + } catch (error) { + console.error(error); + res.status(500).send(error); + } +}); + +// router.post('/create', async (req, res) => { +// const payload = req.body.arg; + +// try { +// const dbResponse = await createCustomGpt(payload); +// res.status(201).send(dbResponse); +// } catch (error) { +// console.error(error); +// res.status(500).send(error); +// } +// }); + +router.post('/', async (req, res) => { + const update = req.body.arg; + + try { + const dbResponse = await updateCustomGpt(update); + res.status(201).send(dbResponse); + } catch (error) { + console.error(error); + res.status(500).send(error); + } +}); + +module.exports = router; diff --git a/server/routes/index.js b/server/routes/index.js index 9e1bd103d3..235d08da2f 100644 --- a/server/routes/index.js +++ b/server/routes/index.js @@ -1,6 +1,7 @@ const ask = require('./ask'); const messages = require('./messages'); const convos = require('./convos'); +const customGpts = require('./customGpts'); const prompts = require('./prompts'); -module.exports = { ask, messages, convos, prompts }; \ No newline at end of file +module.exports = { ask, messages, convos, customGpts, prompts }; \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 745b082b17..0a78ef1ea1 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -12,11 +12,13 @@ const App = () => { const { title } = useSelector((state) => state.convo); useDocumentTitle(title); +// bg-color: #343541 instead of bg-gray-800 + return (