Get/Delete ChatMessage based on startDateTime / endDateTime (#3867)

* Get ChatMessage based on startDateTime / endDateTime - supplements existing startDate / endDate fields

* Proper query handling for between case

* Return 0 result rather than error

* lint fix

* update start date and end date query

---------

Co-authored-by: Henry <hzj94@hotmail.com>
This commit is contained in:
Ryan Halliday
2025-01-15 03:06:42 +13:00
committed by GitHub
parent aab493c3c7
commit 16aa3a0d29
8 changed files with 100 additions and 90 deletions
@@ -2,9 +2,9 @@ import { Request, Response, NextFunction } from 'express'
import { ChatMessageRatingType, ChatType, IReactFlowObject } from '../../Interface' import { ChatMessageRatingType, ChatType, IReactFlowObject } from '../../Interface'
import chatflowsService from '../../services/chatflows' import chatflowsService from '../../services/chatflows'
import chatMessagesService from '../../services/chat-messages' import chatMessagesService from '../../services/chat-messages'
import { aMonthAgo, clearSessionMemory, setDateToStartOrEndOfDay } from '../../utils' import { aMonthAgo, clearSessionMemory } from '../../utils'
import { getRunningExpressApp } from '../../utils/getRunningExpressApp' import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
import { Between, FindOptionsWhere } from 'typeorm' import { Between, DeleteResult, FindOptionsWhere } from 'typeorm'
import { ChatMessage } from '../../database/entities/ChatMessage' import { ChatMessage } from '../../database/entities/ChatMessage'
import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { InternalFlowiseError } from '../../errors/internalFlowiseError'
import { StatusCodes } from 'http-status-codes' import { StatusCodes } from 'http-status-codes'
@@ -167,21 +167,21 @@ const removeAllChatMessages = async (req: Request, res: Response, next: NextFunc
if (!chatId) { if (!chatId) {
const isFeedback = feedbackTypeFilters?.length ? true : false const isFeedback = feedbackTypeFilters?.length ? true : false
const hardDelete = req.query?.hardDelete as boolean | undefined const hardDelete = req.query?.hardDelete as boolean | undefined
const messages = await utilGetChatMessage( const messages = await utilGetChatMessage({
chatflowid, chatflowid,
_chatType as ChatType | undefined, chatType: _chatType as ChatType | undefined,
undefined,
undefined,
undefined,
undefined,
startDate, startDate,
endDate, endDate,
undefined, feedback: isFeedback,
isFeedback, feedbackTypes: feedbackTypeFilters
feedbackTypeFilters })
)
const messageIds = messages.map((message) => message.id) const messageIds = messages.map((message) => message.id)
if (messages.length === 0) {
const result: DeleteResult = { raw: [], affected: 0 }
return res.json(result)
}
// Categorize by chatId_memoryType_sessionId // Categorize by chatId_memoryType_sessionId
const chatIdMap = new Map<string, ChatMessage[]>() const chatIdMap = new Map<string, ChatMessage[]>()
messages.forEach((message) => { messages.forEach((message) => {
@@ -238,8 +238,8 @@ const removeAllChatMessages = async (req: Request, res: Response, next: NextFunc
if (sessionId) deleteOptions.sessionId = sessionId if (sessionId) deleteOptions.sessionId = sessionId
if (_chatType) deleteOptions.chatType = _chatType if (_chatType) deleteOptions.chatType = _chatType
if (startDate && endDate) { if (startDate && endDate) {
const fromDate = setDateToStartOrEndOfDay(startDate, 'start') const fromDate = new Date(startDate)
const toDate = setDateToStartOrEndOfDay(endDate, 'end') const toDate = new Date(endDate)
deleteOptions.createdDate = Between(fromDate ?? aMonthAgo(), toDate ?? new Date()) deleteOptions.createdDate = Between(fromDate ?? aMonthAgo(), toDate ?? new Date())
} }
const apiResponse = await chatMessagesService.removeAllChatMessages(chatId, chatflowid, deleteOptions) const apiResponse = await chatMessagesService.removeAllChatMessages(chatId, chatflowid, deleteOptions)
@@ -39,9 +39,9 @@ const getAllChatMessages = async (
feedbackTypes?: ChatMessageRatingType[] feedbackTypes?: ChatMessageRatingType[]
): Promise<ChatMessage[]> => { ): Promise<ChatMessage[]> => {
try { try {
const dbResponse = await utilGetChatMessage( const dbResponse = await utilGetChatMessage({
chatflowId, chatflowid: chatflowId,
chatTypeFilter, chatType: chatTypeFilter,
sortOrder, sortOrder,
chatId, chatId,
memoryType, memoryType,
@@ -51,7 +51,7 @@ const getAllChatMessages = async (
messageId, messageId,
feedback, feedback,
feedbackTypes feedbackTypes
) })
return dbResponse return dbResponse
} catch (error) { } catch (error) {
throw new InternalFlowiseError( throw new InternalFlowiseError(
@@ -76,9 +76,9 @@ const getAllInternalChatMessages = async (
feedbackTypes?: ChatMessageRatingType[] feedbackTypes?: ChatMessageRatingType[]
): Promise<ChatMessage[]> => { ): Promise<ChatMessage[]> => {
try { try {
const dbResponse = await utilGetChatMessage( const dbResponse = await utilGetChatMessage({
chatflowId, chatflowid: chatflowId,
chatTypeFilter, chatType: chatTypeFilter,
sortOrder, sortOrder,
chatId, chatId,
memoryType, memoryType,
@@ -88,7 +88,7 @@ const getAllInternalChatMessages = async (
messageId, messageId,
feedback, feedback,
feedbackTypes feedbackTypes
) })
return dbResponse return dbResponse
} catch (error) { } catch (error) {
throw new InternalFlowiseError( throw new InternalFlowiseError(
+3 -7
View File
@@ -17,19 +17,15 @@ const getChatflowStats = async (
feedbackTypes?: ChatMessageRatingType[] feedbackTypes?: ChatMessageRatingType[]
): Promise<any> => { ): Promise<any> => {
try { try {
const chatmessages = (await utilGetChatMessage( const chatmessages = (await utilGetChatMessage({
chatflowid, chatflowid,
chatTypeFilter, chatType: chatTypeFilter,
undefined,
undefined,
undefined,
undefined,
startDate, startDate,
endDate, endDate,
messageId, messageId,
feedback, feedback,
feedbackTypes feedbackTypes
)) as Array<ChatMessage & { feedback?: ChatMessageFeedback }> })) as Array<ChatMessage & { feedback?: ChatMessageFeedback }>
const totalMessages = chatmessages.length const totalMessages = chatmessages.length
const totalFeedback = chatmessages.filter((message) => message?.feedback).length const totalFeedback = chatmessages.filter((message) => message?.feedback).length
const positiveFeedback = chatmessages.filter((message) => message?.feedback?.rating === 'THUMBS_UP').length const positiveFeedback = chatmessages.filter((message) => message?.feedback?.rating === 'THUMBS_UP').length
@@ -1,4 +1,4 @@
import { MoreThanOrEqual, LessThanOrEqual } from 'typeorm' import { MoreThanOrEqual, LessThanOrEqual, Between } from 'typeorm'
import { StatusCodes } from 'http-status-codes' import { StatusCodes } from 'http-status-codes'
import { getRunningExpressApp } from '../../utils/getRunningExpressApp' import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
import { UpsertHistory } from '../../database/entities/UpsertHistory' import { UpsertHistory } from '../../database/entities/UpsertHistory'
@@ -14,26 +14,20 @@ const getAllUpsertHistory = async (
try { try {
const appServer = getRunningExpressApp() const appServer = getRunningExpressApp()
const setDateToStartOrEndOfDay = (dateTimeStr: string, setHours: 'start' | 'end') => { let createdDateQuery
const date = new Date(dateTimeStr) if (startDate || endDate) {
if (isNaN(date.getTime())) { if (startDate && endDate) {
return undefined createdDateQuery = Between(new Date(startDate), new Date(endDate))
} else if (startDate) {
createdDateQuery = MoreThanOrEqual(new Date(startDate))
} else if (endDate) {
createdDateQuery = LessThanOrEqual(new Date(endDate))
} }
setHours === 'start' ? date.setHours(0, 0, 0, 0) : date.setHours(23, 59, 59, 999)
return date
} }
let fromDate
if (startDate) fromDate = setDateToStartOrEndOfDay(startDate, 'start')
let toDate
if (endDate) toDate = setDateToStartOrEndOfDay(endDate, 'end')
let upsertHistory = await appServer.AppDataSource.getRepository(UpsertHistory).find({ let upsertHistory = await appServer.AppDataSource.getRepository(UpsertHistory).find({
where: { where: {
chatflowid, chatflowid,
...(fromDate && { date: MoreThanOrEqual(fromDate) }), date: createdDateQuery
...(toDate && { date: LessThanOrEqual(toDate) })
}, },
order: { order: {
date: sortOrder === 'DESC' ? 'DESC' : 'ASC' date: sortOrder === 'DESC' ? 'DESC' : 'ASC'
+47 -26
View File
@@ -1,9 +1,9 @@
import { MoreThanOrEqual, LessThanOrEqual } from 'typeorm' import { MoreThanOrEqual, LessThanOrEqual, Between } from 'typeorm'
import { ChatMessageRatingType, ChatType } from '../Interface' import { ChatMessageRatingType, ChatType } from '../Interface'
import { ChatMessage } from '../database/entities/ChatMessage' import { ChatMessage } from '../database/entities/ChatMessage'
import { ChatMessageFeedback } from '../database/entities/ChatMessageFeedback' import { ChatMessageFeedback } from '../database/entities/ChatMessageFeedback'
import { getRunningExpressApp } from '../utils/getRunningExpressApp' import { getRunningExpressApp } from '../utils/getRunningExpressApp'
import { aMonthAgo, setDateToStartOrEndOfDay } from '.' import { aMonthAgo } from '.'
/** /**
* Method that get chat messages. * Method that get chat messages.
@@ -18,27 +18,35 @@ import { aMonthAgo, setDateToStartOrEndOfDay } from '.'
* @param {boolean} feedback * @param {boolean} feedback
* @param {ChatMessageRatingType[]} feedbackTypes * @param {ChatMessageRatingType[]} feedbackTypes
*/ */
export const utilGetChatMessage = async ( interface GetChatMessageParams {
chatflowid: string, chatflowid: string
chatType: ChatType | undefined, chatType?: ChatType
sortOrder: string = 'ASC', sortOrder?: string
chatId?: string, chatId?: string
memoryType?: string, memoryType?: string
sessionId?: string, sessionId?: string
startDate?: string, startDate?: string
endDate?: string, endDate?: string
messageId?: string, messageId?: string
feedback?: boolean, feedback?: boolean
feedbackTypes?: ChatMessageRatingType[] feedbackTypes?: ChatMessageRatingType[]
): Promise<ChatMessage[]> => { }
export const utilGetChatMessage = async ({
chatflowid,
chatType,
sortOrder = 'ASC',
chatId,
memoryType,
sessionId,
startDate,
endDate,
messageId,
feedback,
feedbackTypes
}: GetChatMessageParams): Promise<ChatMessage[]> => {
const appServer = getRunningExpressApp() const appServer = getRunningExpressApp()
let fromDate
if (startDate) fromDate = setDateToStartOrEndOfDay(startDate, 'start')
let toDate
if (endDate) toDate = setDateToStartOrEndOfDay(endDate, 'end')
if (feedback) { if (feedback) {
const query = await appServer.AppDataSource.getRepository(ChatMessage).createQueryBuilder('chat_message') const query = await appServer.AppDataSource.getRepository(ChatMessage).createQueryBuilder('chat_message')
@@ -62,10 +70,13 @@ export const utilGetChatMessage = async (
} }
// set date range // set date range
query.andWhere('chat_message.createdDate BETWEEN :fromDate AND :toDate', { if (startDate) {
fromDate: fromDate ?? aMonthAgo(), query.andWhere('chat_message.createdDate >= :startDateTime', { startDateTime: startDate ? new Date(startDate) : aMonthAgo() })
toDate: toDate ?? new Date() }
}) if (endDate) {
query.andWhere('chat_message.createdDate <= :endDateTime', { endDateTime: endDate ? new Date(endDate) : new Date() })
}
// sort // sort
query.orderBy('chat_message.createdDate', sortOrder === 'DESC' ? 'DESC' : 'ASC') query.orderBy('chat_message.createdDate', sortOrder === 'DESC' ? 'DESC' : 'ASC')
@@ -89,6 +100,17 @@ export const utilGetChatMessage = async (
return messages return messages
} }
let createdDateQuery
if (startDate || endDate) {
if (startDate && endDate) {
createdDateQuery = Between(new Date(startDate), new Date(endDate))
} else if (startDate) {
createdDateQuery = MoreThanOrEqual(new Date(startDate))
} else if (endDate) {
createdDateQuery = LessThanOrEqual(new Date(endDate))
}
}
return await appServer.AppDataSource.getRepository(ChatMessage).find({ return await appServer.AppDataSource.getRepository(ChatMessage).find({
where: { where: {
chatflowid, chatflowid,
@@ -96,8 +118,7 @@ export const utilGetChatMessage = async (
chatId, chatId,
memoryType: memoryType ?? undefined, memoryType: memoryType ?? undefined,
sessionId: sessionId ?? undefined, sessionId: sessionId ?? undefined,
...(fromDate && { createdDate: MoreThanOrEqual(fromDate) }), createdDate: createdDateQuery,
...(toDate && { createdDate: LessThanOrEqual(toDate) }),
id: messageId ?? undefined id: messageId ?? undefined
}, },
order: { order: {
-9
View File
@@ -1745,15 +1745,6 @@ export const convertToValidFilename = (word: string) => {
.toLowerCase() .toLowerCase()
} }
export const setDateToStartOrEndOfDay = (dateTimeStr: string, setHours: 'start' | 'end') => {
const date = new Date(dateTimeStr)
if (isNaN(date.getTime())) {
return undefined
}
setHours === 'start' ? date.setHours(0, 0, 0, 0) : date.setHours(23, 59, 59, 999)
return date
}
export const aMonthAgo = () => { export const aMonthAgo = () => {
const date = new Date() const date = new Date()
date.setMonth(new Date().getMonth() - 1) date.setMonth(new Date().getMonth() - 1)
@@ -167,28 +167,32 @@ const ViewMessagesDialog = ({ show, dialogProps, onCancel }) => {
let storagePath = '' let storagePath = ''
const onStartDateSelected = (date) => { const onStartDateSelected = (date) => {
setStartDate(date) const updatedDate = new Date(date)
updatedDate.setHours(0, 0, 0, 0)
setStartDate(updatedDate)
getChatmessageApi.request(dialogProps.chatflow.id, { getChatmessageApi.request(dialogProps.chatflow.id, {
startDate: date, startDate: updatedDate,
endDate: endDate, endDate: endDate,
chatType: chatTypeFilter.length ? chatTypeFilter : undefined chatType: chatTypeFilter.length ? chatTypeFilter : undefined
}) })
getStatsApi.request(dialogProps.chatflow.id, { getStatsApi.request(dialogProps.chatflow.id, {
startDate: date, startDate: updatedDate,
endDate: endDate, endDate: endDate,
chatType: chatTypeFilter.length ? chatTypeFilter : undefined chatType: chatTypeFilter.length ? chatTypeFilter : undefined
}) })
} }
const onEndDateSelected = (date) => { const onEndDateSelected = (date) => {
setEndDate(date) const updatedDate = new Date(date)
updatedDate.setHours(23, 59, 59, 999)
setEndDate(updatedDate)
getChatmessageApi.request(dialogProps.chatflow.id, { getChatmessageApi.request(dialogProps.chatflow.id, {
endDate: date, endDate: updatedDate,
startDate: startDate, startDate: startDate,
chatType: chatTypeFilter.length ? chatTypeFilter : undefined chatType: chatTypeFilter.length ? chatTypeFilter : undefined
}) })
getStatsApi.request(dialogProps.chatflow.id, { getStatsApi.request(dialogProps.chatflow.id, {
endDate: date, endDate: updatedDate,
startDate: startDate, startDate: startDate,
chatType: chatTypeFilter.length ? chatTypeFilter : undefined chatType: chatTypeFilter.length ? chatTypeFilter : undefined
}) })
@@ -211,17 +211,21 @@ const UpsertHistoryDialog = ({ show, dialogProps, onCancel }) => {
} }
const onStartDateSelected = (date) => { const onStartDateSelected = (date) => {
setStartDate(date) const updatedDate = new Date(date)
updatedDate.setHours(0, 0, 0, 0)
setStartDate(updatedDate)
getUpsertHistoryApi.request(dialogProps.chatflow.id, { getUpsertHistoryApi.request(dialogProps.chatflow.id, {
startDate: date, startDate: updatedDate,
endDate: endDate endDate: endDate
}) })
} }
const onEndDateSelected = (date) => { const onEndDateSelected = (date) => {
setEndDate(date) const updatedDate = new Date(date)
updatedDate.setHours(23, 59, 59, 999)
setEndDate(updatedDate)
getUpsertHistoryApi.request(dialogProps.chatflow.id, { getUpsertHistoryApi.request(dialogProps.chatflow.id, {
endDate: date, endDate: updatedDate,
startDate: startDate startDate: startDate
}) })
} }