diff --git a/api/models/Conversation.js b/api/models/Conversation.js
index d2ead788d2..a32bc3e7a4 100644
--- a/api/models/Conversation.js
+++ b/api/models/Conversation.js
@@ -57,13 +57,16 @@ const getConvo = async (conversationId) => {
};
module.exports = {
- saveConvo: async ({ conversationId, title, ...convo }) => {
+ saveConvo: async ({ conversationId, newConversationId, title, ...convo }) => {
try {
const messages = await getMessages({ conversationId });
const update = { ...convo, messages };
if (title) {
update.title = title;
}
+ if (newConversationId) {
+ update.conversationId = newConversationId;
+ }
if (!update.jailbreakConversationId)
update.jailbreakConversationId = null
diff --git a/api/server/routes/ask.js b/api/server/routes/ask.js
index 73b85b8012..d12ee17b4e 100644
--- a/api/server/routes/ask.js
+++ b/api/server/routes/ask.js
@@ -12,12 +12,13 @@ const {
} = require('../../app/');
const { getConvo, saveMessage, getConvoTitle, saveConvo } = require('../../models');
const { handleError, sendMessage } = require('./handlers');
+const { getMessages } = require('../../models/Message');
router.use('/bing', askBing);
router.use('/sydney', askSydney);
router.post('/', async (req, res) => {
- let { model, text, parentMessageId, conversationId: oldConversationId , chatGptLabel, promptPrefix } = req.body;
+ let { model, text, parentMessageId, conversationId: oldConversationId , ...convo } = req.body;
if (text.length === 0) {
return handleError(res, { text: 'Prompt empty or too short' });
}
@@ -27,21 +28,94 @@ router.post('/', async (req, res) => {
const userMessageId = crypto.randomUUID();
const userParentMessageId = parentMessageId || '00000000-0000-0000-0000-000000000000'
let userMessage = {
- messageId: userMessageId,
- sender: 'User',
- text,
- parentMessageId: userParentMessageId,
- conversationId,
- isCreatedByUser: true
+ messageId: userMessageId,
+ sender: 'User',
+ text,
+ parentMessageId: userParentMessageId,
+ conversationId,
+ isCreatedByUser: true
};
console.log('ask log', {
model,
...userMessage,
- chatGptLabel,
- promptPrefix
+ ...convo
});
+ // if (model === 'chatgptCustom' && !chatGptLabel && conversationId) {
+ // const convo = await getConvo({ conversationId });
+ // if (convo) {
+ // console.log('found convo for custom gpt', { convo })
+ // chatGptLabel = convo.chatGptLabel;
+ // promptPrefix = convo.promptPrefix;
+ // }
+ // }
+
+ await saveMessage(userMessage);
+ await saveConvo({ ...userMessage, model, ...convo });
+
+ return await ask({
+ userMessage,
+ model,
+ convo,
+ preSendRequest: true,
+ req, res
+ });
+})
+
+router.post('/regenerate', async (req, res) => {
+ const { parentMessageId, model, chatGptLabel, promptPrefix } = 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' });
+
+ // if (model === 'chatgptCustom' && !chatGptLabel && conversationId) {
+ // const convo = await getConvo({ conversationId });
+ // if (convo) {
+ // console.log('found convo for custom gpt', { convo })
+ // chatGptLabel = convo.chatGptLabel;
+ // promptPrefix = convo.promptPrefix;
+ // }
+ // }
+
+ // await saveConvo({ ...userMessage, model, chatGptLabel, promptPrefix });
+});
+
+const ask = async ({
+ userMessage,
+ overrideParentMessageId = null,
+ model,
+ convo,
+ preSendRequest = true,
+ req, res
+}) => {
+ let { sender, text, parentMessageId: userParentMessageId, conversationId, messageId: userMessageId } = userMessage;
+
let client;
if (model === 'chatgpt') {
@@ -52,15 +126,6 @@ router.post('/', async (req, res) => {
client = browserClient;
}
- if (model === 'chatgptCustom' && !chatGptLabel && conversationId) {
- const convo = await getConvo({ conversationId });
- if (convo) {
- console.log('found convo for custom gpt', { convo })
- chatGptLabel = convo.chatGptLabel;
- promptPrefix = convo.promptPrefix;
- }
- }
-
res.writeHead(200, {
Connection: 'keep-alive',
'Content-Type': 'text/event-stream',
@@ -69,9 +134,8 @@ router.post('/', async (req, res) => {
'X-Accel-Buffering': 'no'
});
- await saveMessage(userMessage);
- await saveConvo({ ...userMessage, model, chatGptLabel, promptPrefix });
- sendMessage(res, { message: userMessage, created: true });
+ if (preSendRequest)
+ sendMessage(res, { message: userMessage, created: true });
try {
let i = 0;
@@ -80,12 +144,12 @@ router.post('/', async (req, res) => {
if (i === 0 && typeof partial === 'object') {
userMessage.conversationId = conversationId ? conversationId : partial.conversationId;
await saveMessage(userMessage);
- sendMessage(res, { ...partial, initial: true });
+ sendMessage(res, { ...partial, parentMessageId: overrideParentMessageId || userMessageId, initial: true });
i++;
}
if (typeof partial === 'object') {
- sendMessage(res, { ...partial, message: true });
+ sendMessage(res, { ...partial, parentMessageId: overrideParentMessageId || userMessageId, message: true });
} else {
tokens += partial === text ? '' : partial;
if (tokens.match(/^\n/)) {
@@ -107,10 +171,10 @@ router.post('/', async (req, res) => {
progressCallback,
convo: {
parentMessageId: userParentMessageId,
- conversationId
+ conversationId,
+ ...convo
},
- chatGptLabel,
- promptPrefix
+ ...convo
});
console.log('CLIENT RESPONSE', gptResponse);
@@ -118,7 +182,7 @@ router.post('/', async (req, res) => {
if (!gptResponse.parentMessageId) {
gptResponse.text = gptResponse.response;
// gptResponse.id = gptResponse.messageId;
- gptResponse.parentMessageId = userMessage.messageId;
+ gptResponse.parentMessageId = overrideParentMessageId || userMessageId;
userMessage.conversationId = conversationId
? conversationId
: gptResponse.conversationId;
@@ -133,23 +197,26 @@ router.post('/', async (req, res) => {
) {
await saveMessage({
messageId: crypto.randomUUID(), sender: model,
- conversationId, parentMessageId: userMessageId,
+ conversationId, parentMessageId: overrideParentMessageId || userMessageId,
error: true, text: 'Prompt empty or too short'});
return handleError(res, { text: 'Prompt empty or too short' });
}
- gptResponse.sender = model === 'chatgptCustom' ? chatGptLabel : model;
+ gptResponse.sender = model === 'chatgptCustom' ? convo.chatGptLabel : model;
// gptResponse.final = true;
gptResponse.text = await detectCode(gptResponse.text);
- if (chatGptLabel?.length > 0 && model === 'chatgptCustom') {
- gptResponse.chatGptLabel = chatGptLabel;
+ if (convo.chatGptLabel?.length > 0 && model === 'chatgptCustom') {
+ gptResponse.chatGptLabel = convo.chatGptLabel;
}
- if (promptPrefix?.length > 0 && model === 'chatgptCustom') {
- gptResponse.promptPrefix = promptPrefix;
+ if (convo.promptPrefix?.length > 0 && model === 'chatgptCustom') {
+ gptResponse.promptPrefix = convo.promptPrefix;
}
+ // override the parentMessageId, for the regeneration.
+ gptResponse.parentMessageId = overrideParentMessageId || userMessageId
+
await saveMessage(gptResponse);
await saveConvo(gptResponse);
sendMessage(res, {
@@ -160,7 +227,7 @@ router.post('/', async (req, res) => {
});
res.end();
- if (parentMessageId == '00000000-0000-0000-0000-000000000000') {
+ if (userParentMessageId == '00000000-0000-0000-0000-000000000000') {
const title = await titleConvo({
model,
message: text,
@@ -184,6 +251,6 @@ router.post('/', async (req, res) => {
await saveMessage(errorMessage);
handleError(res, errorMessage);
}
-});
+};
module.exports = router;
diff --git a/api/server/routes/askBing.js b/api/server/routes/askBing.js
index ffe8f2ae6d..1871e96f40 100644
--- a/api/server/routes/askBing.js
+++ b/api/server/routes/askBing.js
@@ -13,6 +13,7 @@ router.post('/', async (req, res) => {
}
const conversationId = oldConversationId || crypto.randomUUID();
+ const isNewConversation = !oldConversationId
const userMessageId = crypto.randomUUID();
const userParentMessageId = parentMessageId || '00000000-0000-0000-0000-000000000000'
@@ -31,6 +32,30 @@ router.post('/', async (req, res) => {
...convo
});
+ await saveMessage(userMessage);
+ await saveConvo({ ...userMessage, model, ...convo });
+
+ return await ask({
+ isNewConversation,
+ userMessage,
+ model,
+ convo,
+ preSendRequest: true,
+ req, res
+ });
+})
+
+const ask = async ({
+ isNewConversation,
+ overrideParentMessageId = null,
+ userMessage,
+ model,
+ convo,
+ preSendRequest = true,
+ req, res
+}) => {
+ let { sender, text, parentMessageId: userParentMessageId, conversationId, messageId: userMessageId } = userMessage;
+
res.writeHead(200, {
Connection: 'keep-alive',
'Content-Type': 'text/event-stream',
@@ -39,9 +64,8 @@ router.post('/', async (req, res) => {
'X-Accel-Buffering': 'no'
});
- await saveMessage(userMessage);
- await saveConvo({ ...userMessage, model, chatGptLabel, promptPrefix });
- sendMessage(res, { message: userMessage, created: true });
+ if (preSendRequest)
+ sendMessage(res, { message: userMessage, created: true });
try {
let tokens = '';
@@ -49,28 +73,36 @@ router.post('/', async (req, res) => {
tokens += partial === text ? '' : partial;
// tokens = appendCode(tokens);
tokens = citeText(tokens, true);
- sendMessage(res, { text: tokens, message: true });
+ sendMessage(res, { text: tokens, message: true, parentMessageId: overrideParentMessageId || userMessageId });
};
let response = await askBing({
text,
progressCallback,
convo: {
+ ...convo,
parentMessageId: userParentMessageId,
conversationId,
- ...convo
},
});
- console.log('BING RESPONSE');
+ console.log('BING RESPONSE', response);
// console.dir(response, { depth: null });
const hasCitations = response.response.match(citationRegex)?.length > 0;
userMessage.conversationSignature =
convo.conversationSignature || response.conversationSignature;
- userMessage.conversationId = conversationId || response.conversationId;
+ userMessage.conversationId = response.conversationId || conversationId;
userMessage.invocationId = response.invocationId;
await saveMessage(userMessage);
+
+ // Bing API will not use our conversationId at the first time,
+ // so change the placeholder conversationId to the real one.
+ // Attition: the api will also create new conversationId while using invalid userMessage.parentMessageId,
+ // but in this situation, don't change the conversationId, but create new convo.
+ if (conversationId != userMessage.conversationId && isNewConversation)
+ await saveConvo({ conversationId: conversationId, newConversationId: userMessage.conversationId });
+ conversationId = userMessage.conversationId;
response.text = response.response;
delete response.response;
@@ -79,29 +111,31 @@ router.post('/', async (req, res) => {
response.details.suggestedResponses &&
response.details.suggestedResponses.map((s) => s.text);
response.sender = model;
- response.parentMessageId = gptResponse.parentMessageId || userMessage.messageId
// response.final = true;
+ // override the parentMessageId, for the regeneration.
+ response.parentMessageId = overrideParentMessageId || response.parentMessageId || userMessageId;
+
const links = getCitations(response);
response.text =
citeText(response) +
(links?.length > 0 && hasCitations ? `\n${links}` : '');
await saveMessage(response);
- await saveConvo(response);
+ await saveConvo({...response, model, ...convo});
sendMessage(res, {
title: await getConvoTitle(conversationId),
final: true,
requestMessage: userMessage,
- responseMessage: gptResponse
+ responseMessage: response
});
res.end();
- if (parentMessageId == '00000000-0000-0000-0000-000000000000') {
+ if (userParentMessageId == '00000000-0000-0000-0000-000000000000') {
const title = await titleConvo({
model,
message: text,
- response: JSON.stringify(gptResponse?.text)
+ response: JSON.stringify(response?.text)
});
console.log('CONVERSATION TITLE', title);
@@ -121,6 +155,6 @@ router.post('/', async (req, res) => {
await saveMessage(errorMessage);
handleError(res, errorMessage);
}
-});
+};
module.exports = router;
diff --git a/api/server/routes/askSydney.js b/api/server/routes/askSydney.js
index 20f6c302b3..3a663184b6 100644
--- a/api/server/routes/askSydney.js
+++ b/api/server/routes/askSydney.js
@@ -13,6 +13,7 @@ router.post('/', async (req, res) => {
}
const conversationId = oldConversationId || crypto.randomUUID();
+ const isNewConversation = !oldConversationId
const userMessageId = crypto.randomUUID();
const userParentMessageId = parentMessageId || '00000000-0000-0000-0000-000000000000'
@@ -25,13 +26,36 @@ router.post('/', async (req, res) => {
isCreatedByUser: true
};
-
console.log('ask log', {
model,
...userMessage,
...convo
});
+ await saveMessage(userMessage);
+ await saveConvo({ ...userMessage, model, ...convo });
+
+ return await ask({
+ isNewConversation,
+ userMessage,
+ model,
+ convo,
+ preSendRequest: true,
+ req, res
+ });
+})
+
+const ask = async ({
+ isNewConversation,
+ overrideParentMessageId = null,
+ userMessage,
+ model,
+ convo,
+ preSendRequest = true,
+ req, res
+}) => {
+ let { sender, text, parentMessageId: userParentMessageId, conversationId, messageId: userMessageId } = userMessage;
+
res.writeHead(200, {
Connection: 'keep-alive',
'Content-Type': 'text/event-stream',
@@ -40,9 +64,8 @@ router.post('/', async (req, res) => {
'X-Accel-Buffering': 'no'
});
- await saveMessage(userMessage);
- await saveConvo({ ...userMessage, model, chatGptLabel, promptPrefix });
- sendMessage(res, { message: userMessage, created: true });
+ if (preSendRequest)
+ sendMessage(res, { message: userMessage, created: true });
try {
let tokens = '';
@@ -50,7 +73,7 @@ router.post('/', async (req, res) => {
tokens += partial === text ? '' : partial;
// tokens = appendCode(tokens);
tokens = citeText(tokens, true);
- sendMessage(res, { text: tokens, message: true });
+ sendMessage(res, { text: tokens, message: true, parentMessageId: overrideParentMessageId || userMessageId });
};
let response = await askSydney({
@@ -63,15 +86,19 @@ router.post('/', async (req, res) => {
},
});
- console.log('SYDNEY RESPONSE');
- console.log(response.response);
+ console.log('SYDNEY RESPONSE', response);
// console.dir(response, { depth: null });
const hasCitations = response.response.match(citationRegex)?.length > 0;
+ userMessage.conversationSignature =
+ convo.conversationSignature || response.conversationSignature;
+ userMessage.conversationId = response.conversationId || conversationId;
+ userMessage.invocationId = response.invocationId;
+ // Unlike gpt and bing, Sydney will never accept our given userMessage.messageId, it will generate its own one.
+ await saveMessage(userMessage);
+
// Save sydney response
// response.id = response.messageId;
- // response.parentMessageId = convo.parentMessageId ? convo.parentMessageId : response.messageId;
- response.parentMessageId = response.messageId;
response.invocationId = convo.invocationId ? convo.invocationId + 1 : 1;
response.conversationId = conversationId
? conversationId
@@ -85,34 +112,44 @@ router.post('/', async (req, res) => {
response.details.suggestedResponses &&
response.details.suggestedResponses.map((s) => s.text);
response.sender = model;
- response.parentMessageId = gptResponse.parentMessageId || userMessage.messageId
// response.final = true;
+ // override the parentMessageId, for the regeneration.
+ response.parentMessageId = overrideParentMessageId || response.parentMessageId || userMessageId;
+
const links = getCitations(response);
response.text =
citeText(response) +
(links?.length > 0 && hasCitations ? `\n${links}` : '');
// Save user message
- userMessage.conversationId = response.conversationId;
+ userMessage.conversationId = response.conversationId || conversationId;
await saveMessage(userMessage);
+ // Bing API will not use our conversationId at the first time,
+ // so change the placeholder conversationId to the real one.
+ // Attition: the api will also create new conversationId while using invalid userMessage.parentMessageId,
+ // but in this situation, don't change the conversationId, but create new convo.
+ if (conversationId != userMessage.conversationId && isNewConversation)
+ await saveConvo({ conversationId: conversationId, newConversationId: userMessage.conversationId });
+ conversationId = userMessage.conversationId;
+
// Save sydney response & convo, then send
await saveMessage(response);
- await saveConvo(response);
+ await saveConvo({...response, model, ...convo});
sendMessage(res, {
title: await getConvoTitle(conversationId),
final: true,
requestMessage: userMessage,
- responseMessage: gptResponse
+ responseMessage: response
});
res.end();
- if (parentMessageId == '00000000-0000-0000-0000-000000000000') {
+ if (userParentMessageId == '00000000-0000-0000-0000-000000000000') {
const title = await titleConvo({
model,
message: text,
- response: JSON.stringify(gptResponse?.text)
+ response: JSON.stringify(response?.text)
});
console.log('CONVERSATION TITLE', title);
@@ -132,6 +169,6 @@ router.post('/', async (req, res) => {
await saveMessage(errorMessage);
handleError(res, errorMessage);
}
-});
+};
module.exports = router;
diff --git a/client/src/components/Main/TextChat.jsx b/client/src/components/Main/TextChat.jsx
index 8ed3576661..8f1276fce6 100644
--- a/client/src/components/Main/TextChat.jsx
+++ b/client/src/components/Main/TextChat.jsx
@@ -49,7 +49,7 @@ export default function TextChat({ messages }) {
const convoHandler = (data, currentState, currentMsg) => {
const { requestMessage, responseMessage } = data;
- const { conversationId } = currentMsg;
+ const { conversationId } = requestMessage;
const { messages, _currentMsg, message, isCustomModel, sender } =
currentState;
const { model, chatGptLabel, promptPrefix } = message;
@@ -66,7 +66,7 @@ export default function TextChat({ messages }) {
// in case it takes too long.
setTimeout(() => {
- dispatch(refreshConversation());
+ dispatch(refreshConversation());
}, 5000);
}
@@ -87,9 +87,7 @@ export default function TextChat({ messages }) {
})
);
} else if (
- model === 'bingai' &&
- convo.conversationId === null &&
- convo.invocationId === null
+ model === 'bingai'
) {
console.log('Bing data:', data);
const { title } = data;