mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-29 03:01:10 +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:
@@ -121,11 +121,22 @@ class File_DocumentLoaders implements INode {
|
||||
}
|
||||
const chatflowid = options.chatflowid
|
||||
|
||||
for (const file of files) {
|
||||
if (!file) continue
|
||||
const fileData = await getFileFromStorage(file, chatflowid)
|
||||
const blob = new Blob([fileData])
|
||||
fileBlobs.push({ blob, ext: file.split('.').pop() || '' })
|
||||
// specific to createAttachment to get files from chatId
|
||||
const retrieveAttachmentChatId = options.retrieveAttachmentChatId
|
||||
if (retrieveAttachmentChatId) {
|
||||
for (const file of files) {
|
||||
if (!file) continue
|
||||
const fileData = await getFileFromStorage(file, chatflowid, options.chatId)
|
||||
const blob = new Blob([fileData])
|
||||
fileBlobs.push({ blob, ext: file.split('.').pop() || '' })
|
||||
}
|
||||
} else {
|
||||
for (const file of files) {
|
||||
if (!file) continue
|
||||
const fileData = await getFileFromStorage(file, chatflowid)
|
||||
const blob = new Blob([fileData])
|
||||
fileBlobs.push({ blob, ext: file.split('.').pop() || '' })
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (totalFiles.startsWith('[') && totalFiles.endsWith(']')) {
|
||||
@@ -288,7 +299,12 @@ class MultiFileLoader extends BaseDocumentLoader {
|
||||
const loader = loaderFactory(fileBlob.blob)
|
||||
documents.push(...(await loader.load()))
|
||||
} else {
|
||||
throw new Error(`Error loading file`)
|
||||
const loader = new TextLoader(fileBlob.blob)
|
||||
try {
|
||||
documents.push(...(await loader.load()))
|
||||
} catch (error) {
|
||||
throw new Error(`Error loading file`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,9 @@ const howToUseCode = `
|
||||
"sourceDocuments": [
|
||||
{
|
||||
"pageContent": "This is the page content",
|
||||
"metadata": "{foo: var}",
|
||||
"metadata": "{foo: var}"
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
@@ -102,10 +102,10 @@ const howToUse = `
|
||||
|-----------|-----------|
|
||||
| user | john doe |
|
||||
|
||||
2. If you want to use the agent's output as the value to update state, it is available as available as \`$flow.output\` with the following structure:
|
||||
2. If you want to use the Agent's output as the value to update state, it is available as available as \`$flow.output\` with the following structure:
|
||||
\`\`\`json
|
||||
{
|
||||
"output": "Hello! How can I assist you today?",
|
||||
"content": "Hello! How can I assist you today?",
|
||||
"usedTools": [
|
||||
{
|
||||
"tool": "tool-name",
|
||||
@@ -116,9 +116,9 @@ const howToUse = `
|
||||
"sourceDocuments": [
|
||||
{
|
||||
"pageContent": "This is the page content",
|
||||
"metadata": "{foo: var}",
|
||||
"metadata": "{foo: var}"
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
@@ -195,7 +195,7 @@ class Agent_SeqAgents implements INode {
|
||||
constructor() {
|
||||
this.label = 'Agent'
|
||||
this.name = 'seqAgent'
|
||||
this.version = 3.0
|
||||
this.version = 3.1
|
||||
this.type = 'Agent'
|
||||
this.icon = 'seqAgent.png'
|
||||
this.category = 'Sequential Agents'
|
||||
|
||||
@@ -88,7 +88,7 @@ const howToUse = `
|
||||
|-----------|-----------|
|
||||
| user | john doe |
|
||||
|
||||
2. If you want to use the agent's output as the value to update state, it is available as available as \`$flow.output\` with the following structure:
|
||||
2. If you want to use the LLM Node's output as the value to update state, it is available as available as \`$flow.output\` with the following structure:
|
||||
\`\`\`json
|
||||
{
|
||||
"content": 'Hello! How can I assist you today?',
|
||||
|
||||
@@ -48,9 +48,9 @@ const howToUseCode = `
|
||||
"sourceDocuments": [
|
||||
{
|
||||
"pageContent": "This is the page content",
|
||||
"metadata": "{foo: var}",
|
||||
"metadata": "{foo: var}"
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
]
|
||||
\`\`\`
|
||||
@@ -64,7 +64,7 @@ const howToUseCode = `
|
||||
*/
|
||||
|
||||
return {
|
||||
"sources": $flow.output[0].sourceDocuments
|
||||
"sources": $flow.output[0].toolOutput
|
||||
}
|
||||
\`\`\`
|
||||
|
||||
@@ -89,17 +89,19 @@ const howToUse = `
|
||||
|-----------|-----------|
|
||||
| user | john doe |
|
||||
|
||||
2. If you want to use the agent's output as the value to update state, it is available as available as \`$flow.output\` with the following structure (array):
|
||||
2. If you want to use the Tool Node's output as the value to update state, it is available as available as \`$flow.output\` with the following structure (array):
|
||||
\`\`\`json
|
||||
[
|
||||
{
|
||||
"content": "Hello! How can I assist you today?",
|
||||
"tool": "tool's name",
|
||||
"toolInput": {},
|
||||
"toolOutput": "tool's output content",
|
||||
"sourceDocuments": [
|
||||
{
|
||||
"pageContent": "This is the page content",
|
||||
"metadata": "{foo: var}",
|
||||
"metadata": "{foo: var}"
|
||||
}
|
||||
],
|
||||
]
|
||||
}
|
||||
]
|
||||
\`\`\`
|
||||
@@ -107,7 +109,7 @@ const howToUse = `
|
||||
For example:
|
||||
| Key | Value |
|
||||
|--------------|-------------------------------------------|
|
||||
| sources | \`$flow.output[0].sourceDocuments\` |
|
||||
| sources | \`$flow.output[0].toolOutput\` |
|
||||
|
||||
3. You can get default flow config, including the current "state":
|
||||
- \`$flow.sessionId\`
|
||||
@@ -152,7 +154,7 @@ class ToolNode_SeqAgents implements INode {
|
||||
constructor() {
|
||||
this.label = 'Tool Node'
|
||||
this.name = 'seqToolNode'
|
||||
this.version = 2.0
|
||||
this.version = 2.1
|
||||
this.type = 'ToolNode'
|
||||
this.icon = 'toolNode.svg'
|
||||
this.category = 'Sequential Agents'
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as path from 'path'
|
||||
import { JSDOM } from 'jsdom'
|
||||
import { z } from 'zod'
|
||||
import { DataSource } from 'typeorm'
|
||||
import { ICommonObject, IDatabaseEntity, IMessage, INodeData, IVariable, MessageContentImageUrl } from './Interface'
|
||||
import { ICommonObject, IDatabaseEntity, IDocument, IMessage, INodeData, IVariable, MessageContentImageUrl } from './Interface'
|
||||
import { AES, enc } from 'crypto-js'
|
||||
import { AIMessage, HumanMessage, BaseMessage } from '@langchain/core/messages'
|
||||
import { getFileFromStorage } from './storageUtils'
|
||||
@@ -609,10 +609,11 @@ export const mapChatMessageToBaseMessage = async (chatmessages: any[] = []): Pro
|
||||
if (message.role === 'apiMessage' || message.type === 'apiMessage') {
|
||||
chatHistory.push(new AIMessage(message.content || ''))
|
||||
} else if (message.role === 'userMessage' || message.role === 'userMessage') {
|
||||
// check for image uploads
|
||||
// check for image/files uploads
|
||||
if (message.fileUploads) {
|
||||
// example: [{"type":"stored-file","name":"0_DiXc4ZklSTo3M8J4.jpg","mime":"image/jpeg"}]
|
||||
try {
|
||||
let messageWithFileUploads = ''
|
||||
const uploads = JSON.parse(message.fileUploads)
|
||||
const imageContents: MessageContentImageUrl[] = []
|
||||
for (const upload of uploads) {
|
||||
@@ -634,14 +635,32 @@ export const mapChatMessageToBaseMessage = async (chatmessages: any[] = []): Pro
|
||||
url: upload.data
|
||||
}
|
||||
})
|
||||
} else if (upload.type === 'stored-file:full') {
|
||||
const fileLoaderNodeModule = await import('../nodes/documentloaders/File/File')
|
||||
// @ts-ignore
|
||||
const fileLoaderNodeInstance = new fileLoaderNodeModule.nodeClass()
|
||||
const options = {
|
||||
retrieveAttachmentChatId: true,
|
||||
chatflowid: message.chatflowid,
|
||||
chatId: message.chatId
|
||||
}
|
||||
const nodeData = {
|
||||
inputs: {
|
||||
txtFile: `FILE-STORAGE::${JSON.stringify([upload.name])}`
|
||||
}
|
||||
}
|
||||
const documents: IDocument[] = await fileLoaderNodeInstance.init(nodeData, '', options)
|
||||
const pageContents = documents.map((doc) => doc.pageContent).join('\n')
|
||||
messageWithFileUploads += `<doc name='${upload.name}'>${pageContents}</doc>\n\n`
|
||||
}
|
||||
}
|
||||
const messageContent = messageWithFileUploads ? `${messageWithFileUploads}\n\n${message.content}` : message.content
|
||||
chatHistory.push(
|
||||
new HumanMessage({
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: message.content
|
||||
text: messageContent
|
||||
},
|
||||
...imageContents
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user