mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 13:00:56 +03:00
Feature/Full File Uploads & Message Delete API (#3314)
* add functionality for full file uploads, add remove messages from view dialog and API * add attachments swagger * update question to include uploadedFilesContent * make config dialog modal lg size
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import attachmentsService from '../../services/attachments'
|
||||
|
||||
const createAttachment = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const apiResponse = await attachmentsService.createAttachment(req)
|
||||
return res.json(apiResponse)
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
createAttachment
|
||||
}
|
||||
@@ -1,13 +1,36 @@
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import { ChatMessageRatingType, chatType, IReactFlowObject } from '../../Interface'
|
||||
import { ChatMessageRatingType, ChatType, IReactFlowObject } from '../../Interface'
|
||||
import chatflowsService from '../../services/chatflows'
|
||||
import chatMessagesService from '../../services/chat-messages'
|
||||
import { clearSessionMemory } from '../../utils'
|
||||
import { aMonthAgo, clearSessionMemory, setDateToStartOrEndOfDay } from '../../utils'
|
||||
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
||||
import { FindOptionsWhere } from 'typeorm'
|
||||
import { Between, FindOptionsWhere } from 'typeorm'
|
||||
import { ChatMessage } from '../../database/entities/ChatMessage'
|
||||
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
||||
import { StatusCodes } from 'http-status-codes'
|
||||
import { utilGetChatMessage } from '../../utils/getChatMessage'
|
||||
|
||||
const getFeedbackTypeFilters = (_feedbackTypeFilters: ChatMessageRatingType[]): ChatMessageRatingType[] | undefined => {
|
||||
try {
|
||||
let feedbackTypeFilters
|
||||
const feedbackTypeFilterArray = JSON.parse(JSON.stringify(_feedbackTypeFilters))
|
||||
if (
|
||||
feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_UP) &&
|
||||
feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_DOWN)
|
||||
) {
|
||||
feedbackTypeFilters = [ChatMessageRatingType.THUMBS_UP, ChatMessageRatingType.THUMBS_DOWN]
|
||||
} else if (feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_UP)) {
|
||||
feedbackTypeFilters = [ChatMessageRatingType.THUMBS_UP]
|
||||
} else if (feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_DOWN)) {
|
||||
feedbackTypeFilters = [ChatMessageRatingType.THUMBS_DOWN]
|
||||
} else {
|
||||
feedbackTypeFilters = undefined
|
||||
}
|
||||
return feedbackTypeFilters
|
||||
} catch (e) {
|
||||
return _feedbackTypeFilters
|
||||
}
|
||||
}
|
||||
|
||||
const createChatMessage = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
@@ -26,16 +49,16 @@ const createChatMessage = async (req: Request, res: Response, next: NextFunction
|
||||
|
||||
const getAllChatMessages = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
let chatTypeFilter = req.query?.chatType as chatType | undefined
|
||||
let chatTypeFilter = req.query?.chatType as ChatType | undefined
|
||||
if (chatTypeFilter) {
|
||||
try {
|
||||
const chatTypeFilterArray = JSON.parse(chatTypeFilter)
|
||||
if (chatTypeFilterArray.includes(chatType.EXTERNAL) && chatTypeFilterArray.includes(chatType.INTERNAL)) {
|
||||
if (chatTypeFilterArray.includes(ChatType.EXTERNAL) && chatTypeFilterArray.includes(ChatType.INTERNAL)) {
|
||||
chatTypeFilter = undefined
|
||||
} else if (chatTypeFilterArray.includes(chatType.EXTERNAL)) {
|
||||
chatTypeFilter = chatType.EXTERNAL
|
||||
} else if (chatTypeFilterArray.includes(chatType.INTERNAL)) {
|
||||
chatTypeFilter = chatType.INTERNAL
|
||||
} else if (chatTypeFilterArray.includes(ChatType.EXTERNAL)) {
|
||||
chatTypeFilter = ChatType.EXTERNAL
|
||||
} else if (chatTypeFilterArray.includes(ChatType.INTERNAL)) {
|
||||
chatTypeFilter = ChatType.INTERNAL
|
||||
}
|
||||
} catch (e) {
|
||||
return res.status(500).send(e)
|
||||
@@ -51,23 +74,7 @@ const getAllChatMessages = async (req: Request, res: Response, next: NextFunctio
|
||||
const feedback = req.query?.feedback as boolean | undefined
|
||||
let feedbackTypeFilters = req.query?.feedbackType as ChatMessageRatingType[] | undefined
|
||||
if (feedbackTypeFilters) {
|
||||
try {
|
||||
const feedbackTypeFilterArray = JSON.parse(JSON.stringify(feedbackTypeFilters))
|
||||
if (
|
||||
feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_UP) &&
|
||||
feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_DOWN)
|
||||
) {
|
||||
feedbackTypeFilters = [ChatMessageRatingType.THUMBS_UP, ChatMessageRatingType.THUMBS_DOWN]
|
||||
} else if (feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_UP)) {
|
||||
feedbackTypeFilters = [ChatMessageRatingType.THUMBS_UP]
|
||||
} else if (feedbackTypeFilterArray.includes(ChatMessageRatingType.THUMBS_DOWN)) {
|
||||
feedbackTypeFilters = [ChatMessageRatingType.THUMBS_DOWN]
|
||||
} else {
|
||||
feedbackTypeFilters = undefined
|
||||
}
|
||||
} catch (e) {
|
||||
return res.status(500).send(e)
|
||||
}
|
||||
feedbackTypeFilters = getFeedbackTypeFilters(feedbackTypeFilters)
|
||||
}
|
||||
if (typeof req.params === 'undefined' || !req.params.id) {
|
||||
throw new InternalFlowiseError(
|
||||
@@ -105,9 +112,13 @@ const getAllInternalChatMessages = async (req: Request, res: Response, next: Nex
|
||||
const startDate = req.query?.startDate as string | undefined
|
||||
const endDate = req.query?.endDate as string | undefined
|
||||
const feedback = req.query?.feedback as boolean | undefined
|
||||
let feedbackTypeFilters = req.query?.feedbackType as ChatMessageRatingType[] | undefined
|
||||
if (feedbackTypeFilters) {
|
||||
feedbackTypeFilters = getFeedbackTypeFilters(feedbackTypeFilters)
|
||||
}
|
||||
const apiResponse = await chatMessagesService.getAllInternalChatMessages(
|
||||
req.params.id,
|
||||
chatType.INTERNAL,
|
||||
ChatType.INTERNAL,
|
||||
sortOrder,
|
||||
chatId,
|
||||
memoryType,
|
||||
@@ -115,7 +126,8 @@ const getAllInternalChatMessages = async (req: Request, res: Response, next: Nex
|
||||
startDate,
|
||||
endDate,
|
||||
messageId,
|
||||
feedback
|
||||
feedback,
|
||||
feedbackTypeFilters
|
||||
)
|
||||
return res.json(parseAPIResponse(apiResponse))
|
||||
} catch (error) {
|
||||
@@ -123,7 +135,6 @@ const getAllInternalChatMessages = async (req: Request, res: Response, next: Nex
|
||||
}
|
||||
}
|
||||
|
||||
//Delete all chatmessages from chatId
|
||||
const removeAllChatMessages = async (req: Request, res: Response, next: NextFunction) => {
|
||||
try {
|
||||
const appServer = getRunningExpressApp()
|
||||
@@ -138,35 +149,102 @@ const removeAllChatMessages = async (req: Request, res: Response, next: NextFunc
|
||||
if (!chatflow) {
|
||||
return res.status(404).send(`Chatflow ${req.params.id} not found`)
|
||||
}
|
||||
const chatId = req.query?.chatId as string
|
||||
const memoryType = req.query?.memoryType as string | undefined
|
||||
const sessionId = req.query?.sessionId as string | undefined
|
||||
const chatType = req.query?.chatType as string | undefined
|
||||
const isClearFromViewMessageDialog = req.query?.isClearFromViewMessageDialog as string | undefined
|
||||
const flowData = chatflow.flowData
|
||||
const parsedFlowData: IReactFlowObject = JSON.parse(flowData)
|
||||
const nodes = parsedFlowData.nodes
|
||||
try {
|
||||
await clearSessionMemory(
|
||||
nodes,
|
||||
appServer.nodesPool.componentNodes,
|
||||
chatId,
|
||||
appServer.AppDataSource,
|
||||
sessionId,
|
||||
memoryType,
|
||||
isClearFromViewMessageDialog
|
||||
)
|
||||
} catch (e) {
|
||||
return res.status(500).send('Error clearing chat messages')
|
||||
const chatId = req.query?.chatId as string
|
||||
const memoryType = req.query?.memoryType as string | undefined
|
||||
const sessionId = req.query?.sessionId as string | undefined
|
||||
const _chatType = req.query?.chatType as string | undefined
|
||||
const startDate = req.query?.startDate as string | undefined
|
||||
const endDate = req.query?.endDate as string | undefined
|
||||
const isClearFromViewMessageDialog = req.query?.isClearFromViewMessageDialog as string | undefined
|
||||
let feedbackTypeFilters = req.query?.feedbackType as ChatMessageRatingType[] | undefined
|
||||
if (feedbackTypeFilters) {
|
||||
feedbackTypeFilters = getFeedbackTypeFilters(feedbackTypeFilters)
|
||||
}
|
||||
|
||||
const deleteOptions: FindOptionsWhere<ChatMessage> = { chatflowid }
|
||||
if (chatId) deleteOptions.chatId = chatId
|
||||
if (memoryType) deleteOptions.memoryType = memoryType
|
||||
if (sessionId) deleteOptions.sessionId = sessionId
|
||||
if (chatType) deleteOptions.chatType = chatType
|
||||
const apiResponse = await chatMessagesService.removeAllChatMessages(chatId, chatflowid, deleteOptions)
|
||||
return res.json(apiResponse)
|
||||
if (!chatId) {
|
||||
const isFeedback = feedbackTypeFilters?.length ? true : false
|
||||
const hardDelete = req.query?.hardDelete as boolean | undefined
|
||||
const messages = await utilGetChatMessage(
|
||||
chatflowid,
|
||||
_chatType as ChatType | undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
startDate,
|
||||
endDate,
|
||||
undefined,
|
||||
isFeedback,
|
||||
feedbackTypeFilters
|
||||
)
|
||||
const messageIds = messages.map((message) => message.id)
|
||||
|
||||
// Categorize by chatId_memoryType_sessionId
|
||||
const chatIdMap = new Map<string, ChatMessage[]>()
|
||||
messages.forEach((message) => {
|
||||
const chatId = message.chatId
|
||||
const memoryType = message.memoryType
|
||||
const sessionId = message.sessionId
|
||||
const composite_key = `${chatId}_${memoryType}_${sessionId}`
|
||||
if (!chatIdMap.has(composite_key)) {
|
||||
chatIdMap.set(composite_key, [])
|
||||
}
|
||||
chatIdMap.get(composite_key)?.push(message)
|
||||
})
|
||||
|
||||
// If hardDelete is ON, we clearSessionMemory from third party integrations
|
||||
if (hardDelete) {
|
||||
for (const [composite_key] of chatIdMap) {
|
||||
const [chatId, memoryType, sessionId] = composite_key.split('_')
|
||||
try {
|
||||
await clearSessionMemory(
|
||||
nodes,
|
||||
appServer.nodesPool.componentNodes,
|
||||
chatId,
|
||||
appServer.AppDataSource,
|
||||
sessionId,
|
||||
memoryType,
|
||||
isClearFromViewMessageDialog
|
||||
)
|
||||
} catch (e) {
|
||||
console.error('Error clearing chat messages')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const apiResponse = await chatMessagesService.removeChatMessagesByMessageIds(chatflowid, chatIdMap, messageIds)
|
||||
return res.json(apiResponse)
|
||||
} else {
|
||||
try {
|
||||
await clearSessionMemory(
|
||||
nodes,
|
||||
appServer.nodesPool.componentNodes,
|
||||
chatId,
|
||||
appServer.AppDataSource,
|
||||
sessionId,
|
||||
memoryType,
|
||||
isClearFromViewMessageDialog
|
||||
)
|
||||
} catch (e) {
|
||||
return res.status(500).send('Error clearing chat messages')
|
||||
}
|
||||
|
||||
const deleteOptions: FindOptionsWhere<ChatMessage> = { chatflowid }
|
||||
if (chatId) deleteOptions.chatId = chatId
|
||||
if (memoryType) deleteOptions.memoryType = memoryType
|
||||
if (sessionId) deleteOptions.sessionId = sessionId
|
||||
if (_chatType) deleteOptions.chatType = _chatType
|
||||
if (startDate && endDate) {
|
||||
const fromDate = setDateToStartOrEndOfDay(startDate, 'start')
|
||||
const toDate = setDateToStartOrEndOfDay(endDate, 'end')
|
||||
deleteOptions.createdDate = Between(fromDate ?? aMonthAgo(), toDate ?? new Date())
|
||||
}
|
||||
const apiResponse = await chatMessagesService.removeAllChatMessages(chatId, chatflowid, deleteOptions)
|
||||
return res.json(apiResponse)
|
||||
}
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { StatusCodes } from 'http-status-codes'
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import statsService from '../../services/stats'
|
||||
import { ChatMessageRatingType, chatType } from '../../Interface'
|
||||
import { ChatMessageRatingType, ChatType } from '../../Interface'
|
||||
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
||||
import { getErrorMessage } from '../../errors/utils'
|
||||
|
||||
@@ -11,19 +11,19 @@ const getChatflowStats = async (req: Request, res: Response, next: NextFunction)
|
||||
throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: statsController.getChatflowStats - id not provided!`)
|
||||
}
|
||||
const chatflowid = req.params.id
|
||||
let chatTypeFilter = req.query?.chatType as chatType | undefined
|
||||
let chatTypeFilter = req.query?.chatType as ChatType | undefined
|
||||
const startDate = req.query?.startDate as string | undefined
|
||||
const endDate = req.query?.endDate as string | undefined
|
||||
let feedbackTypeFilters = req.query?.feedbackType as ChatMessageRatingType[] | undefined
|
||||
if (chatTypeFilter) {
|
||||
try {
|
||||
const chatTypeFilterArray = JSON.parse(chatTypeFilter)
|
||||
if (chatTypeFilterArray.includes(chatType.EXTERNAL) && chatTypeFilterArray.includes(chatType.INTERNAL)) {
|
||||
if (chatTypeFilterArray.includes(ChatType.EXTERNAL) && chatTypeFilterArray.includes(ChatType.INTERNAL)) {
|
||||
chatTypeFilter = undefined
|
||||
} else if (chatTypeFilterArray.includes(chatType.EXTERNAL)) {
|
||||
chatTypeFilter = chatType.EXTERNAL
|
||||
} else if (chatTypeFilterArray.includes(chatType.INTERNAL)) {
|
||||
chatTypeFilter = chatType.INTERNAL
|
||||
} else if (chatTypeFilterArray.includes(ChatType.EXTERNAL)) {
|
||||
chatTypeFilter = ChatType.EXTERNAL
|
||||
} else if (chatTypeFilterArray.includes(ChatType.INTERNAL)) {
|
||||
chatTypeFilter = ChatType.INTERNAL
|
||||
}
|
||||
} catch (e) {
|
||||
throw new InternalFlowiseError(
|
||||
|
||||
Reference in New Issue
Block a user