| const { logger } = require('@librechat/data-schemas'); |
| const { ConversationTag, Conversation } = require('~/db/models'); |
|
|
| |
| |
| |
| |
| |
| const getConversationTags = async (user) => { |
| try { |
| return await ConversationTag.find({ user }).sort({ position: 1 }).lean(); |
| } catch (error) { |
| logger.error('[getConversationTags] Error getting conversation tags', error); |
| throw new Error('Error getting conversation tags'); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const createConversationTag = async (user, data) => { |
| try { |
| const { tag, description, addToConversation, conversationId } = data; |
|
|
| const existingTag = await ConversationTag.findOne({ user, tag }).lean(); |
| if (existingTag) { |
| return existingTag; |
| } |
|
|
| const maxPosition = await ConversationTag.findOne({ user }).sort('-position').lean(); |
| const position = (maxPosition?.position || 0) + 1; |
|
|
| const newTag = await ConversationTag.findOneAndUpdate( |
| { tag, user }, |
| { |
| tag, |
| user, |
| count: addToConversation ? 1 : 0, |
| position, |
| description, |
| $setOnInsert: { createdAt: new Date() }, |
| }, |
| { |
| new: true, |
| upsert: true, |
| lean: true, |
| }, |
| ); |
|
|
| if (addToConversation && conversationId) { |
| await Conversation.findOneAndUpdate( |
| { user, conversationId }, |
| { $addToSet: { tags: tag } }, |
| { new: true }, |
| ); |
| } |
|
|
| return newTag; |
| } catch (error) { |
| logger.error('[createConversationTag] Error creating conversation tag', error); |
| throw new Error('Error creating conversation tag'); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const updateConversationTag = async (user, oldTag, data) => { |
| try { |
| const { tag: newTag, description, position } = data; |
|
|
| const existingTag = await ConversationTag.findOne({ user, tag: oldTag }).lean(); |
| if (!existingTag) { |
| return null; |
| } |
|
|
| if (newTag && newTag !== oldTag) { |
| const tagAlreadyExists = await ConversationTag.findOne({ user, tag: newTag }).lean(); |
| if (tagAlreadyExists) { |
| throw new Error('Tag already exists'); |
| } |
|
|
| await Conversation.updateMany({ user, tags: oldTag }, { $set: { 'tags.$': newTag } }); |
| } |
|
|
| const updateData = {}; |
| if (newTag) { |
| updateData.tag = newTag; |
| } |
| if (description !== undefined) { |
| updateData.description = description; |
| } |
| if (position !== undefined) { |
| await adjustPositions(user, existingTag.position, position); |
| updateData.position = position; |
| } |
|
|
| return await ConversationTag.findOneAndUpdate({ user, tag: oldTag }, updateData, { |
| new: true, |
| lean: true, |
| }); |
| } catch (error) { |
| logger.error('[updateConversationTag] Error updating conversation tag', error); |
| throw new Error('Error updating conversation tag'); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| const adjustPositions = async (user, oldPosition, newPosition) => { |
| if (oldPosition === newPosition) { |
| return; |
| } |
|
|
| const update = oldPosition < newPosition ? { $inc: { position: -1 } } : { $inc: { position: 1 } }; |
| const position = |
| oldPosition < newPosition |
| ? { |
| $gt: Math.min(oldPosition, newPosition), |
| $lte: Math.max(oldPosition, newPosition), |
| } |
| : { |
| $gte: Math.min(oldPosition, newPosition), |
| $lt: Math.max(oldPosition, newPosition), |
| }; |
|
|
| await ConversationTag.updateMany( |
| { |
| user, |
| position, |
| }, |
| update, |
| ); |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| const deleteConversationTag = async (user, tag) => { |
| try { |
| const deletedTag = await ConversationTag.findOneAndDelete({ user, tag }).lean(); |
| if (!deletedTag) { |
| return null; |
| } |
|
|
| await Conversation.updateMany({ user, tags: tag }, { $pull: { tags: tag } }); |
|
|
| await ConversationTag.updateMany( |
| { user, position: { $gt: deletedTag.position } }, |
| { $inc: { position: -1 } }, |
| ); |
|
|
| return deletedTag; |
| } catch (error) { |
| logger.error('[deleteConversationTag] Error deleting conversation tag', error); |
| throw new Error('Error deleting conversation tag'); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| const updateTagsForConversation = async (user, conversationId, tags) => { |
| try { |
| const conversation = await Conversation.findOne({ user, conversationId }).lean(); |
| if (!conversation) { |
| throw new Error('Conversation not found'); |
| } |
|
|
| const oldTags = new Set(conversation.tags); |
| const newTags = new Set(tags); |
|
|
| const addedTags = [...newTags].filter((tag) => !oldTags.has(tag)); |
| const removedTags = [...oldTags].filter((tag) => !newTags.has(tag)); |
|
|
| const bulkOps = []; |
|
|
| for (const tag of addedTags) { |
| bulkOps.push({ |
| updateOne: { |
| filter: { user, tag }, |
| update: { $inc: { count: 1 } }, |
| upsert: true, |
| }, |
| }); |
| } |
|
|
| for (const tag of removedTags) { |
| bulkOps.push({ |
| updateOne: { |
| filter: { user, tag }, |
| update: { $inc: { count: -1 } }, |
| }, |
| }); |
| } |
|
|
| if (bulkOps.length > 0) { |
| await ConversationTag.bulkWrite(bulkOps); |
| } |
|
|
| const updatedConversation = ( |
| await Conversation.findOneAndUpdate( |
| { user, conversationId }, |
| { $set: { tags: [...newTags] } }, |
| { new: true }, |
| ) |
| ).toObject(); |
|
|
| return updatedConversation.tags; |
| } catch (error) { |
| logger.error('[updateTagsForConversation] Error updating tags', error); |
| throw new Error('Error updating tags for conversation'); |
| } |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| const bulkIncrementTagCounts = async (user, tags) => { |
| if (!tags || tags.length === 0) { |
| return; |
| } |
|
|
| try { |
| const uniqueTags = [...new Set(tags.filter(Boolean))]; |
| if (uniqueTags.length === 0) { |
| return; |
| } |
|
|
| const bulkOps = uniqueTags.map((tag) => ({ |
| updateOne: { |
| filter: { user, tag }, |
| update: { $inc: { count: 1 } }, |
| }, |
| })); |
|
|
| const result = await ConversationTag.bulkWrite(bulkOps); |
| if (result && result.modifiedCount > 0) { |
| logger.debug( |
| `user: ${user} | Incremented tag counts - modified ${result.modifiedCount} tags`, |
| ); |
| } |
| } catch (error) { |
| logger.error('[bulkIncrementTagCounts] Error incrementing tag counts', error); |
| } |
| }; |
|
|
| module.exports = { |
| getConversationTags, |
| createConversationTag, |
| updateConversationTag, |
| deleteConversationTag, |
| bulkIncrementTagCounts, |
| updateTagsForConversation, |
| }; |
|
|