From a81bd27b39b2957a2619dee002bf38b15998beac Mon Sep 17 00:00:00 2001 From: Daniel Avila Date: Sun, 9 Apr 2023 11:17:08 -0400 Subject: [PATCH] feat(api): add support for saving messages to database fix(api): change arrowParens prettier option to always fix(api): update addToCache to include endpointOption and latestMessage fix(api): update askOpenAI to include endpointOption in abortControllers fix(client): remove abortKey state and add currentParent state to MessageHandler --- api/.prettierrc | 2 +- api/models/Message.js | 1 + api/server/routes/ask/addToCache.js | 79 +++++++++++++------ api/server/routes/ask/askOpenAI.js | 17 ++-- .../src/components/MessageHandler/index.jsx | 11 ++- 5 files changed, 78 insertions(+), 32 deletions(-) diff --git a/api/.prettierrc b/api/.prettierrc index 34e12e2f49..1c37ff0e5b 100644 --- a/api/.prettierrc +++ b/api/.prettierrc @@ -1,5 +1,5 @@ { - "arrowParens": "avoid", + "arrowParens": "always", "bracketSpacing": true, "endOfLine": "lf", "htmlWhitespaceSensitivity": "css", diff --git a/api/models/Message.js b/api/models/Message.js index c0b280a85b..af3d454980 100644 --- a/api/models/Message.js +++ b/api/models/Message.js @@ -12,6 +12,7 @@ module.exports = { error }) => { try { + // may also need to update the conversation here await Message.findOneAndUpdate( { messageId }, { diff --git a/api/server/routes/ask/addToCache.js b/api/server/routes/ask/addToCache.js index 826e5d74fa..869f47dc7f 100644 --- a/api/server/routes/ask/addToCache.js +++ b/api/server/routes/ask/addToCache.js @@ -1,31 +1,66 @@ const Keyv = require('keyv'); const { KeyvFile } = require('keyv-file'); const crypto = require('crypto'); +const { saveMessage } = require('../../../models'); -const addToCache = async ( { conversationId, parentMessageId }) => { - const conversationsCache = new Keyv({ - store: new KeyvFile({ filename: './data/cache.json' }) - }); +const addToCache = async ({ + endpointOption, + conversationId, + userMessage, + latestMessage, + parentMessageId +}) => { + try { + const conversationsCache = new Keyv({ + store: new KeyvFile({ filename: './data/cache.json' }), + namespace: 'chatgpt', // should be 'bing' for bing/sydney + }); - let conversation = await conversationsCache.get(conversationId); - let isNewConversation = false; - if (!conversation) { - conversation = { - messages: [], - createdAt: Date.now() + let conversation = await conversationsCache.get(conversationId); + // used to generate a title for the conversation if none exists + // let isNewConversation = false; + if (!conversation) { + conversation = { + messages: [], + createdAt: Date.now() + }; + // isNewConversation = true; + } + + // const shouldGenerateTitle = opts.shouldGenerateTitle && isNewConversation; + + const roles = (options) => { + const { endpoint } = options; + if (endpoint === 'openAI') { + return options?.chatGptLabel || 'ChatGPT'; + } else if (endpoint === 'bingAI') { + return options?.jailbreak ? 'Sydney' : 'BingAI'; + } }; - isNewConversation = true; + + const messageId = crypto.randomUUID(); + + let responseMessage = { + id: messageId, + parentMessageId, + role: roles(endpointOption), + message: latestMessage + }; + + await saveMessage({ + ...responseMessage, + conversationId, + messageId, + sender: responseMessage.role, + text: latestMessage + }); + + conversation.messages.push(userMessage, responseMessage); + + await conversationsCache.set(conversationId, conversation); + } catch (error) { + console.error('Trouble adding to cache', error); } - - // const shouldGenerateTitle = opts.shouldGenerateTitle && isNewConversation; - - const userMessage = { - id: crypto.randomUUID(), - parentMessageId, - role: 'User', - message - }; - conversation.messages.push(userMessage); }; -module.exports = { addToCache }; +module.exports = addToCache; diff --git a/api/server/routes/ask/askOpenAI.js b/api/server/routes/ask/askOpenAI.js index 4ad601068b..56f4aee897 100644 --- a/api/server/routes/ask/askOpenAI.js +++ b/api/server/routes/ask/askOpenAI.js @@ -1,6 +1,7 @@ const express = require('express'); const crypto = require('crypto'); const router = express.Router(); +const addToCache = require('./addToCache'); const { getOpenAIModels } = require('../endpoints'); const { titleConvo, askClient } = require('../../../app/'); const { saveMessage, getConvoTitle, saveConvo, updateConvo, getConvo } = require('../../../models'); @@ -8,16 +9,22 @@ const { handleError, sendMessage, createOnProgress, handleText } = require('./ha const abortControllers = new Map(); -router.post('/abort', (req, res) => { - const { abortKey, message } = req.body; +router.post('/abort', async (req, res) => { + const { abortKey, latestMessage, parentMessageId } = req.body; + console.log(`req.body`, req.body); if (!abortControllers.has(abortKey)) { return res.status(404).send('Request not found'); } + + const { abortController, userMessage, endpointOption } = abortControllers.get(abortKey); + if (!endpointOption.endpoint) { + endpointOption.endpoint = req.originalUrl.replace('/api/ask/','').split('/abort')[0]; + } - const { abortController, userMessage } = abortControllers.get(abortKey); abortController.abort(); abortControllers.delete(abortKey); - console.log('Aborted request', abortKey, userMessage); + console.log('Aborted request', abortKey, userMessage, endpointOption); + await addToCache({ endpointOption, conversationId: abortKey, userMessage, latestMessage, parentMessageId }); res.status(200).send('Aborted'); }); @@ -118,7 +125,7 @@ const ask = async ({ const abortController = new AbortController(); const abortKey = conversationId; console.log('conversationId -----> ', conversationId); - abortControllers.set(abortKey, { abortController, userMessage }); + abortControllers.set(abortKey, { abortController, userMessage, endpointOption }); res.on('close', () => { abortController.abort(); diff --git a/client/src/components/MessageHandler/index.jsx b/client/src/components/MessageHandler/index.jsx index 8d95e78294..dd792e7ed0 100644 --- a/client/src/components/MessageHandler/index.jsx +++ b/client/src/components/MessageHandler/index.jsx @@ -15,7 +15,8 @@ export default function MessageHandler() { const [lastResponse, setLastResponse] = useRecoilState(store.lastResponse); const setSubmission = useSetRecoilState(store.submission); const [source, setSource] = useState(null); - const [abortKey, setAbortKey] = useState(null); + // const [abortKey, setAbortKey] = useState(null); + const [currentParent, setCurrentParent] = useState(null); const { refreshConversations } = store.useConversations(); @@ -174,8 +175,9 @@ export default function MessageHandler() { 'Content-Type': 'application/json' }, body: JSON.stringify({ - abortKey, - message: latestMessage, + abortKey: currentParent.conversationId, + latestMessage, + parentMessageId: currentParent.messageId, }) }) .then(response => { @@ -219,7 +221,8 @@ export default function MessageHandler() { }; createdHandler(data, { ...submission, message }); console.log('created', message); - setAbortKey(message?.conversationId); + // setAbortKey(message?.conversationId); + setCurrentParent(message); } else { let text = data.text || data.response; if (data.initial) console.log(data);