2023-03-22 01:31:01 -04:00
|
|
|
const Conversation = require('./schema/convoSchema');
|
2023-02-07 16:22:35 -05:00
|
|
|
const { getMessages, deleteMessages } = require('./Message');
|
2023-12-14 07:49:27 -05:00
|
|
|
const logger = require('~/config/winston');
|
2023-02-06 14:05:02 -05:00
|
|
|
|
2024-08-09 15:17:13 -04:00
|
|
|
/**
|
|
|
|
|
* Searches for a conversation by conversationId and returns a lean document with only conversationId and user.
|
|
|
|
|
* @param {string} conversationId - The conversation's ID.
|
|
|
|
|
* @returns {Promise<{conversationId: string, user: string} | null>} The conversation object with selected fields or null if not found.
|
|
|
|
|
*/
|
|
|
|
|
const searchConversation = async (conversationId) => {
|
|
|
|
|
try {
|
|
|
|
|
return await Conversation.findOne({ conversationId }, 'conversationId user').lean();
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error('[searchConversation] Error searching conversation', error);
|
|
|
|
|
throw new Error('Error searching conversation');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
🌿 feat: Fork Messages/Conversations (#2617)
* typedef for ImportBatchBuilder
* feat: first pass, fork conversations
* feat: fork - getMessagesUpToTargetLevel
* fix: additional tests and fix getAllMessagesUpToParent
* chore: arrow function return
* refactor: fork 3 options
* chore: remove unused genbuttons
* chore: remove unused hover buttons code
* feat: fork first pass
* wip: fork remember setting
* style: user icon
* chore: move clear chats to data tab
* WIP: fork UI options
* feat: data-provider fork types/services/vars and use generic MutationOptions
* refactor: use single param for fork option, use enum, fix mongo errors, use Date.now(), add records flag for testing, use endpoint from original convo and messages, pass originalConvo to finishConversation
* feat: add fork mutation hook and consolidate type imports
* refactor: use enum
* feat: first pass, fork mutation
* chore: add enum for target level fork option
* chore: add enum for target level fork option
* show toast when checking remember selection
* feat: splitAtTarget
* feat: split at target option
* feat: navigate to new fork, show toasts, set result query data
* feat: hover info for all fork options
* refactor: add Messages settings tab
* fix(Fork): remember text info
* ci: test for single message and is target edge case
* feat: additional tests for getAllMessagesUpToParent
* ci: additional tests and cycle detection for getMessagesUpToTargetLevel
* feat: circular dependency checks for getAllMessagesUpToParent
* fix: getMessagesUpToTargetLevel circular dep. check
* ci: more tests for getMessagesForConversation
* style: hover text for checkbox fork items
* refactor: add statefulness to conversation import
2024-05-05 11:48:20 -04:00
|
|
|
/**
|
|
|
|
|
* Retrieves a single conversation for a given user and conversation ID.
|
|
|
|
|
* @param {string} user - The user's ID.
|
|
|
|
|
* @param {string} conversationId - The conversation's ID.
|
|
|
|
|
* @returns {Promise<TConversation>} The conversation object.
|
|
|
|
|
*/
|
2023-03-14 01:24:43 +08:00
|
|
|
const getConvo = async (user, conversationId) => {
|
2023-03-08 22:30:29 -05:00
|
|
|
try {
|
2023-07-25 19:27:55 -04:00
|
|
|
return await Conversation.findOne({ user, conversationId }).lean();
|
2023-03-08 22:30:29 -05:00
|
|
|
} catch (error) {
|
2023-12-14 07:49:27 -05:00
|
|
|
logger.error('[getConvo] Error getting single conversation', error);
|
2023-03-08 22:30:29 -05:00
|
|
|
return { message: 'Error getting single conversation' };
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-09-22 17:21:50 -04:00
|
|
|
const deleteNullOrEmptyConversations = async () => {
|
|
|
|
|
try {
|
|
|
|
|
const filter = {
|
|
|
|
|
$or: [
|
|
|
|
|
{ conversationId: null },
|
|
|
|
|
{ conversationId: '' },
|
|
|
|
|
{ conversationId: { $exists: false } },
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const result = await Conversation.deleteMany(filter);
|
|
|
|
|
|
|
|
|
|
// Delete associated messages
|
|
|
|
|
const messageDeleteResult = await deleteMessages(filter);
|
|
|
|
|
|
|
|
|
|
logger.info(
|
|
|
|
|
`[deleteNullOrEmptyConversations] Deleted ${result.deletedCount} conversations and ${messageDeleteResult.deletedCount} messages`,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
conversations: result,
|
|
|
|
|
messages: messageDeleteResult,
|
|
|
|
|
};
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error('[deleteNullOrEmptyConversations] Error deleting conversations', error);
|
|
|
|
|
throw new Error('Error deleting conversations with null or empty conversationId');
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-02-06 14:05:02 -05:00
|
|
|
module.exports = {
|
2023-03-17 19:58:13 -04:00
|
|
|
Conversation,
|
2024-08-09 15:17:13 -04:00
|
|
|
searchConversation,
|
2024-09-22 17:21:50 -04:00
|
|
|
deleteNullOrEmptyConversations,
|
2024-07-20 01:51:59 -04:00
|
|
|
/**
|
|
|
|
|
* Saves a conversation to the database.
|
|
|
|
|
* @param {Object} req - The request object.
|
|
|
|
|
* @param {string} conversationId - The conversation's ID.
|
|
|
|
|
* @param {Object} metadata - Additional metadata to log for operation.
|
|
|
|
|
* @returns {Promise<TConversation>} The conversation object.
|
|
|
|
|
*/
|
|
|
|
|
saveConvo: async (req, { conversationId, newConversationId, ...convo }, metadata) => {
|
2023-02-08 00:02:29 -05:00
|
|
|
try {
|
2024-07-20 01:51:59 -04:00
|
|
|
if (metadata && metadata?.context) {
|
2024-07-21 13:54:47 -04:00
|
|
|
logger.debug(`[saveConvo] ${metadata.context}`);
|
2024-07-20 01:51:59 -04:00
|
|
|
}
|
2024-05-29 09:15:05 -04:00
|
|
|
const messages = await getMessages({ conversationId }, '_id');
|
2024-07-20 01:51:59 -04:00
|
|
|
const update = { ...convo, messages, user: req.user.id };
|
2023-03-15 00:54:50 +08:00
|
|
|
if (newConversationId) {
|
|
|
|
|
update.conversationId = newConversationId;
|
|
|
|
|
}
|
2023-02-06 14:05:02 -05:00
|
|
|
|
2024-07-20 01:51:59 -04:00
|
|
|
const conversation = await Conversation.findOneAndUpdate(
|
|
|
|
|
{ conversationId, user: req.user.id },
|
|
|
|
|
update,
|
|
|
|
|
{
|
|
|
|
|
new: true,
|
|
|
|
|
upsert: true,
|
|
|
|
|
},
|
|
|
|
|
);
|
2024-06-28 21:57:53 -04:00
|
|
|
|
|
|
|
|
return conversation.toObject();
|
2023-02-11 10:22:15 -05:00
|
|
|
} catch (error) {
|
2023-12-14 07:49:27 -05:00
|
|
|
logger.error('[saveConvo] Error saving conversation', error);
|
2024-07-21 13:54:47 -04:00
|
|
|
if (metadata && metadata?.context) {
|
|
|
|
|
logger.info(`[saveConvo] ${metadata.context}`);
|
|
|
|
|
}
|
2023-04-11 03:26:38 +08:00
|
|
|
return { message: 'Error saving conversation' };
|
2023-02-11 10:22:15 -05:00
|
|
|
}
|
|
|
|
|
},
|
2024-05-02 08:48:26 +02:00
|
|
|
bulkSaveConvos: async (conversations) => {
|
|
|
|
|
try {
|
|
|
|
|
const bulkOps = conversations.map((convo) => ({
|
|
|
|
|
updateOne: {
|
|
|
|
|
filter: { conversationId: convo.conversationId, user: convo.user },
|
|
|
|
|
update: convo,
|
|
|
|
|
upsert: true,
|
|
|
|
|
timestamps: false,
|
|
|
|
|
},
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const result = await Conversation.bulkWrite(bulkOps);
|
|
|
|
|
return result;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
logger.error('[saveBulkConversations] Error saving conversations in bulk', error);
|
|
|
|
|
throw new Error('Failed to save conversations in bulk.');
|
|
|
|
|
}
|
|
|
|
|
},
|
2024-07-29 07:45:59 -07:00
|
|
|
getConvosByPage: async (user, pageNumber = 1, pageSize = 25, isArchived = false, tags) => {
|
🚀feat: Archive conversations (#2590)
* 🔧chore: add internationalization labels for archive feature
* ✨ feat: Add function to useArchiveConversationMutation()
This commit adds a new mutation function `useArchiveConversationMutation()` for archiving conversations. This function takes the ID string of the conversation to be archived and returns a mutation result object. Upon successful archiving, it removes and refreshes the conversation from the query data cache.
While ChatGPT PATCHes the archived status by sending `{is_archived: true}` to the URL `/backend-api/conversation/$conversation_id`, this implementation uses the `dataService.updateConversation(payload)` with a POST method, aligning with the existing code conventions.
* ✨ feat(api): add is_archived field to Conversation schema and update getConvosByPage method
This commit adds a new field `is_archived` with a default value of false to the Conversation schema. It also modifies the `getConvosByPage` method within the Conversation API to adjust the query to only target conversations where `is_archived` is set to false or where the `is_archived` field does not exist. The function `getConvosQueried`, which returns conversations for a specified Conversation ID, was determined not to require consideration of whether `is_archived` is true or false, and thus was not modified.
* ♻️ refactor: add className prop to DotsIcon component
To enhance the versatility of the DotsIcon component, this commit introduces the ability to specify a className prop, allowing for greater customization.
* ✨ feat(ui): add Edit Button to group Title change and Conversation delete buttons
Added a new Edit Button to the conversations, similar to the ChatGPT UI, which groups options for editing the conversation title and deleting conversations. This grouping is accessible through a dialogue that appears when the three-dot icon is clicked.
* ♻️ refactor(ui): enhance Delete Button to accept className and label options
Enhanced the Delete Button component to accept a `className` for customization and an optional `appendLabel`. The DeleteButton component is used by both `Convo.tsx` and `Conversation.tsx`, but currently only `Convo.tsx` is active and `Conversation.tsx `is apparently not used; removing `Conversation.tsx` may eliminate the need for the `appendLabel` property in the future.
* ♻️ refactor(ui): enhance RenameButton to accept label options
Added the ability to optionally display labels; the Rename Button component is used by both `Convo.tsx` and `Conversation.tsx`, but currently only `Convo.tsx` is active and `Conversation.tsx `is apparently not used; removing `Conversation.tsx` may eliminate the need for the `appendLabel` property in the future.
* 🔧 chors: additional localization labels
* ♻️ refactor: change is_archived property of conversation to camelCase
* Refactor the is_archived property of conversation to camelCase (isArchived) to adhere to the existing code conventions
* Modify the function that retrieves conversations to accept the isArchived parameter
* ♻️ refactor: add archiveConversation mutation
I thought I could divert dataService.updateConversation, but added a new archiveConversation because the request types are different. It might be better to make them common, but to avoid side effects, I added a new function this time.
Added process to deleteConversationMutation to delete archived conversations
* ✨ feat: Add the function to hide a cancel button in DialogTemplate component
The Cancel button is not needed when displaying the archive list, so I made the Cancel button optional.
* ♻️ refactor: Add support for filtering archived conversations in Nav component
This commit modifies the Nav component to add the ability to filter out archived conversations when fetching data. This is done by adding `isArchived: false` to the query parameters for both the `useConversationsInfiniteQuery()` and `useSearchInfiniteQuery()` hooks, effectively excluding any archived conversations from the results returned.
* ♻️ refactor: add Tooltip to DeleteButton
* Add Tooltip to DeleteButton component
* Display Tooltip when DeleteButton only shows an Icon without text
* ✨ feat(ui): add ArchiveButton component for archiving conversations
To be compatible with the ChatGPT UI, no confirmation dialog is displayed when ArchiveButton is clicked. The basic behavior conforms to DeleteButton and RenameButton.
* ✨ feat(ui): add Archive button to list of conversations
Modify the Nav of the conversation list to include a dropdown that contains the Rename and Delete options, similar to the ChatGPT UI. Additionally, an Archive button has been added adjacent to the dropdown menu.
* ✨ feat: Add ArchivedChatsTable component
Adds the `ArchivedChatsTable` component, which displays a table of archived chats. It has been implemented to be as compatible with the ChatGPT UI as possible.
* 🚑 fix(tooltip): increase z-index to ensure visibility over Dialog
Resolve an issue where tooltips were not visible when displayed over a Dialog. The z-index of `DialogPrimitive.Portal` in `Dialog.tsx` is set to 999. Since the rationale for this value is unclear, the z-index of the tooltip has been increased to 1000 to guarantee its visibility above the Dialog component.
* 🔧 chors: add internationalization labels
2024-05-06 20:07:00 -07:00
|
|
|
const query = { user };
|
|
|
|
|
if (isArchived) {
|
|
|
|
|
query.isArchived = true;
|
|
|
|
|
} else {
|
|
|
|
|
query.$or = [{ isArchived: false }, { isArchived: { $exists: false } }];
|
|
|
|
|
}
|
2024-07-29 07:45:59 -07:00
|
|
|
if (Array.isArray(tags) && tags.length > 0) {
|
|
|
|
|
query.tags = { $in: tags };
|
|
|
|
|
}
|
2023-03-07 14:22:33 -05:00
|
|
|
try {
|
🚀feat: Archive conversations (#2590)
* 🔧chore: add internationalization labels for archive feature
* ✨ feat: Add function to useArchiveConversationMutation()
This commit adds a new mutation function `useArchiveConversationMutation()` for archiving conversations. This function takes the ID string of the conversation to be archived and returns a mutation result object. Upon successful archiving, it removes and refreshes the conversation from the query data cache.
While ChatGPT PATCHes the archived status by sending `{is_archived: true}` to the URL `/backend-api/conversation/$conversation_id`, this implementation uses the `dataService.updateConversation(payload)` with a POST method, aligning with the existing code conventions.
* ✨ feat(api): add is_archived field to Conversation schema and update getConvosByPage method
This commit adds a new field `is_archived` with a default value of false to the Conversation schema. It also modifies the `getConvosByPage` method within the Conversation API to adjust the query to only target conversations where `is_archived` is set to false or where the `is_archived` field does not exist. The function `getConvosQueried`, which returns conversations for a specified Conversation ID, was determined not to require consideration of whether `is_archived` is true or false, and thus was not modified.
* ♻️ refactor: add className prop to DotsIcon component
To enhance the versatility of the DotsIcon component, this commit introduces the ability to specify a className prop, allowing for greater customization.
* ✨ feat(ui): add Edit Button to group Title change and Conversation delete buttons
Added a new Edit Button to the conversations, similar to the ChatGPT UI, which groups options for editing the conversation title and deleting conversations. This grouping is accessible through a dialogue that appears when the three-dot icon is clicked.
* ♻️ refactor(ui): enhance Delete Button to accept className and label options
Enhanced the Delete Button component to accept a `className` for customization and an optional `appendLabel`. The DeleteButton component is used by both `Convo.tsx` and `Conversation.tsx`, but currently only `Convo.tsx` is active and `Conversation.tsx `is apparently not used; removing `Conversation.tsx` may eliminate the need for the `appendLabel` property in the future.
* ♻️ refactor(ui): enhance RenameButton to accept label options
Added the ability to optionally display labels; the Rename Button component is used by both `Convo.tsx` and `Conversation.tsx`, but currently only `Convo.tsx` is active and `Conversation.tsx `is apparently not used; removing `Conversation.tsx` may eliminate the need for the `appendLabel` property in the future.
* 🔧 chors: additional localization labels
* ♻️ refactor: change is_archived property of conversation to camelCase
* Refactor the is_archived property of conversation to camelCase (isArchived) to adhere to the existing code conventions
* Modify the function that retrieves conversations to accept the isArchived parameter
* ♻️ refactor: add archiveConversation mutation
I thought I could divert dataService.updateConversation, but added a new archiveConversation because the request types are different. It might be better to make them common, but to avoid side effects, I added a new function this time.
Added process to deleteConversationMutation to delete archived conversations
* ✨ feat: Add the function to hide a cancel button in DialogTemplate component
The Cancel button is not needed when displaying the archive list, so I made the Cancel button optional.
* ♻️ refactor: Add support for filtering archived conversations in Nav component
This commit modifies the Nav component to add the ability to filter out archived conversations when fetching data. This is done by adding `isArchived: false` to the query parameters for both the `useConversationsInfiniteQuery()` and `useSearchInfiniteQuery()` hooks, effectively excluding any archived conversations from the results returned.
* ♻️ refactor: add Tooltip to DeleteButton
* Add Tooltip to DeleteButton component
* Display Tooltip when DeleteButton only shows an Icon without text
* ✨ feat(ui): add ArchiveButton component for archiving conversations
To be compatible with the ChatGPT UI, no confirmation dialog is displayed when ArchiveButton is clicked. The basic behavior conforms to DeleteButton and RenameButton.
* ✨ feat(ui): add Archive button to list of conversations
Modify the Nav of the conversation list to include a dropdown that contains the Rename and Delete options, similar to the ChatGPT UI. Additionally, an Archive button has been added adjacent to the dropdown menu.
* ✨ feat: Add ArchivedChatsTable component
Adds the `ArchivedChatsTable` component, which displays a table of archived chats. It has been implemented to be as compatible with the ChatGPT UI as possible.
* 🚑 fix(tooltip): increase z-index to ensure visibility over Dialog
Resolve an issue where tooltips were not visible when displayed over a Dialog. The z-index of `DialogPrimitive.Portal` in `Dialog.tsx` is set to 999. Since the rationale for this value is unclear, the z-index of the tooltip has been increased to 1000 to guarantee its visibility above the Dialog component.
* 🔧 chors: add internationalization labels
2024-05-06 20:07:00 -07:00
|
|
|
const totalConvos = (await Conversation.countDocuments(query)) || 1;
|
2023-03-15 04:05:14 +08:00
|
|
|
const totalPages = Math.ceil(totalConvos / pageSize);
|
🚀feat: Archive conversations (#2590)
* 🔧chore: add internationalization labels for archive feature
* ✨ feat: Add function to useArchiveConversationMutation()
This commit adds a new mutation function `useArchiveConversationMutation()` for archiving conversations. This function takes the ID string of the conversation to be archived and returns a mutation result object. Upon successful archiving, it removes and refreshes the conversation from the query data cache.
While ChatGPT PATCHes the archived status by sending `{is_archived: true}` to the URL `/backend-api/conversation/$conversation_id`, this implementation uses the `dataService.updateConversation(payload)` with a POST method, aligning with the existing code conventions.
* ✨ feat(api): add is_archived field to Conversation schema and update getConvosByPage method
This commit adds a new field `is_archived` with a default value of false to the Conversation schema. It also modifies the `getConvosByPage` method within the Conversation API to adjust the query to only target conversations where `is_archived` is set to false or where the `is_archived` field does not exist. The function `getConvosQueried`, which returns conversations for a specified Conversation ID, was determined not to require consideration of whether `is_archived` is true or false, and thus was not modified.
* ♻️ refactor: add className prop to DotsIcon component
To enhance the versatility of the DotsIcon component, this commit introduces the ability to specify a className prop, allowing for greater customization.
* ✨ feat(ui): add Edit Button to group Title change and Conversation delete buttons
Added a new Edit Button to the conversations, similar to the ChatGPT UI, which groups options for editing the conversation title and deleting conversations. This grouping is accessible through a dialogue that appears when the three-dot icon is clicked.
* ♻️ refactor(ui): enhance Delete Button to accept className and label options
Enhanced the Delete Button component to accept a `className` for customization and an optional `appendLabel`. The DeleteButton component is used by both `Convo.tsx` and `Conversation.tsx`, but currently only `Convo.tsx` is active and `Conversation.tsx `is apparently not used; removing `Conversation.tsx` may eliminate the need for the `appendLabel` property in the future.
* ♻️ refactor(ui): enhance RenameButton to accept label options
Added the ability to optionally display labels; the Rename Button component is used by both `Convo.tsx` and `Conversation.tsx`, but currently only `Convo.tsx` is active and `Conversation.tsx `is apparently not used; removing `Conversation.tsx` may eliminate the need for the `appendLabel` property in the future.
* 🔧 chors: additional localization labels
* ♻️ refactor: change is_archived property of conversation to camelCase
* Refactor the is_archived property of conversation to camelCase (isArchived) to adhere to the existing code conventions
* Modify the function that retrieves conversations to accept the isArchived parameter
* ♻️ refactor: add archiveConversation mutation
I thought I could divert dataService.updateConversation, but added a new archiveConversation because the request types are different. It might be better to make them common, but to avoid side effects, I added a new function this time.
Added process to deleteConversationMutation to delete archived conversations
* ✨ feat: Add the function to hide a cancel button in DialogTemplate component
The Cancel button is not needed when displaying the archive list, so I made the Cancel button optional.
* ♻️ refactor: Add support for filtering archived conversations in Nav component
This commit modifies the Nav component to add the ability to filter out archived conversations when fetching data. This is done by adding `isArchived: false` to the query parameters for both the `useConversationsInfiniteQuery()` and `useSearchInfiniteQuery()` hooks, effectively excluding any archived conversations from the results returned.
* ♻️ refactor: add Tooltip to DeleteButton
* Add Tooltip to DeleteButton component
* Display Tooltip when DeleteButton only shows an Icon without text
* ✨ feat(ui): add ArchiveButton component for archiving conversations
To be compatible with the ChatGPT UI, no confirmation dialog is displayed when ArchiveButton is clicked. The basic behavior conforms to DeleteButton and RenameButton.
* ✨ feat(ui): add Archive button to list of conversations
Modify the Nav of the conversation list to include a dropdown that contains the Rename and Delete options, similar to the ChatGPT UI. Additionally, an Archive button has been added adjacent to the dropdown menu.
* ✨ feat: Add ArchivedChatsTable component
Adds the `ArchivedChatsTable` component, which displays a table of archived chats. It has been implemented to be as compatible with the ChatGPT UI as possible.
* 🚑 fix(tooltip): increase z-index to ensure visibility over Dialog
Resolve an issue where tooltips were not visible when displayed over a Dialog. The z-index of `DialogPrimitive.Portal` in `Dialog.tsx` is set to 999. Since the rationale for this value is unclear, the z-index of the tooltip has been increased to 1000 to guarantee its visibility above the Dialog component.
* 🔧 chors: add internationalization labels
2024-05-06 20:07:00 -07:00
|
|
|
const convos = await Conversation.find(query)
|
♾️ style: Infinite Scroll Nav and Sort Convos by Date/Usage (#1708)
* Style: Infinite Scroll and Group convos by date
* Style: Infinite Scroll and Group convos by date- Redesign NavBar
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Clean code
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Redesign NewChat Component
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Redesign NewChat Component
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Redesign NewChat Component
* Including OpenRouter and Mistral icon
* refactor(Conversations): cleanup use of utility functions and typing
* refactor(Nav/NewChat): use localStorage `lastConversationSetup` to determine the endpoint to use, as well as icons -> JSX components, remove use of `endpointSelected`
* refactor: remove use of `isFirstToday`
* refactor(Nav): remove use of `endpointSelected`, consolidate scrolling logic to its own hook `useNavScrolling`, remove use of recoil `conversation`
* refactor: Add spinner to bottom of list, throttle fetching, move query hooks to client workspace
* chore: sort by `updatedAt` field
* refactor: optimize conversation infinite query, use optimistic updates, add conversation helpers for managing pagination, remove unnecessary operations
* feat: gen_title route for generating the title for the conversation
* style(Convo): change hover bg-color
* refactor: memoize groupedConversations and return as array of tuples, correctly update convos pre/post message stream, only call genTitle if conversation is new, make `addConversation` dynamically either add/update depending if convo exists in pages already, reorganize type definitions
* style: rename Header NewChat Button -> HeaderNewChat, add NewChatIcon, closely match main Nav New Chat button to ChatGPT
* style(NewChat): add hover bg color
* style: cleanup comments, match ChatGPT nav styling, redesign search bar, make part of new chat sticky header, move Nav under same parent as outlet/mobilenav, remove legacy code, search only if searchQuery is not empty
* feat: add tests for conversation helpers and ensure no duplicate conversations are ever grouped
* style: hover bg-color
* feat: alt-click on convo item to open conversation in new tab
* chore: send error message when `gen_title` fails
---------
Co-authored-by: Walber Cardoso <walbercardoso@gmail.com>
2024-02-03 20:25:35 -05:00
|
|
|
.sort({ updatedAt: -1 })
|
2023-03-15 04:05:14 +08:00
|
|
|
.skip((pageNumber - 1) * pageSize)
|
2023-03-07 14:22:33 -05:00
|
|
|
.limit(pageSize)
|
2023-07-25 19:27:55 -04:00
|
|
|
.lean();
|
2023-03-15 04:05:14 +08:00
|
|
|
return { conversations: convos, pages: totalPages, pageNumber, pageSize };
|
2023-03-07 14:22:33 -05:00
|
|
|
} catch (error) {
|
2023-12-14 07:49:27 -05:00
|
|
|
logger.error('[getConvosByPage] Error getting conversations', error);
|
2023-03-07 14:22:33 -05:00
|
|
|
return { message: 'Error getting conversations' };
|
|
|
|
|
}
|
|
|
|
|
},
|
♾️ style: Infinite Scroll Nav and Sort Convos by Date/Usage (#1708)
* Style: Infinite Scroll and Group convos by date
* Style: Infinite Scroll and Group convos by date- Redesign NavBar
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Clean code
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Redesign NewChat Component
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Redesign NewChat Component
* Style: Infinite Scroll and Group convos by date- Redesign NavBar - Redesign NewChat Component
* Including OpenRouter and Mistral icon
* refactor(Conversations): cleanup use of utility functions and typing
* refactor(Nav/NewChat): use localStorage `lastConversationSetup` to determine the endpoint to use, as well as icons -> JSX components, remove use of `endpointSelected`
* refactor: remove use of `isFirstToday`
* refactor(Nav): remove use of `endpointSelected`, consolidate scrolling logic to its own hook `useNavScrolling`, remove use of recoil `conversation`
* refactor: Add spinner to bottom of list, throttle fetching, move query hooks to client workspace
* chore: sort by `updatedAt` field
* refactor: optimize conversation infinite query, use optimistic updates, add conversation helpers for managing pagination, remove unnecessary operations
* feat: gen_title route for generating the title for the conversation
* style(Convo): change hover bg-color
* refactor: memoize groupedConversations and return as array of tuples, correctly update convos pre/post message stream, only call genTitle if conversation is new, make `addConversation` dynamically either add/update depending if convo exists in pages already, reorganize type definitions
* style: rename Header NewChat Button -> HeaderNewChat, add NewChatIcon, closely match main Nav New Chat button to ChatGPT
* style(NewChat): add hover bg color
* style: cleanup comments, match ChatGPT nav styling, redesign search bar, make part of new chat sticky header, move Nav under same parent as outlet/mobilenav, remove legacy code, search only if searchQuery is not empty
* feat: add tests for conversation helpers and ensure no duplicate conversations are ever grouped
* style: hover bg-color
* feat: alt-click on convo item to open conversation in new tab
* chore: send error message when `gen_title` fails
---------
Co-authored-by: Walber Cardoso <walbercardoso@gmail.com>
2024-02-03 20:25:35 -05:00
|
|
|
getConvosQueried: async (user, convoIds, pageNumber = 1, pageSize = 25) => {
|
2023-03-18 01:40:49 -04:00
|
|
|
try {
|
|
|
|
|
if (!convoIds || convoIds.length === 0) {
|
|
|
|
|
return { conversations: [], pages: 1, pageNumber, pageSize };
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-18 17:49:24 -04:00
|
|
|
const cache = {};
|
2023-03-22 16:06:11 -04:00
|
|
|
const convoMap = {};
|
2023-03-18 17:49:24 -04:00
|
|
|
const promises = [];
|
|
|
|
|
|
2023-05-18 11:44:07 -07:00
|
|
|
convoIds.forEach((convo) =>
|
2023-03-18 23:18:36 -04:00
|
|
|
promises.push(
|
|
|
|
|
Conversation.findOne({
|
|
|
|
|
user,
|
2023-07-14 09:36:49 -04:00
|
|
|
conversationId: convo.conversationId,
|
2023-07-25 19:27:55 -04:00
|
|
|
}).lean(),
|
2023-07-14 09:36:49 -04:00
|
|
|
),
|
2023-03-18 23:18:36 -04:00
|
|
|
);
|
2023-03-18 17:49:24 -04:00
|
|
|
|
2023-07-28 13:16:41 -04:00
|
|
|
const results = (await Promise.all(promises)).filter(Boolean);
|
|
|
|
|
|
|
|
|
|
results.forEach((convo, i) => {
|
|
|
|
|
const page = Math.floor(i / pageSize) + 1;
|
|
|
|
|
if (!cache[page]) {
|
|
|
|
|
cache[page] = [];
|
2023-03-18 23:18:36 -04:00
|
|
|
}
|
2023-07-28 13:16:41 -04:00
|
|
|
cache[page].push(convo);
|
|
|
|
|
convoMap[convo.conversationId] = convo;
|
2023-03-18 01:40:49 -04:00
|
|
|
});
|
2023-03-18 23:18:36 -04:00
|
|
|
|
2023-03-18 01:40:49 -04:00
|
|
|
const totalPages = Math.ceil(results.length / pageSize);
|
2023-03-18 17:49:24 -04:00
|
|
|
cache.pages = totalPages;
|
|
|
|
|
cache.pageSize = pageSize;
|
|
|
|
|
return {
|
|
|
|
|
cache,
|
2023-03-18 23:18:36 -04:00
|
|
|
conversations: cache[pageNumber] || [],
|
|
|
|
|
pages: totalPages || 1,
|
2023-03-18 17:49:24 -04:00
|
|
|
pageNumber,
|
2023-03-18 23:18:36 -04:00
|
|
|
pageSize,
|
2023-07-14 09:36:49 -04:00
|
|
|
convoMap,
|
2023-03-18 17:49:24 -04:00
|
|
|
};
|
2023-03-18 01:40:49 -04:00
|
|
|
} catch (error) {
|
2023-12-14 07:49:27 -05:00
|
|
|
logger.error('[getConvosQueried] Error getting conversations', error);
|
2023-03-18 01:40:49 -04:00
|
|
|
return { message: 'Error fetching conversations' };
|
|
|
|
|
}
|
|
|
|
|
},
|
2023-03-08 22:30:29 -05:00
|
|
|
getConvo,
|
2023-03-20 01:35:02 -04:00
|
|
|
/* chore: this method is not properly error handled */
|
2023-03-14 01:24:43 +08:00
|
|
|
getConvoTitle: async (user, conversationId) => {
|
2023-03-07 14:22:33 -05:00
|
|
|
try {
|
2023-03-14 01:24:43 +08:00
|
|
|
const convo = await getConvo(user, conversationId);
|
2023-03-20 01:35:02 -04:00
|
|
|
/* ChatGPT Browser was triggering error here due to convo being saved later */
|
|
|
|
|
if (convo && !convo.title) {
|
|
|
|
|
return null;
|
|
|
|
|
} else {
|
2023-03-20 02:30:08 -04:00
|
|
|
// TypeError: Cannot read properties of null (reading 'title')
|
|
|
|
|
return convo?.title || 'New Chat';
|
2023-03-20 01:35:02 -04:00
|
|
|
}
|
2023-03-07 14:22:33 -05:00
|
|
|
} catch (error) {
|
2023-12-14 07:49:27 -05:00
|
|
|
logger.error('[getConvoTitle] Error getting conversation title', error);
|
2023-03-28 01:19:44 +08:00
|
|
|
return { message: 'Error getting conversation title' };
|
2023-03-07 14:22:33 -05:00
|
|
|
}
|
2023-03-05 14:41:50 -05:00
|
|
|
},
|
2023-09-18 15:19:50 -04:00
|
|
|
/**
|
|
|
|
|
* Asynchronously deletes conversations and associated messages for a given user and filter.
|
|
|
|
|
*
|
|
|
|
|
* @async
|
|
|
|
|
* @function
|
|
|
|
|
* @param {string|ObjectId} user - The user's ID.
|
|
|
|
|
* @param {Object} filter - Additional filter criteria for the conversations to be deleted.
|
|
|
|
|
* @returns {Promise<{ n: number, ok: number, deletedCount: number, messages: { n: number, ok: number, deletedCount: number } }>}
|
|
|
|
|
* An object containing the count of deleted conversations and associated messages.
|
|
|
|
|
* @throws {Error} Throws an error if there's an issue with the database operations.
|
|
|
|
|
*
|
|
|
|
|
* @example
|
|
|
|
|
* const user = 'someUserId';
|
|
|
|
|
* const filter = { someField: 'someValue' };
|
|
|
|
|
* const result = await deleteConvos(user, filter);
|
2023-12-14 07:49:27 -05:00
|
|
|
* logger.error(result); // { n: 5, ok: 1, deletedCount: 5, messages: { n: 10, ok: 1, deletedCount: 10 } }
|
2023-09-18 15:19:50 -04:00
|
|
|
*/
|
2023-03-14 01:24:43 +08:00
|
|
|
deleteConvos: async (user, filter) => {
|
2023-03-31 03:22:57 +08:00
|
|
|
let toRemove = await Conversation.find({ ...filter, user }).select('conversationId');
|
2023-05-18 11:44:07 -07:00
|
|
|
const ids = toRemove.map((instance) => instance.conversationId);
|
2023-07-25 19:27:55 -04:00
|
|
|
let deleteCount = await Conversation.deleteMany({ ...filter, user });
|
2023-03-31 03:22:57 +08:00
|
|
|
deleteCount.messages = await deleteMessages({ conversationId: { $in: ids } });
|
2023-02-07 16:22:35 -05:00
|
|
|
return deleteCount;
|
2023-07-14 09:36:49 -04:00
|
|
|
},
|
2023-02-06 14:05:02 -05:00
|
|
|
};
|