Download api/server/middleware/abortMiddleware.js from Zhitomir/chat: direct link, hf CLI and curl.
- Browser
- Download file 6.05 kB
-
https://huggingface.co/spaces/Zhitomir/chat/resolve/main/api/server/middleware/abortMiddleware.js
- Command line
-
hf download hf://spaces/Zhitomir/chat/api/server/middleware/abortMiddleware.js
-
curl -L -o abortMiddleware.js https://huggingface.co/spaces/Zhitomir/chat/resolve/main/api/server/middleware/abortMiddleware.js
6.05 kB
| const { isAssistantsEndpoint } = require('librechat-data-provider'); | |
| const { sendMessage, sendError, countTokens, isEnabled } = require('~/server/utils'); | |
| const { truncateText, smartTruncateText } = require('~/app/clients/prompts'); | |
| const { saveMessage, getConvo, getConvoTitle } = require('~/models'); | |
| const clearPendingReq = require('~/cache/clearPendingReq'); | |
| const abortControllers = require('./abortControllers'); | |
| const spendTokens = require('~/models/spendTokens'); | |
| const { abortRun } = require('./abortRun'); | |
| const { logger } = require('~/config'); | |
| async function abortMessage(req, res) { | |
| let { abortKey, endpoint } = req.body; | |
| if (isAssistantsEndpoint(endpoint)) { | |
| return await abortRun(req, res); | |
| } | |
| const conversationId = abortKey?.split(':')?.[0] ?? req.user.id; | |
| if (!abortControllers.has(abortKey) && abortControllers.has(conversationId)) { | |
| abortKey = conversationId; | |
| } | |
| if (!abortControllers.has(abortKey) && !res.headersSent) { | |
| return res.status(204).send({ message: 'Request not found' }); | |
| } | |
| const { abortController } = abortControllers.get(abortKey) ?? {}; | |
| if (!abortController) { | |
| return res.status(204).send({ message: 'Request not found' }); | |
| } | |
| const finalEvent = await abortController.abortCompletion(); | |
| logger.info('[abortMessage] Aborted request', { abortKey }); | |
| abortControllers.delete(abortKey); | |
| if (res.headersSent && finalEvent) { | |
| return sendMessage(res, finalEvent); | |
| } | |
| res.setHeader('Content-Type', 'application/json'); | |
| res.send(JSON.stringify(finalEvent)); | |
| } | |
| const handleAbort = () => { | |
| return async (req, res) => { | |
| try { | |
| if (isEnabled(process.env.LIMIT_CONCURRENT_MESSAGES)) { | |
| await clearPendingReq({ userId: req.user.id }); | |
| } | |
| return await abortMessage(req, res); | |
| } catch (err) { | |
| logger.error('[abortMessage] handleAbort error', err); | |
| } | |
| }; | |
| }; | |
| const createAbortController = (req, res, getAbortData, getReqData) => { | |
| const abortController = new AbortController(); | |
| const { endpointOption } = req.body; | |
| abortController.getAbortData = function () { | |
| return getAbortData(); | |
| }; | |
| /** | |
| * @param {TMessage} userMessage | |
| * @param {string} responseMessageId | |
| */ | |
| const onStart = (userMessage, responseMessageId) => { | |
| sendMessage(res, { message: userMessage, created: true }); | |
| const abortKey = userMessage?.conversationId ?? req.user.id; | |
| const prevRequest = abortControllers.get(abortKey); | |
| if (prevRequest && prevRequest?.abortController) { | |
| const data = prevRequest.abortController.getAbortData(); | |
| getReqData({ userMessage: data?.userMessage }); | |
| const addedAbortKey = `${abortKey}:${responseMessageId}`; | |
| abortControllers.set(addedAbortKey, { abortController, ...endpointOption }); | |
| res.on('finish', function () { | |
| abortControllers.delete(addedAbortKey); | |
| }); | |
| return; | |
| } | |
| abortControllers.set(abortKey, { abortController, ...endpointOption }); | |
| res.on('finish', function () { | |
| abortControllers.delete(abortKey); | |
| }); | |
| }; | |
| abortController.abortCompletion = async function () { | |
| abortController.abort(); | |
| const { conversationId, userMessage, promptTokens, ...responseData } = getAbortData(); | |
| const completionTokens = await countTokens(responseData?.text ?? ''); | |
| const user = req.user.id; | |
| const responseMessage = { | |
| ...responseData, | |
| conversationId, | |
| finish_reason: 'incomplete', | |
| endpoint: endpointOption.endpoint, | |
| iconURL: endpointOption.iconURL, | |
| model: endpointOption.modelOptions.model, | |
| unfinished: false, | |
| error: false, | |
| isCreatedByUser: false, | |
| tokenCount: completionTokens, | |
| }; | |
| await spendTokens( | |
| { ...responseMessage, context: 'incomplete', user }, | |
| { promptTokens, completionTokens }, | |
| ); | |
| saveMessage({ ...responseMessage, user }); | |
| return { | |
| title: await getConvoTitle(user, conversationId), | |
| final: true, | |
| conversation: await getConvo(user, conversationId), | |
| requestMessage: userMessage, | |
| responseMessage: responseMessage, | |
| }; | |
| }; | |
| return { abortController, onStart }; | |
| }; | |
| const handleAbortError = async (res, req, error, data) => { | |
| if (error?.message?.includes('base64')) { | |
| logger.error('[handleAbortError] Error in base64 encoding', { | |
| ...error, | |
| stack: smartTruncateText(error?.stack, 1000), | |
| message: truncateText(error.message, 350), | |
| }); | |
| } else { | |
| logger.error('[handleAbortError] AI response error; aborting request:', error); | |
| } | |
| const { sender, conversationId, messageId, parentMessageId, partialText } = data; | |
| if (error.stack && error.stack.includes('google')) { | |
| logger.warn( | |
| `AI Response error for conversation ${conversationId} likely caused by Google censor/filter`, | |
| ); | |
| } | |
| const errorText = error?.message?.includes('"type"') | |
| ? error.message | |
| : 'An error occurred while processing your request. Please contact the Admin.'; | |
| const respondWithError = async (partialText) => { | |
| let options = { | |
| sender, | |
| messageId, | |
| conversationId, | |
| parentMessageId, | |
| text: errorText, | |
| shouldSaveMessage: true, | |
| user: req.user.id, | |
| }; | |
| if (partialText) { | |
| options = { | |
| ...options, | |
| error: false, | |
| unfinished: true, | |
| text: partialText, | |
| }; | |
| } | |
| const callback = async () => { | |
| if (abortControllers.has(conversationId)) { | |
| const { abortController } = abortControllers.get(conversationId); | |
| abortController.abort(); | |
| abortControllers.delete(conversationId); | |
| } | |
| }; | |
| await sendError(res, options, callback); | |
| }; | |
| if (partialText && partialText.length > 5) { | |
| try { | |
| return await abortMessage(req, res); | |
| } catch (err) { | |
| logger.error('[handleAbortError] error while trying to abort message', err); | |
| return respondWithError(partialText); | |
| } | |
| } else { | |
| return respondWithError(); | |
| } | |
| }; | |
| module.exports = { | |
| handleAbort, | |
| createAbortController, | |
| handleAbortError, | |
| }; | |