mongodb-chatbot-server
Version:
A chatbot server for retrieval augmented generation (RAG).
168 lines • 8.05 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeConversationsRouter = exports.defaultAddMessageToConversationCustomData = exports.defaultCreateConversationCustomData = exports.rateLimitResponse = void 0;
const express_promise_router_1 = __importDefault(require("express-promise-router"));
const express_rate_limit_1 = require("express-rate-limit");
const express_slow_down_1 = __importDefault(require("express-slow-down"));
const validateRequestSchema_1 = __importDefault(require("../../middleware/validateRequestSchema"));
const commentMessage_1 = require("./commentMessage");
const rateMessage_1 = require("./rateMessage");
const createConversation_1 = require("./createConversation");
const addMessageToConversation_1 = require("./addMessageToConversation");
const requireRequestOrigin_1 = require("../../middleware/requireRequestOrigin");
const middleware_1 = require("../../middleware");
const getConversation_1 = require("./getConversation");
exports.rateLimitResponse = {
error: "Too many requests, please try again later.",
};
function keyGenerator(request) {
if (!request.ip) {
throw new Error("Request IP is not defined");
}
return request.ip;
}
const addIpToCustomData = async (req) => req.ip
? {
ip: req.ip,
}
: undefined;
const addOriginToCustomData = async (_, res) => res.locals.customData.origin
? {
origin: res.locals.customData.origin,
}
: undefined;
const addUserAgentToCustomData = async (req) => req.headers["user-agent"]
? {
userAgent: req.headers["user-agent"],
}
: undefined;
const defaultCreateConversationCustomData = async (req, res) => {
return {
...(await addIpToCustomData(req, res)),
...(await addOriginToCustomData(req, res)),
...(await addUserAgentToCustomData(req, res)),
};
};
exports.defaultCreateConversationCustomData = defaultCreateConversationCustomData;
const defaultAddMessageToConversationCustomData = async (req, res) => {
return {
...(await addIpToCustomData(req, res)),
...(await addOriginToCustomData(req, res)),
...(await addUserAgentToCustomData(req, res)),
};
};
exports.defaultAddMessageToConversationCustomData = defaultAddMessageToConversationCustomData;
/**
Constructor function to make the /conversations/* Express.js router.
*/
function makeConversationsRouter({ llm, conversations, systemPrompt, maxInputLengthCharacters, maxUserMessagesInConversation, filterPreviousMessages, rateLimitConfig, generateUserPrompt, middleware = [(0, middleware_1.requireValidIpAddress)(), (0, requireRequestOrigin_1.requireRequestOrigin)()], createConversationCustomData = exports.defaultCreateConversationCustomData, addMessageToConversationCustomData = exports.defaultAddMessageToConversationCustomData, addMessageToConversationUpdateTrace, rateMessageUpdateTrace, commentMessageUpdateTrace, maxUserCommentLength, createConversationOnNullMessageId = true, braintrustLogger, }) {
const conversationsRouter = (0, express_promise_router_1.default)();
// Set the customData and conversations on the response locals
// for use in subsequent middleware.
conversationsRouter.use(((_, res, next) => {
res.locals.conversations = conversations;
res.locals.customData = {};
next();
}));
// Add middleware to the conversationsRouter.
middleware?.forEach((middleware) => conversationsRouter.use(middleware));
/*
Global rate limit the requests to the conversationsRouter.
*/
const globalRateLimit = (0, express_rate_limit_1.rateLimit)({
windowMs: 5 * 60 * 1000,
max: 5000,
standardHeaders: "draft-7", // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
legacyHeaders: true, // X-RateLimit-* headers
message: exports.rateLimitResponse,
keyGenerator,
...(rateLimitConfig?.routerRateLimitConfig ?? {}),
});
conversationsRouter.use(globalRateLimit);
/*
Slow down the response to the conversationsRouter after certain number
of requests in the time window.
*/
const globalSlowDown = (0, express_slow_down_1.default)({
windowMs: 60 * 1000,
delayAfter: 20,
delayMs: 500,
keyGenerator,
...(rateLimitConfig?.routerSlowDownConfig ?? {}),
});
conversationsRouter.use(globalSlowDown);
// Create new conversation.
conversationsRouter.post("/", (0, validateRequestSchema_1.default)(createConversation_1.CreateConversationRequest), (0, createConversation_1.makeCreateConversationRoute)({
conversations,
createConversationCustomData,
systemPrompt,
}));
/*
Rate limit the requests to the addMessageToConversationRoute.
Rate limit should be more restrictive than global rate limiter to limit expensive requests to the LLM.
*/
const addMessageRateLimit = (0, express_rate_limit_1.rateLimit)({
windowMs: 5 * 60 * 1000,
max: 2500,
standardHeaders: "draft-7", // draft-6: RateLimit-* headers; draft-7: combined RateLimit header
legacyHeaders: true, // X-RateLimit-* headers
message: exports.rateLimitResponse,
keyGenerator,
...(rateLimitConfig?.addMessageRateLimitConfig ?? {}),
});
/*
Slow down the response to the addMessageToConversationRoute after certain number
of requests in the time window. Rate limit should be more restrictive than global slow down
to limit expensive requests to the LLM.
*/
const addMessageSlowDown = (0, express_slow_down_1.default)({
windowMs: 60 * 1000,
delayAfter: 10,
delayMs: 1500,
keyGenerator,
...(rateLimitConfig?.addMessageSlowDownConfig ?? {}),
});
/*
Create a new message from the user and get response from the LLM.
*/
const addMessageToConversationRoute = (0, addMessageToConversation_1.makeAddMessageToConversationRoute)({
conversations,
llm,
maxInputLengthCharacters,
maxUserMessagesInConversation,
addMessageToConversationCustomData,
generateUserPrompt,
filterPreviousMessages,
createConversation: createConversationOnNullMessageId
? {
createOnNullConversationId: createConversationOnNullMessageId,
addCustomData: createConversationCustomData,
systemMessage: systemPrompt,
}
: undefined,
updateTrace: addMessageToConversationUpdateTrace,
braintrustLogger,
});
conversationsRouter.post("/:conversationId/messages", addMessageRateLimit, addMessageSlowDown, (0, validateRequestSchema_1.default)(addMessageToConversation_1.AddMessageRequest), addMessageToConversationRoute);
// Get conversations by conversation ID.
conversationsRouter.get("/:conversationId", (0, validateRequestSchema_1.default)(getConversation_1.GetConversationRequest), (0, getConversation_1.makeGetConversationRoute)({ conversations }));
// Rate a message.
conversationsRouter.post("/:conversationId/messages/:messageId/rating", (0, validateRequestSchema_1.default)(rateMessage_1.RateMessageRequest), (0, rateMessage_1.makeRateMessageRoute)({
conversations,
updateTrace: rateMessageUpdateTrace,
braintrustLogger,
}));
// Comment on a message.
conversationsRouter.post("/:conversationId/messages/:messageId/comment", (0, validateRequestSchema_1.default)(commentMessage_1.CommentMessageRequest), (0, commentMessage_1.makeCommentMessageRoute)({
conversations,
maxCommentLength: maxUserCommentLength,
updateTrace: commentMessageUpdateTrace,
braintrustLogger,
}));
return conversationsRouter;
}
exports.makeConversationsRouter = makeConversationsRouter;
//# sourceMappingURL=conversationsRouter.js.map