Spaces:
Runtime error
Runtime error
const express = require('express'); | |
const crypto = require('crypto'); | |
const router = express.Router(); | |
const { titleConvoBing, askBing } = require('../../../app'); | |
const { saveMessage, getConvoTitle, saveConvo, getConvo } = require('../../../models'); | |
const { handleError, sendMessage, createOnProgress, handleText } = require('./handlers'); | |
const requireJwtAuth = require('../../../middleware/requireJwtAuth'); | |
router.post('/', requireJwtAuth, async (req, res) => { | |
const { | |
endpoint, | |
text, | |
messageId, | |
overrideParentMessageId = null, | |
parentMessageId, | |
conversationId: oldConversationId, | |
} = req.body; | |
if (text.length === 0) { | |
return handleError(res, { text: 'Prompt empty or too short' }); | |
} | |
if (endpoint !== 'bingAI') { | |
return handleError(res, { text: 'Illegal request' }); | |
} | |
// build user message | |
const conversationId = oldConversationId || crypto.randomUUID(); | |
const isNewConversation = !oldConversationId; | |
const userMessageId = messageId; | |
const userParentMessageId = parentMessageId || '00000000-0000-0000-0000-000000000000'; | |
let userMessage = { | |
messageId: userMessageId, | |
sender: 'User', | |
text, | |
parentMessageId: userParentMessageId, | |
conversationId, | |
isCreatedByUser: true, | |
}; | |
// build endpoint option | |
let endpointOption = {}; | |
if (req.body?.jailbreak) { | |
endpointOption = { | |
jailbreak: req.body?.jailbreak ?? false, | |
jailbreakConversationId: req.body?.jailbreakConversationId ?? null, | |
systemMessage: req.body?.systemMessage ?? null, | |
context: req.body?.context ?? null, | |
toneStyle: req.body?.toneStyle ?? 'creative', | |
token: req.body?.token ?? null, | |
}; | |
} else { | |
endpointOption = { | |
jailbreak: req.body?.jailbreak ?? false, | |
systemMessage: req.body?.systemMessage ?? null, | |
context: req.body?.context ?? null, | |
conversationSignature: req.body?.conversationSignature ?? null, | |
clientId: req.body?.clientId ?? null, | |
invocationId: req.body?.invocationId ?? null, | |
toneStyle: req.body?.toneStyle ?? 'creative', | |
token: req.body?.token ?? null, | |
}; | |
} | |
console.log('ask log', { | |
userMessage, | |
endpointOption, | |
conversationId, | |
}); | |
if (!overrideParentMessageId) { | |
await saveMessage(userMessage); | |
await saveConvo(req.user.id, { | |
...userMessage, | |
...endpointOption, | |
conversationId, | |
endpoint, | |
}); | |
} | |
// eslint-disable-next-line no-use-before-define | |
return await ask({ | |
isNewConversation, | |
userMessage, | |
endpointOption, | |
conversationId, | |
preSendRequest: true, | |
overrideParentMessageId, | |
req, | |
res, | |
}); | |
}); | |
const ask = async ({ | |
isNewConversation, | |
userMessage, | |
endpointOption, | |
conversationId, | |
preSendRequest = true, | |
overrideParentMessageId = null, | |
req, | |
res, | |
}) => { | |
let { text, parentMessageId: userParentMessageId, messageId: userMessageId } = userMessage; | |
let responseMessageId = crypto.randomUUID(); | |
res.writeHead(200, { | |
Connection: 'keep-alive', | |
'Content-Type': 'text/event-stream', | |
'Cache-Control': 'no-cache, no-transform', | |
'Access-Control-Allow-Origin': '*', | |
'X-Accel-Buffering': 'no', | |
}); | |
if (preSendRequest) { | |
sendMessage(res, { message: userMessage, created: true }); | |
} | |
let lastSavedTimestamp = 0; | |
const { onProgress: progressCallback, getPartialText } = createOnProgress({ | |
onProgress: ({ text }) => { | |
const currentTimestamp = Date.now(); | |
if (currentTimestamp - lastSavedTimestamp > 500) { | |
lastSavedTimestamp = currentTimestamp; | |
saveMessage({ | |
messageId: responseMessageId, | |
sender: endpointOption?.jailbreak ? 'Sydney' : 'BingAI', | |
conversationId, | |
parentMessageId: overrideParentMessageId || userMessageId, | |
text: text, | |
unfinished: true, | |
cancelled: false, | |
error: false, | |
}); | |
} | |
}, | |
}); | |
const abortController = new AbortController(); | |
let bingConversationId = null; | |
if (!isNewConversation) { | |
const convo = await getConvo(req.user.id, conversationId); | |
bingConversationId = convo.bingConversationId; | |
} | |
try { | |
let response = await askBing({ | |
text, | |
parentMessageId: userParentMessageId, | |
conversationId: bingConversationId ?? conversationId, | |
...endpointOption, | |
onProgress: progressCallback.call(null, { | |
res, | |
text, | |
parentMessageId: overrideParentMessageId || userMessageId, | |
}), | |
abortController, | |
}); | |
console.log('BING RESPONSE', response); | |
const newConversationId = endpointOption?.jailbreak | |
? response.jailbreakConversationId | |
: response.conversationId || conversationId; | |
const newUserMessageId = | |
response.parentMessageId || response.details.requestId || userMessageId; | |
const newResponseMessageId = response.messageId || response.details.messageId; | |
// STEP1 generate response message | |
response.text = | |
response.response || response.details.spokenText || '**Bing refused to answer.**'; | |
const partialText = getPartialText(); | |
let unfinished = false; | |
if (partialText?.trim()?.length > response.text.length) { | |
response.text = partialText; | |
unfinished = false; | |
//setting "unfinished" to false fix bing image generation error msg and allows to continue a convo after being triggered by censorship (bing does remember the context after a "censored error" so there is no reason to end the convo) | |
} | |
let responseMessage = { | |
conversationId, | |
bingConversationId: newConversationId, | |
messageId: responseMessageId, | |
newMessageId: newResponseMessageId, | |
parentMessageId: overrideParentMessageId || newUserMessageId, | |
sender: endpointOption?.jailbreak ? 'Sydney' : 'BingAI', | |
text: await handleText(response, true), | |
suggestions: | |
response.details.suggestedResponses && | |
response.details.suggestedResponses.map((s) => s.text), | |
unfinished, | |
cancelled: false, | |
error: false, | |
}; | |
await saveMessage(responseMessage); | |
responseMessage.messageId = newResponseMessageId; | |
let conversationUpdate = { | |
conversationId, | |
bingConversationId: newConversationId, | |
endpoint: 'bingAI', | |
}; | |
if (endpointOption?.jailbreak) { | |
conversationUpdate.jailbreak = true; | |
conversationUpdate.jailbreakConversationId = response.jailbreakConversationId; | |
} else { | |
conversationUpdate.jailbreak = false; | |
conversationUpdate.conversationSignature = response.conversationSignature; | |
conversationUpdate.clientId = response.clientId; | |
conversationUpdate.invocationId = response.invocationId; | |
} | |
await saveConvo(req.user.id, conversationUpdate); | |
userMessage.messageId = newUserMessageId; | |
// If response has parentMessageId, the fake userMessage.messageId should be updated to the real one. | |
if (!overrideParentMessageId) { | |
await saveMessage({ | |
...userMessage, | |
messageId: userMessageId, | |
newMessageId: newUserMessageId, | |
}); | |
} | |
userMessageId = newUserMessageId; | |
sendMessage(res, { | |
title: await getConvoTitle(req.user.id, conversationId), | |
final: true, | |
conversation: await getConvo(req.user.id, conversationId), | |
requestMessage: userMessage, | |
responseMessage: responseMessage, | |
}); | |
res.end(); | |
if (userParentMessageId == '00000000-0000-0000-0000-000000000000') { | |
const title = await titleConvoBing({ | |
text, | |
response: responseMessage, | |
}); | |
await saveConvo(req.user.id, { | |
conversationId: conversationId, | |
title, | |
}); | |
} | |
} catch (error) { | |
console.error(error); | |
const partialText = getPartialText(); | |
if (partialText?.length > 2) { | |
const responseMessage = { | |
messageId: responseMessageId, | |
sender: endpointOption?.jailbreak ? 'Sydney' : 'BingAI', | |
conversationId, | |
parentMessageId: overrideParentMessageId || userMessageId, | |
text: partialText, | |
model: endpointOption.modelOptions.model, | |
unfinished: true, | |
cancelled: false, | |
error: false, | |
}; | |
saveMessage(responseMessage); | |
return { | |
title: await getConvoTitle(req.user.id, conversationId), | |
final: true, | |
conversation: await getConvo(req.user.id, conversationId), | |
requestMessage: userMessage, | |
responseMessage: responseMessage, | |
}; | |
} else { | |
console.log(error); | |
const errorMessage = { | |
messageId: responseMessageId, | |
sender: endpointOption?.jailbreak ? 'Sydney' : 'BingAI', | |
conversationId, | |
parentMessageId: overrideParentMessageId || userMessageId, | |
unfinished: false, | |
cancelled: false, | |
error: true, | |
text: error.message, | |
}; | |
await saveMessage(errorMessage); | |
handleError(res, errorMessage); | |
} | |
} | |
}; | |
module.exports = router; | |