diff --git a/api/server/routes/ask.js b/api/server/routes/ask.js index f016a49b30..c8313efd68 100644 --- a/api/server/routes/ask.js +++ b/api/server/routes/ask.js @@ -12,7 +12,7 @@ router.use('/bing', askBing); router.use('/sydney', askSydney); router.post('/', async (req, res) => { - let { model, text, parentMessageId, conversationId: oldConversationId, ...convo } = req.body; + let { model, text, overrideParentMessageId=null, parentMessageId, conversationId: oldConversationId, ...convo } = req.body; if (text.length === 0) { return handleError(res, { text: 'Prompt empty or too short' }); } @@ -36,51 +36,22 @@ router.post('/', async (req, res) => { ...convo }); - await saveMessage(userMessage); - await saveConvo(req?.session?.user?.username, { ...userMessage, model, ...convo }); + if (!overrideParentMessageId) { + await saveMessage(userMessage); + await saveConvo(req?.session?.user?.username, { ...userMessage, model, ...convo }); + } return await ask({ userMessage, model, convo, preSendRequest: true, + overrideParentMessageId, req, res }); }); -router.post('/regenerate', async (req, res) => { - const { model } = req.body; - - const oldUserMessage = await getMessages({ messageId: req.body }); - - if (oldUserMessage) { - const convo = await getConvo(userMessage?.conversationId); - - const userMessageId = crypto.randomUUID(); - - let userMessage = { - ...userMessage, - messageId: userMessageId - }; - - console.log('ask log for regeneration', { - model, - ...userMessage, - ...convo - }); - - return await ask({ - userMessage, - model, - convo, - preSendRequest: false, - req, - res - }); - } else return handleError(res, { text: 'Parent message not found' }); -}); - const ask = async ({ userMessage, overrideParentMessageId = null, @@ -136,10 +107,10 @@ const ask = async ({ gptResponse.text = gptResponse.response; // gptResponse.id = gptResponse.messageId; gptResponse.parentMessageId = overrideParentMessageId || userMessageId; - userMessage.conversationId = conversationId - ? conversationId - : gptResponse.conversationId; - await saveMessage(userMessage); + // userMessage.conversationId = conversationId + // ? conversationId + // : gptResponse.conversationId; + // await saveMessage(userMessage); delete gptResponse.response; } diff --git a/client/src/components/Conversations/Conversation.jsx b/client/src/components/Conversations/Conversation.jsx index 9e5c3dce6d..5d503372fd 100644 --- a/client/src/components/Conversations/Conversation.jsx +++ b/client/src/components/Conversations/Conversation.jsx @@ -58,7 +58,8 @@ export default function Conversation({ jailbreakConversationId, conversationSignature, clientId, - invocationId + invocationId, + latestMessage: null }) ); } else { @@ -69,7 +70,8 @@ export default function Conversation({ jailbreakConversationId: null, conversationSignature: null, clientId: null, - invocationId: null + invocationId: null, + latestMessage: null }) ); } diff --git a/client/src/components/Main/TextChat.jsx b/client/src/components/Main/TextChat.jsx index 9221e67090..e6bd79c8f0 100644 --- a/client/src/components/Main/TextChat.jsx +++ b/client/src/components/Main/TextChat.jsx @@ -7,11 +7,14 @@ 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 { setMessages } from '~/store/messageSlice'; import { setSubmitState, setSubmission } from '~/store/submitSlice'; import { setText } from '~/store/textSlice'; +import { useMessageHandler } from '../../utils/handleSubmit' export default function TextChat({ messages }) { const [errorMessage, setErrorMessage] = useState(''); @@ -24,7 +27,8 @@ export default function TextChat({ messages }) { const { isSubmitting, stopStream, submission, disabled, model, chatGptLabel, promptPrefix } = useSelector((state) => state.submit); const { text } = useSelector((state) => state.text); - const { error } = convo; + const { error, latestMessage } = convo; + const { ask, regenerate } = useMessageHandler(); // auto focus to input, when enter a conversation. useEffect(() => { @@ -32,9 +36,12 @@ export default function TextChat({ messages }) { }, [convo?.conversationId,]) const messageHandler = (data, currentState, currentMsg) => { - const { messages, _currentMsg, message, sender } = currentState; + const { messages, _currentMsg, message, sender, isRegenerate } = currentState; - dispatch(setMessages([...messages, currentMsg, { sender, text: data, parentMessageId: currentMsg?.messageId, messageId: currentMsg?.messageId + '_', submitting: true }])); + if (isRegenerate) + dispatch(setMessages([...messages, { sender, text: data, parentMessageId: message?.overrideParentMessageId, messageId: message?.overrideParentMessageId + '_', submitting: true }])); + else + dispatch(setMessages([...messages, currentMsg, { sender, text: data, parentMessageId: currentMsg?.messageId, messageId: currentMsg?.messageId + '_', submitting: true }])); }; const createdHandler = (data, currentState, currentMsg) => { @@ -42,6 +49,7 @@ export default function TextChat({ messages }) { dispatch( setConversation({ conversationId, + latestMessage: null }) ); }; @@ -49,12 +57,17 @@ export default function TextChat({ messages }) { const convoHandler = (data, currentState, currentMsg) => { const { requestMessage, responseMessage } = data; const { conversationId } = requestMessage; - const { messages, _currentMsg, message, isCustomModel, sender } = + const { messages, _currentMsg, message, isCustomModel, sender, isRegenerate } = currentState; const { model, chatGptLabel, promptPrefix } = message; - dispatch( - setMessages([...messages, requestMessage, responseMessage,]) - ); + if (isRegenerate) + dispatch( + setMessages([...messages, responseMessage,]) + ); + else + dispatch( + setMessages([...messages, requestMessage, responseMessage,]) + ); const isBing = model === 'bingai' || model === 'sydney'; @@ -82,7 +95,8 @@ export default function TextChat({ messages }) { clientId: null, invocationId: null, chatGptLabel: model === isCustomModel ? chatGptLabel : null, - promptPrefix: model === isCustomModel ? promptPrefix : null + promptPrefix: model === isCustomModel ? promptPrefix : null, + latestMessage: null }) ); } else if ( @@ -98,7 +112,8 @@ export default function TextChat({ messages }) { conversationSignature, clientId, conversationId, - invocationId + invocationId, + latestMessage: null }) ); } else if (model === 'sydney') { @@ -119,7 +134,8 @@ export default function TextChat({ messages }) { conversationSignature, clientId, conversationId, - invocationId + invocationId, + latestMessage: null }) ); } @@ -142,51 +158,8 @@ export default function TextChat({ messages }) { dispatch(setError(true)); return; }; - const submitMessage = () => { - if (error) { - dispatch(setError(false)); - } - - if (!!isSubmitting || text.trim() === '') { - return; - } - - // this is not a real messageId, it is used as placeholder before real messageId returned - const fakeMessageId = crypto.randomUUID(); - const isCustomModel = model === 'chatgptCustom' || !initial[model]; - const message = text.trim(); - const sender = model === 'chatgptCustom' ? chatGptLabel : model; - let parentMessageId = convo.parentMessageId || '00000000-0000-0000-0000-000000000000'; - let currentMessages = messages; - if (resetConvo(currentMessages, sender)) { - parentMessageId = '00000000-0000-0000-0000-000000000000'; - dispatch(setNewConvo()); - currentMessages = []; - } - const currentMsg = { sender: 'User', text: message, current: true, isCreatedByUser: true, parentMessageId , messageId: fakeMessageId }; - const initialResponse = { sender, text: '', parentMessageId: fakeMessageId, submitting: true }; - - dispatch(setSubmitState(true)); - dispatch(setMessages([...currentMessages, currentMsg, initialResponse])); - dispatch(setText('')); - - const submission = { - convo, - isCustomModel, - message: { - ...currentMsg, - model, - chatGptLabel, - promptPrefix, - }, - messages: currentMessages, - currentMsg, - initialResponse, - sender, - }; - console.log('User Input:', message); - dispatch(setSubmission(submission)); + ask({ text }) }; useEffect(() => { @@ -196,7 +169,8 @@ export default function TextChat({ messages }) { } const currentState = submission; - let currentMsg = currentState.currentMsg; + let currentMsg = {...currentState.message}; + const { server, payload } = createPayload(submission); const onMessage = (e) => { if (stopStream) { @@ -252,6 +226,11 @@ export default function TextChat({ messages }) { }; }, [submission]); + const handleRegenerate = () => { + if (latestMessage&&!latestMessage?.isCreatedByUser) + regenerate(latestMessage) + } + const handleKeyDown = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); @@ -307,32 +286,56 @@ export default function TextChat({ messages }) { errorMessage={errorMessage} /> ) : ( -