mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 15:00:57 +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:
@@ -4,7 +4,7 @@ export type MessageType = 'apiMessage' | 'userMessage'
|
||||
|
||||
export type ChatflowType = 'CHATFLOW' | 'MULTIAGENT'
|
||||
|
||||
export enum chatType {
|
||||
export enum ChatType {
|
||||
INTERNAL = 'INTERNAL',
|
||||
EXTERNAL = 'EXTERNAL'
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -136,7 +136,8 @@ export class App {
|
||||
'/api/v1/get-upload-file',
|
||||
'/api/v1/ip',
|
||||
'/api/v1/ping',
|
||||
'/api/v1/version'
|
||||
'/api/v1/version',
|
||||
'/api/v1/attachments'
|
||||
]
|
||||
const URL_CASE_INSENSITIVE_REGEX: RegExp = /\/api\/v1\//i
|
||||
const URL_CASE_SENSITIVE_REGEX: RegExp = /\/api\/v1\//
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import express from 'express'
|
||||
import multer from 'multer'
|
||||
import path from 'path'
|
||||
import attachmentsController from '../../controllers/attachments'
|
||||
|
||||
const router = express.Router()
|
||||
|
||||
const upload = multer({ dest: `${path.join(__dirname, '..', '..', '..', 'uploads')}/` })
|
||||
|
||||
// CREATE
|
||||
router.post('/:chatflowId/:chatId', upload.array('files'), attachmentsController.createAttachment)
|
||||
|
||||
export default router
|
||||
@@ -1,6 +1,7 @@
|
||||
import express from 'express'
|
||||
import apikeyRouter from './apikey'
|
||||
import assistantsRouter from './assistants'
|
||||
import attachmentsRouter from './attachments'
|
||||
import chatMessageRouter from './chat-messages'
|
||||
import chatflowsRouter from './chatflows'
|
||||
import chatflowsStreamingRouter from './chatflows-streaming'
|
||||
@@ -47,6 +48,7 @@ const router = express.Router()
|
||||
router.use('/ping', pingRouter)
|
||||
router.use('/apikey', apikeyRouter)
|
||||
router.use('/assistants', assistantsRouter)
|
||||
router.use('/attachments', attachmentsRouter)
|
||||
router.use('/chatflows', chatflowsRouter)
|
||||
router.use('/chatflows-streaming', chatflowsStreamingRouter)
|
||||
router.use('/chatmessage', chatMessageRouter)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { Request } from 'express'
|
||||
import { StatusCodes } from 'http-status-codes'
|
||||
import { createFileAttachment } from '../../utils/createAttachment'
|
||||
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
|
||||
import { getErrorMessage } from '../../errors/utils'
|
||||
|
||||
const createAttachment = async (req: Request) => {
|
||||
try {
|
||||
return await createFileAttachment(req)
|
||||
} catch (error) {
|
||||
throw new InternalFlowiseError(
|
||||
StatusCodes.INTERNAL_SERVER_ERROR,
|
||||
`Error: attachmentService.createAttachment - ${getErrorMessage(error)}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
createAttachment
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { DeleteResult, FindOptionsWhere } from 'typeorm'
|
||||
import { StatusCodes } from 'http-status-codes'
|
||||
import { ChatMessageRatingType, chatType, IChatMessage } from '../../Interface'
|
||||
import { ChatMessageRatingType, ChatType, IChatMessage } from '../../Interface'
|
||||
import { utilGetChatMessage } from '../../utils/getChatMessage'
|
||||
import { utilAddChatMessage } from '../../utils/addChatMesage'
|
||||
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
|
||||
@@ -27,7 +27,7 @@ const createChatMessage = async (chatMessage: Partial<IChatMessage>) => {
|
||||
// Get all chatmessages from chatflowid
|
||||
const getAllChatMessages = async (
|
||||
chatflowId: string,
|
||||
chatTypeFilter: chatType | undefined,
|
||||
chatTypeFilter: ChatType | undefined,
|
||||
sortOrder: string = 'ASC',
|
||||
chatId?: string,
|
||||
memoryType?: string,
|
||||
@@ -64,7 +64,7 @@ const getAllChatMessages = async (
|
||||
// Get internal chatmessages from chatflowid
|
||||
const getAllInternalChatMessages = async (
|
||||
chatflowId: string,
|
||||
chatTypeFilter: chatType | undefined,
|
||||
chatTypeFilter: ChatType | undefined,
|
||||
sortOrder: string = 'ASC',
|
||||
chatId?: string,
|
||||
memoryType?: string,
|
||||
@@ -128,6 +128,35 @@ const removeAllChatMessages = async (
|
||||
}
|
||||
}
|
||||
|
||||
const removeChatMessagesByMessageIds = async (
|
||||
chatflowid: string,
|
||||
chatIdMap: Map<string, ChatMessage[]>,
|
||||
messageIds: string[]
|
||||
): Promise<DeleteResult> => {
|
||||
try {
|
||||
const appServer = getRunningExpressApp()
|
||||
|
||||
for (const [composite_key] of chatIdMap) {
|
||||
const [chatId] = composite_key.split('_')
|
||||
|
||||
// Remove all related feedback records
|
||||
const feedbackDeleteOptions: FindOptionsWhere<ChatMessageFeedback> = { chatId }
|
||||
await appServer.AppDataSource.getRepository(ChatMessageFeedback).delete(feedbackDeleteOptions)
|
||||
|
||||
// Delete all uploads corresponding to this chatflow/chatId
|
||||
await removeFilesFromStorage(chatflowid, chatId)
|
||||
}
|
||||
|
||||
const dbResponse = await appServer.AppDataSource.getRepository(ChatMessage).delete(messageIds)
|
||||
return dbResponse
|
||||
} catch (error) {
|
||||
throw new InternalFlowiseError(
|
||||
StatusCodes.INTERNAL_SERVER_ERROR,
|
||||
`Error: chatMessagesService.removeAllChatMessages - ${getErrorMessage(error)}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const abortChatMessage = async (chatId: string, chatflowid: string) => {
|
||||
try {
|
||||
const appServer = getRunningExpressApp()
|
||||
@@ -155,5 +184,6 @@ export default {
|
||||
getAllChatMessages,
|
||||
getAllInternalChatMessages,
|
||||
removeAllChatMessages,
|
||||
removeChatMessagesByMessageIds,
|
||||
abortChatMessage
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
removeSpecificFileFromStorage
|
||||
} from 'flowise-components'
|
||||
import {
|
||||
chatType,
|
||||
ChatType,
|
||||
DocumentStoreStatus,
|
||||
IDocumentStoreFileChunkPagedResponse,
|
||||
IDocumentStoreLoader,
|
||||
@@ -995,7 +995,7 @@ const _insertIntoVectorStoreWorkerThread = async (data: ICommonObject) => {
|
||||
data: {
|
||||
version: await getAppVersion(),
|
||||
chatlowId: chatflowid,
|
||||
type: chatType.INTERNAL,
|
||||
type: ChatType.INTERNAL,
|
||||
flowGraph: omit(indexResult['result'], ['totalKeys', 'addedDocs'])
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { StatusCodes } from 'http-status-codes'
|
||||
import { ChatMessageRatingType, chatType } from '../../Interface'
|
||||
import { ChatMessageRatingType, ChatType } from '../../Interface'
|
||||
import { ChatMessage } from '../../database/entities/ChatMessage'
|
||||
import { utilGetChatMessage } from '../../utils/getChatMessage'
|
||||
import { ChatMessageFeedback } from '../../database/entities/ChatMessageFeedback'
|
||||
@@ -9,7 +9,7 @@ import { getErrorMessage } from '../../errors/utils'
|
||||
// get stats for showing in chatflow
|
||||
const getChatflowStats = async (
|
||||
chatflowid: string,
|
||||
chatTypeFilter: chatType | undefined,
|
||||
chatTypeFilter: ChatType | undefined,
|
||||
startDate?: string,
|
||||
endDate?: string,
|
||||
messageId?: string,
|
||||
|
||||
@@ -63,7 +63,8 @@ export const buildAgentGraph = async (
|
||||
isInternal: boolean,
|
||||
baseURL?: string,
|
||||
sseStreamer?: IServerSideEventStreamer,
|
||||
shouldStreamResponse?: boolean
|
||||
shouldStreamResponse?: boolean,
|
||||
uploadedFilesContent?: string
|
||||
): Promise<any> => {
|
||||
try {
|
||||
const appServer = getRunningExpressApp()
|
||||
@@ -129,7 +130,8 @@ export const buildAgentGraph = async (
|
||||
cachePool: appServer.cachePool,
|
||||
isUpsert: false,
|
||||
uploads: incomingInput.uploads,
|
||||
baseURL
|
||||
baseURL,
|
||||
uploadedFilesContent
|
||||
})
|
||||
|
||||
const options = {
|
||||
@@ -188,7 +190,8 @@ export const buildAgentGraph = async (
|
||||
chatHistory,
|
||||
incomingInput?.overrideConfig,
|
||||
sessionId || chatId,
|
||||
seqAgentNodes.some((node) => node.data.inputs?.summarization)
|
||||
seqAgentNodes.some((node) => node.data.inputs?.summarization),
|
||||
uploadedFilesContent
|
||||
)
|
||||
} else {
|
||||
isSequential = true
|
||||
@@ -204,7 +207,8 @@ export const buildAgentGraph = async (
|
||||
chatHistory,
|
||||
incomingInput?.overrideConfig,
|
||||
sessionId || chatId,
|
||||
incomingInput.action
|
||||
incomingInput.action,
|
||||
uploadedFilesContent
|
||||
)
|
||||
}
|
||||
|
||||
@@ -348,7 +352,6 @@ export const buildAgentGraph = async (
|
||||
if (isSequential && !finalResult && agentReasoning.length) {
|
||||
const lastMessages = agentReasoning[agentReasoning.length - 1].messages
|
||||
const lastAgentReasoningMessage = lastMessages[lastMessages.length - 1]
|
||||
|
||||
// If last message is an AI Message with tool calls, that means the last node was interrupted
|
||||
if (lastMessageRaw.tool_calls && lastMessageRaw.tool_calls.length > 0) {
|
||||
// The last node that got interrupted
|
||||
@@ -456,6 +459,7 @@ export const buildAgentGraph = async (
|
||||
* @param {ICommonObject} overrideConfig
|
||||
* @param {string} threadId
|
||||
* @param {boolean} summarization
|
||||
* @param {string} uploadedFilesContent,
|
||||
*/
|
||||
const compileMultiAgentsGraph = async (
|
||||
chatflow: IChatFlow,
|
||||
@@ -470,7 +474,8 @@ const compileMultiAgentsGraph = async (
|
||||
chatHistory: IMessage[] = [],
|
||||
overrideConfig?: ICommonObject,
|
||||
threadId?: string,
|
||||
summarization?: boolean
|
||||
summarization?: boolean,
|
||||
uploadedFilesContent?: string
|
||||
) => {
|
||||
const appServer = getRunningExpressApp()
|
||||
const channels: ITeamState = {
|
||||
@@ -502,7 +507,15 @@ const compileMultiAgentsGraph = async (
|
||||
|
||||
let flowNodeData = cloneDeep(workerNode.data)
|
||||
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
||||
flowNodeData = await resolveVariables(appServer.AppDataSource, flowNodeData, reactflowNodes, question, chatHistory, overrideConfig)
|
||||
flowNodeData = await resolveVariables(
|
||||
appServer.AppDataSource,
|
||||
flowNodeData,
|
||||
reactflowNodes,
|
||||
question,
|
||||
chatHistory,
|
||||
overrideConfig,
|
||||
uploadedFilesContent
|
||||
)
|
||||
|
||||
try {
|
||||
const workerResult: IMultiAgentNode = await newNodeInstance.init(flowNodeData, question, options)
|
||||
@@ -533,7 +546,15 @@ const compileMultiAgentsGraph = async (
|
||||
let flowNodeData = cloneDeep(supervisorNode.data)
|
||||
|
||||
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
||||
flowNodeData = await resolveVariables(appServer.AppDataSource, flowNodeData, reactflowNodes, question, chatHistory, overrideConfig)
|
||||
flowNodeData = await resolveVariables(
|
||||
appServer.AppDataSource,
|
||||
flowNodeData,
|
||||
reactflowNodes,
|
||||
question,
|
||||
chatHistory,
|
||||
overrideConfig,
|
||||
uploadedFilesContent
|
||||
)
|
||||
|
||||
if (flowNodeData.inputs) flowNodeData.inputs.workerNodes = supervisorWorkers[supervisor]
|
||||
|
||||
@@ -603,9 +624,10 @@ const compileMultiAgentsGraph = async (
|
||||
}
|
||||
|
||||
// Return stream result as we should only have 1 supervisor
|
||||
const finalQuestion = uploadedFilesContent ? `${uploadedFilesContent}\n\n${question}` : question
|
||||
return await graph.stream(
|
||||
{
|
||||
messages: [...prependMessages, new HumanMessage({ content: question })]
|
||||
messages: [...prependMessages, new HumanMessage({ content: finalQuestion })]
|
||||
},
|
||||
{ recursionLimit: supervisorResult?.recursionLimit ?? 100, callbacks: [loggerHandler, ...callbacks], configurable: config }
|
||||
)
|
||||
@@ -641,7 +663,8 @@ const compileSeqAgentsGraph = async (
|
||||
chatHistory: IMessage[] = [],
|
||||
overrideConfig?: ICommonObject,
|
||||
threadId?: string,
|
||||
action?: IAction
|
||||
action?: IAction,
|
||||
uploadedFilesContent?: string
|
||||
) => {
|
||||
const appServer = getRunningExpressApp()
|
||||
|
||||
@@ -693,7 +716,15 @@ const compileSeqAgentsGraph = async (
|
||||
|
||||
flowNodeData = cloneDeep(node.data)
|
||||
if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig)
|
||||
flowNodeData = await resolveVariables(appServer.AppDataSource, flowNodeData, reactflowNodes, question, chatHistory, overrideConfig)
|
||||
flowNodeData = await resolveVariables(
|
||||
appServer.AppDataSource,
|
||||
flowNodeData,
|
||||
reactflowNodes,
|
||||
question,
|
||||
chatHistory,
|
||||
overrideConfig,
|
||||
uploadedFilesContent
|
||||
)
|
||||
|
||||
const seqAgentNode: ISeqAgentNode = await newNodeInstance.init(flowNodeData, question, options)
|
||||
return seqAgentNode
|
||||
@@ -997,8 +1028,9 @@ const compileSeqAgentsGraph = async (
|
||||
}
|
||||
}
|
||||
|
||||
const finalQuestion = uploadedFilesContent ? `${uploadedFilesContent}\n\n${question}` : question
|
||||
let humanMsg: { messages: HumanMessage[] | ToolMessage[] } | null = {
|
||||
messages: [...prependMessages, new HumanMessage({ content: question })]
|
||||
messages: [...prependMessages, new HumanMessage({ content: finalQuestion })]
|
||||
}
|
||||
|
||||
if (action && action.mapping && question === action.mapping.approve) {
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
IReactFlowObject,
|
||||
IReactFlowNode,
|
||||
IDepthQueue,
|
||||
chatType,
|
||||
ChatType,
|
||||
IChatMessage,
|
||||
IChatFlow,
|
||||
IReactFlowEdge
|
||||
@@ -88,12 +88,14 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
}
|
||||
|
||||
let fileUploads: IFileUpload[] = []
|
||||
let uploadedFilesContent = ''
|
||||
if (incomingInput.uploads) {
|
||||
fileUploads = incomingInput.uploads
|
||||
for (let i = 0; i < fileUploads.length; i += 1) {
|
||||
const upload = fileUploads[i]
|
||||
|
||||
if ((upload.type === 'file' || upload.type === 'audio') && upload.data) {
|
||||
// if upload in an image, a rag file, or audio
|
||||
if ((upload.type === 'file' || upload.type === 'file:rag' || upload.type === 'audio') && upload.data) {
|
||||
const filename = upload.name
|
||||
const splitDataURI = upload.data.split(',')
|
||||
const bf = Buffer.from(splitDataURI.pop() || '', 'base64')
|
||||
@@ -139,6 +141,13 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (upload.type === 'file:full' && upload.data) {
|
||||
upload.type = 'stored-file:full'
|
||||
// Omit upload.data since we don't store the content in database
|
||||
uploadedFilesContent += `<doc name='${upload.name}'>${upload.data}</doc>\n\n`
|
||||
fileUploads[i] = omit(upload, ['data'])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +238,8 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
edges,
|
||||
baseURL,
|
||||
appServer.sseStreamer,
|
||||
true
|
||||
true,
|
||||
uploadedFilesContent
|
||||
)
|
||||
}
|
||||
|
||||
@@ -345,6 +355,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
apiMessageId,
|
||||
componentNodes: appServer.nodesPool.componentNodes,
|
||||
question: incomingInput.question,
|
||||
uploadedFilesContent,
|
||||
chatHistory,
|
||||
chatId,
|
||||
sessionId: sessionId ?? '',
|
||||
@@ -384,7 +395,8 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
reactFlowNodes,
|
||||
incomingInput.question,
|
||||
chatHistory,
|
||||
flowData
|
||||
flowData,
|
||||
uploadedFilesContent
|
||||
)
|
||||
nodeToExecuteData = reactFlowNodeData
|
||||
|
||||
@@ -398,6 +410,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
const nodeInstance = new nodeModule.nodeClass({ sessionId })
|
||||
|
||||
isStreamValid = (req.body.streaming === 'true' || req.body.streaming === true) && isStreamValid
|
||||
const finalQuestion = uploadedFilesContent ? `${uploadedFilesContent}\n\n${incomingInput.question}` : incomingInput.question
|
||||
|
||||
const runParams = {
|
||||
chatId,
|
||||
@@ -411,7 +424,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
prependMessages
|
||||
}
|
||||
|
||||
let result = await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
|
||||
let result = await nodeInstance.run(nodeToExecuteData, finalQuestion, {
|
||||
...runParams,
|
||||
...(isStreamValid && { sseStreamer: appServer.sseStreamer, shouldStreamResponse: true })
|
||||
})
|
||||
@@ -427,7 +440,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
role: 'userMessage',
|
||||
content: incomingInput.question,
|
||||
chatflowid,
|
||||
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
|
||||
chatType: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||
chatId,
|
||||
memoryType,
|
||||
sessionId,
|
||||
@@ -447,7 +460,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
role: 'apiMessage',
|
||||
content: resultText,
|
||||
chatflowid,
|
||||
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
|
||||
chatType: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||
chatId,
|
||||
memoryType,
|
||||
sessionId
|
||||
@@ -476,7 +489,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
|
||||
version: await getAppVersion(),
|
||||
chatflowId: chatflowid,
|
||||
chatId,
|
||||
type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
|
||||
type: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||
flowGraph: getTelemetryFlowObj(nodes, edges)
|
||||
})
|
||||
|
||||
@@ -517,7 +530,8 @@ const utilBuildAgentResponse = async (
|
||||
edges: IReactFlowEdge[],
|
||||
baseURL?: string,
|
||||
sseStreamer?: IServerSideEventStreamer,
|
||||
shouldStreamResponse?: boolean
|
||||
shouldStreamResponse?: boolean,
|
||||
uploadedFilesContent?: string
|
||||
) => {
|
||||
try {
|
||||
const appServer = getRunningExpressApp()
|
||||
@@ -530,7 +544,8 @@ const utilBuildAgentResponse = async (
|
||||
isInternal,
|
||||
baseURL,
|
||||
sseStreamer,
|
||||
shouldStreamResponse
|
||||
shouldStreamResponse,
|
||||
uploadedFilesContent
|
||||
)
|
||||
if (streamResults) {
|
||||
const { finalResult, finalAction, sourceDocuments, artifacts, usedTools, agentReasoning } = streamResults
|
||||
@@ -538,7 +553,7 @@ const utilBuildAgentResponse = async (
|
||||
role: 'userMessage',
|
||||
content: incomingInput.question,
|
||||
chatflowid: agentflow.id,
|
||||
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
|
||||
chatType: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||
chatId,
|
||||
memoryType,
|
||||
sessionId,
|
||||
@@ -553,7 +568,7 @@ const utilBuildAgentResponse = async (
|
||||
role: 'apiMessage',
|
||||
content: finalResult,
|
||||
chatflowid: agentflow.id,
|
||||
chatType: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
|
||||
chatType: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||
chatId,
|
||||
memoryType,
|
||||
sessionId
|
||||
@@ -581,7 +596,7 @@ const utilBuildAgentResponse = async (
|
||||
version: await getAppVersion(),
|
||||
agentflowId: agentflow.id,
|
||||
chatId,
|
||||
type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
|
||||
type: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||
flowGraph: getTelemetryFlowObj(nodes, edges)
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { Request } from 'express'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import { addArrayFilesToStorage, IDocument, mapExtToInputField, mapMimeTypeToInputField } from 'flowise-components'
|
||||
import { getRunningExpressApp } from './getRunningExpressApp'
|
||||
import { getErrorMessage } from '../errors/utils'
|
||||
|
||||
/**
|
||||
* Create attachment
|
||||
* @param {Request} req
|
||||
*/
|
||||
export const createFileAttachment = async (req: Request) => {
|
||||
const appServer = getRunningExpressApp()
|
||||
|
||||
const chatflowid = req.params.chatflowId
|
||||
if (!chatflowid) {
|
||||
throw new Error(
|
||||
'Params chatflowId is required! Please provide chatflowId and chatId in the URL: /api/v1/attachments/:chatflowId/:chatId'
|
||||
)
|
||||
}
|
||||
|
||||
const chatId = req.params.chatId
|
||||
if (!chatId) {
|
||||
throw new Error(
|
||||
'Params chatId is required! Please provide chatflowId and chatId in the URL: /api/v1/attachments/:chatflowId/:chatId'
|
||||
)
|
||||
}
|
||||
|
||||
// Find FileLoader node
|
||||
const fileLoaderComponent = appServer.nodesPool.componentNodes['fileLoader']
|
||||
const fileLoaderNodeInstanceFilePath = fileLoaderComponent.filePath as string
|
||||
const fileLoaderNodeModule = await import(fileLoaderNodeInstanceFilePath)
|
||||
const fileLoaderNodeInstance = new fileLoaderNodeModule.nodeClass()
|
||||
const options = {
|
||||
retrieveAttachmentChatId: true,
|
||||
chatflowid,
|
||||
chatId
|
||||
}
|
||||
const files = (req.files as Express.Multer.File[]) || []
|
||||
const fileAttachments = []
|
||||
if (files.length) {
|
||||
for (const file of files) {
|
||||
const fileBuffer = fs.readFileSync(file.path)
|
||||
const fileNames: string[] = []
|
||||
const storagePath = await addArrayFilesToStorage(file.mimetype, fileBuffer, file.originalname, fileNames, chatflowid, chatId)
|
||||
|
||||
const fileInputFieldFromMimeType = mapMimeTypeToInputField(file.mimetype)
|
||||
|
||||
const fileExtension = path.extname(file.originalname)
|
||||
|
||||
const fileInputFieldFromExt = mapExtToInputField(fileExtension)
|
||||
|
||||
let fileInputField = 'txtFile'
|
||||
|
||||
if (fileInputFieldFromExt !== 'txtFile') {
|
||||
fileInputField = fileInputFieldFromExt
|
||||
} else if (fileInputFieldFromMimeType !== 'txtFile') {
|
||||
fileInputField = fileInputFieldFromExt
|
||||
}
|
||||
|
||||
fs.unlinkSync(file.path)
|
||||
|
||||
try {
|
||||
const nodeData = {
|
||||
inputs: {
|
||||
[fileInputField]: storagePath
|
||||
}
|
||||
}
|
||||
const documents: IDocument[] = await fileLoaderNodeInstance.init(nodeData, '', options)
|
||||
const pageContents = documents.map((doc) => doc.pageContent).join('\n')
|
||||
fileAttachments.push({
|
||||
name: file.originalname,
|
||||
mimeType: file.mimetype,
|
||||
size: file.size,
|
||||
content: pageContents
|
||||
})
|
||||
} catch (error) {
|
||||
throw new Error(`Failed operation: createFileAttachment - ${getErrorMessage(error)}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fileAttachments
|
||||
}
|
||||
@@ -1,13 +1,14 @@
|
||||
import { MoreThanOrEqual, LessThanOrEqual } from 'typeorm'
|
||||
import { ChatMessageRatingType, chatType } from '../Interface'
|
||||
import { ChatMessageRatingType, ChatType } from '../Interface'
|
||||
import { ChatMessage } from '../database/entities/ChatMessage'
|
||||
import { ChatMessageFeedback } from '../database/entities/ChatMessageFeedback'
|
||||
import { getRunningExpressApp } from '../utils/getRunningExpressApp'
|
||||
import { aMonthAgo, setDateToStartOrEndOfDay } from '.'
|
||||
|
||||
/**
|
||||
* Method that get chat messages.
|
||||
* @param {string} chatflowid
|
||||
* @param {chatType} chatType
|
||||
* @param {ChatType} chatType
|
||||
* @param {string} sortOrder
|
||||
* @param {string} chatId
|
||||
* @param {string} memoryType
|
||||
@@ -19,7 +20,7 @@ import { getRunningExpressApp } from '../utils/getRunningExpressApp'
|
||||
*/
|
||||
export const utilGetChatMessage = async (
|
||||
chatflowid: string,
|
||||
chatType: chatType | undefined,
|
||||
chatType: ChatType | undefined,
|
||||
sortOrder: string = 'ASC',
|
||||
chatId?: string,
|
||||
memoryType?: string,
|
||||
@@ -31,20 +32,6 @@ export const utilGetChatMessage = async (
|
||||
feedbackTypes?: ChatMessageRatingType[]
|
||||
): Promise<ChatMessage[]> => {
|
||||
const appServer = getRunningExpressApp()
|
||||
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
|
||||
}
|
||||
|
||||
const aMonthAgo = () => {
|
||||
const date = new Date()
|
||||
date.setMonth(new Date().getMonth() - 1)
|
||||
return date
|
||||
}
|
||||
|
||||
let fromDate
|
||||
if (startDate) fromDate = setDateToStartOrEndOfDay(startDate, 'start')
|
||||
|
||||
@@ -8,7 +8,7 @@ import { InternalFlowiseError } from '../errors/internalFlowiseError'
|
||||
type IUploadConfig = {
|
||||
isSpeechToTextEnabled: boolean
|
||||
isImageUploadAllowed: boolean
|
||||
isFileUploadAllowed: boolean
|
||||
isRAGFileUploadAllowed: boolean
|
||||
imgUploadSizeAndTypes: IUploadFileSizeAndTypes[]
|
||||
fileUploadSizeAndTypes: IUploadFileSizeAndTypes[]
|
||||
}
|
||||
@@ -32,7 +32,7 @@ export const utilGetUploadsConfig = async (chatflowid: string): Promise<IUploadC
|
||||
|
||||
let isSpeechToTextEnabled = false
|
||||
let isImageUploadAllowed = false
|
||||
let isFileUploadAllowed = false
|
||||
let isRAGFileUploadAllowed = false
|
||||
|
||||
/*
|
||||
* Check for STT
|
||||
@@ -51,7 +51,7 @@ export const utilGetUploadsConfig = async (chatflowid: string): Promise<IUploadC
|
||||
}
|
||||
|
||||
/*
|
||||
* Condition for isFileUploadAllowed
|
||||
* Condition for isRAGFileUploadAllowed
|
||||
* 1.) vector store with fileUpload = true && connected to a document loader with fileType
|
||||
*/
|
||||
const fileUploadSizeAndTypes: IUploadFileSizeAndTypes[] = []
|
||||
@@ -70,7 +70,7 @@ export const utilGetUploadsConfig = async (chatflowid: string): Promise<IUploadC
|
||||
fileTypes: fileType.split(', '),
|
||||
maxUploadSize: 500
|
||||
})
|
||||
isFileUploadAllowed = true
|
||||
isRAGFileUploadAllowed = true
|
||||
}
|
||||
}
|
||||
break
|
||||
@@ -114,7 +114,7 @@ export const utilGetUploadsConfig = async (chatflowid: string): Promise<IUploadC
|
||||
return {
|
||||
isSpeechToTextEnabled,
|
||||
isImageUploadAllowed,
|
||||
isFileUploadAllowed,
|
||||
isRAGFileUploadAllowed,
|
||||
imgUploadSizeAndTypes,
|
||||
fileUploadSizeAndTypes
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import { InternalFlowiseError } from '../errors/internalFlowiseError'
|
||||
import { StatusCodes } from 'http-status-codes'
|
||||
|
||||
const QUESTION_VAR_PREFIX = 'question'
|
||||
const FILE_ATTACHMENT_PREFIX = 'file_attachment'
|
||||
const CHAT_HISTORY_VAR_PREFIX = 'chat_history'
|
||||
const REDACTED_CREDENTIAL_VALUE = '_FLOWISE_BLANK_07167752-1a71-43b1-bf8f-4f32252165db'
|
||||
|
||||
@@ -438,6 +439,7 @@ type BuildFlowParams = {
|
||||
stopNodeId?: string
|
||||
uploads?: IFileUpload[]
|
||||
baseURL?: string
|
||||
uploadedFilesContent?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -452,6 +454,7 @@ export const buildFlow = async ({
|
||||
depthQueue,
|
||||
componentNodes,
|
||||
question,
|
||||
uploadedFilesContent,
|
||||
chatHistory,
|
||||
apiMessageId,
|
||||
chatId,
|
||||
@@ -516,7 +519,8 @@ export const buildFlow = async ({
|
||||
flowNodes,
|
||||
question,
|
||||
chatHistory,
|
||||
flowData
|
||||
flowData,
|
||||
uploadedFilesContent
|
||||
)
|
||||
|
||||
if (isUpsert && stopNodeId && nodeId === stopNodeId) {
|
||||
@@ -546,7 +550,8 @@ export const buildFlow = async ({
|
||||
initializedNodes.add(nodeId)
|
||||
} else {
|
||||
logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||
let outputResult = await newNodeInstance.init(reactFlowNodeData, question, {
|
||||
const finalQuestion = uploadedFilesContent ? `${uploadedFilesContent}\n\n${question}` : question
|
||||
let outputResult = await newNodeInstance.init(reactFlowNodeData, finalQuestion, {
|
||||
chatId,
|
||||
sessionId,
|
||||
chatflowid,
|
||||
@@ -770,7 +775,8 @@ export const getVariableValue = async (
|
||||
question: string,
|
||||
chatHistory: IMessage[],
|
||||
isAcceptVariable = false,
|
||||
flowData?: ICommonObject
|
||||
flowData?: ICommonObject,
|
||||
uploadedFilesContent?: string
|
||||
) => {
|
||||
const isObject = typeof paramValue === 'object'
|
||||
const initialValue = (isObject ? JSON.stringify(paramValue) : paramValue) ?? ''
|
||||
@@ -803,6 +809,10 @@ export const getVariableValue = async (
|
||||
variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(question, false)
|
||||
}
|
||||
|
||||
if (isAcceptVariable && variableFullPath === FILE_ATTACHMENT_PREFIX) {
|
||||
variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(uploadedFilesContent, false)
|
||||
}
|
||||
|
||||
if (isAcceptVariable && variableFullPath === CHAT_HISTORY_VAR_PREFIX) {
|
||||
variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(convertChatHistoryToText(chatHistory), false)
|
||||
}
|
||||
@@ -916,7 +926,8 @@ export const resolveVariables = async (
|
||||
reactFlowNodes: IReactFlowNode[],
|
||||
question: string,
|
||||
chatHistory: IMessage[],
|
||||
flowData?: ICommonObject
|
||||
flowData?: ICommonObject,
|
||||
uploadedFilesContent?: string
|
||||
): Promise<INodeData> => {
|
||||
let flowNodeData = cloneDeep(reactFlowNodeData)
|
||||
const types = 'inputs'
|
||||
@@ -934,7 +945,8 @@ export const resolveVariables = async (
|
||||
question,
|
||||
chatHistory,
|
||||
undefined,
|
||||
flowData
|
||||
flowData,
|
||||
uploadedFilesContent
|
||||
)
|
||||
resolvedInstances.push(resolvedInstance)
|
||||
}
|
||||
@@ -948,7 +960,8 @@ export const resolveVariables = async (
|
||||
question,
|
||||
chatHistory,
|
||||
isAcceptVariable,
|
||||
flowData
|
||||
flowData,
|
||||
uploadedFilesContent
|
||||
)
|
||||
paramsObj[key] = resolvedInstance
|
||||
}
|
||||
@@ -1572,3 +1585,18 @@ export const convertToValidFilename = (word: string) => {
|
||||
.replace(' ', '')
|
||||
.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 = () => {
|
||||
const date = new Date()
|
||||
date.setMonth(new Date().getMonth() - 1)
|
||||
return date
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
getStartingNodes
|
||||
} from '../utils'
|
||||
import { validateChatflowAPIKey } from './validateKey'
|
||||
import { IncomingInput, INodeDirectedGraph, IReactFlowObject, chatType } from '../Interface'
|
||||
import { IncomingInput, INodeDirectedGraph, IReactFlowObject, ChatType } from '../Interface'
|
||||
import { ChatFlow } from '../database/entities/ChatFlow'
|
||||
import { getRunningExpressApp } from '../utils/getRunningExpressApp'
|
||||
import { UpsertHistory } from '../database/entities/UpsertHistory'
|
||||
@@ -195,7 +195,7 @@ export const upsertVector = async (req: Request, isInternal: boolean = false) =>
|
||||
data: {
|
||||
version: await getAppVersion(),
|
||||
chatlowId: chatflowid,
|
||||
type: isInternal ? chatType.INTERNAL : chatType.EXTERNAL,
|
||||
type: isInternal ? ChatType.INTERNAL : ChatType.EXTERNAL,
|
||||
flowGraph: getTelemetryFlowObj(nodes, edges),
|
||||
stopNodeId
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user