From 58e06718d1f3f95a31e9ece6d0b0a610f3da1092 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 10 Apr 2023 13:56:44 +0100 Subject: [PATCH] Add more nodes for agents, loaders --- .../ConversationalAgent.ts | 64 ++++++++++ .../agents/ConversationalAgent/agent.svg | 9 ++ .../agents/MRLKAgentChat/MRLKAgentChat.ts | 58 +++++++++ .../nodes/agents/MRLKAgentChat/agent.svg | 9 ++ .../nodes/agents/MRLKAgentLLM/MRLKAgentLLM.ts | 4 +- .../ConversationalRetrievalQAChain.ts | 74 ++++++++++++ .../ConversationalRetrievalQAChain/chain.svg | 6 + .../nodes/chains/LLMChain/LLMChain.ts | 47 +++++++- .../RetrievalQAChain/RetrievalQAChain.ts | 57 +++++++++ .../nodes/chains/RetrievalQAChain/chain.svg | 6 + .../nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts | 75 ++++++++++++ .../nodes/documentloaders/Github/Github.ts | 81 +++++++++++++ .../nodes/documentloaders/Github/github.png | Bin 0 -> 16945 bytes .../nodes/documentloaders/Pdf/Pdf.ts | 90 ++++++++++++++ .../nodes/documentloaders/Pdf/pdf.svg | 7 ++ .../nodes/documentloaders/Text/Text.ts | 61 ++++++++++ .../nodes/documentloaders/Text/textFile.svg | 7 ++ .../OpenAIEmbedding/OpenAIEmbedding.ts | 44 +++++++ .../embeddings/OpenAIEmbedding/openai.png | Bin 0 -> 3991 bytes .../HuggingFaceInference.ts | 64 ++++++++++ .../llms/HuggingFaceInference/huggingface.png | Bin 0 -> 120391 bytes .../nodes/memory/BufferMemory/BufferMemory.ts | 54 +++++++++ .../nodes/memory/BufferMemory/memory.svg | 8 ++ .../ChatPromptTemplate/ChatPromptTemplate.ts | 57 +++++++++ .../prompts/ChatPromptTemplate/prompt.svg | 6 + .../FewShotPromptTemplate.ts | 112 ++++++++++++++++++ .../prompts/FewShotPromptTemplate/prompt.svg | 6 + .../HumanMessagePromptTemplate.ts | 0 .../prompts/PromptTemplate/PromptTemplate.ts | 12 +- .../SysmtemMessagePromptTemplate.ts | 0 .../RecursiveCharacterTextSplitter.ts | 59 +++++++++ .../textsplitter.svg | 7 ++ .../Chroma_Existing/Chroma_Existing.ts | 52 ++++++++ .../vectorstores/Chroma_Existing/chroma.svg | 7 ++ .../Chroma_Upsert/Chroma_Upsert.ts | 65 ++++++++++ .../vectorstores/Chroma_Upsert/chroma.svg | 7 ++ .../Pinecone_Existing/Pinecone_Existing.ts | 73 ++++++++++++ .../Pinecone_Existing/pinecone.png | Bin 0 -> 2423 bytes .../Pinecone_Upsert/Pinecone_Upsert.ts | 86 ++++++++++++++ .../vectorstores/Pinecone_Upsert/pinecone.png | Bin 0 -> 2423 bytes packages/components/package.json | 5 + packages/components/src/Interface.ts | 10 +- packages/components/src/utils.ts | 7 ++ packages/server/src/ChatflowPool.ts | 43 +++++++ packages/server/src/Interface.ts | 16 ++- packages/server/src/NodesPool.ts | 4 +- packages/server/src/index.ts | 76 +++++++----- packages/server/src/utils/index.ts | 18 +-- packages/ui/src/store/actions.js | 1 - .../ui/src/store/context/ReactFlowContext.js | 10 +- .../ui/src/store/reducers/canvasReducer.js | 6 - packages/ui/src/ui-component/file/File.js | 57 +++++++++ packages/ui/src/views/canvas/ButtonEdge.js | 9 +- packages/ui/src/views/canvas/CanvasNode.js | 2 +- .../ui/src/views/canvas/NodeInputHandler.js | 8 ++ packages/ui/src/views/canvas/index.js | 13 -- .../ui/src/views/chatmessage/ChatMessage.js | 14 +-- 57 files changed, 1584 insertions(+), 89 deletions(-) create mode 100644 packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts create mode 100644 packages/components/nodes/agents/ConversationalAgent/agent.svg create mode 100644 packages/components/nodes/agents/MRLKAgentChat/MRLKAgentChat.ts create mode 100644 packages/components/nodes/agents/MRLKAgentChat/agent.svg create mode 100644 packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts create mode 100644 packages/components/nodes/chains/ConversationalRetrievalQAChain/chain.svg create mode 100644 packages/components/nodes/chains/RetrievalQAChain/RetrievalQAChain.ts create mode 100644 packages/components/nodes/chains/RetrievalQAChain/chain.svg create mode 100644 packages/components/nodes/documentloaders/Github/Github.ts create mode 100644 packages/components/nodes/documentloaders/Github/github.png create mode 100644 packages/components/nodes/documentloaders/Pdf/Pdf.ts create mode 100644 packages/components/nodes/documentloaders/Pdf/pdf.svg create mode 100644 packages/components/nodes/documentloaders/Text/Text.ts create mode 100644 packages/components/nodes/documentloaders/Text/textFile.svg create mode 100644 packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts create mode 100644 packages/components/nodes/embeddings/OpenAIEmbedding/openai.png create mode 100644 packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts create mode 100644 packages/components/nodes/llms/HuggingFaceInference/huggingface.png create mode 100644 packages/components/nodes/memory/BufferMemory/BufferMemory.ts create mode 100644 packages/components/nodes/memory/BufferMemory/memory.svg create mode 100644 packages/components/nodes/prompts/ChatPromptTemplate/prompt.svg create mode 100644 packages/components/nodes/prompts/FewShotPromptTemplate/FewShotPromptTemplate.ts create mode 100644 packages/components/nodes/prompts/FewShotPromptTemplate/prompt.svg delete mode 100644 packages/components/nodes/prompts/HumanMessagePromptTemplate/HumanMessagePromptTemplate.ts delete mode 100644 packages/components/nodes/prompts/SysmtemMessagePromptTemplate/SysmtemMessagePromptTemplate.ts create mode 100644 packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts create mode 100644 packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/textsplitter.svg create mode 100644 packages/components/nodes/vectorstores/Chroma_Existing/Chroma_Existing.ts create mode 100644 packages/components/nodes/vectorstores/Chroma_Existing/chroma.svg create mode 100644 packages/components/nodes/vectorstores/Chroma_Upsert/Chroma_Upsert.ts create mode 100644 packages/components/nodes/vectorstores/Chroma_Upsert/chroma.svg create mode 100644 packages/components/nodes/vectorstores/Pinecone_Existing/Pinecone_Existing.ts create mode 100644 packages/components/nodes/vectorstores/Pinecone_Existing/pinecone.png create mode 100644 packages/components/nodes/vectorstores/Pinecone_Upsert/Pinecone_Upsert.ts create mode 100644 packages/components/nodes/vectorstores/Pinecone_Upsert/pinecone.png create mode 100644 packages/server/src/ChatflowPool.ts create mode 100644 packages/ui/src/ui-component/file/File.js diff --git a/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts new file mode 100644 index 00000000..d3ff6f4d --- /dev/null +++ b/packages/components/nodes/agents/ConversationalAgent/ConversationalAgent.ts @@ -0,0 +1,64 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' + +class ConversationalAgent_Agents implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Conversational Agent' + this.name = 'conversationalAgent' + this.type = 'AgentExecutor' + this.category = 'Agents' + this.icon = 'agent.svg' + this.description = 'Conversational agent for a chat model. It will utilize chat specific prompts' + this.inputs = [ + { + label: 'Allowed Tools', + name: 'tools', + type: 'Tool', + list: true + }, + { + label: 'Chat Model', + name: 'model', + type: 'BaseChatModel' + }, + { + label: 'Memory', + name: 'memory', + type: 'BaseChatMemory' + } + ] + } + + async getBaseClasses(): Promise { + return ['AgentExecutor'] + } + + async init(nodeData: INodeData): Promise { + const { initializeAgentExecutor } = await import('langchain/agents') + + const model = nodeData.inputs?.model + const tools = nodeData.inputs?.tools + const memory = nodeData.inputs?.memory + + const executor = await initializeAgentExecutor(tools, model, 'chat-conversational-react-description', true) + executor.memory = memory + return executor + } + + async run(nodeData: INodeData, input: string): Promise { + const executor = nodeData.instance + const result = await executor.call({ input }) + + return result?.output + } +} + +module.exports = { nodeClass: ConversationalAgent_Agents } diff --git a/packages/components/nodes/agents/ConversationalAgent/agent.svg b/packages/components/nodes/agents/ConversationalAgent/agent.svg new file mode 100644 index 00000000..c87861e5 --- /dev/null +++ b/packages/components/nodes/agents/ConversationalAgent/agent.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/agents/MRLKAgentChat/MRLKAgentChat.ts b/packages/components/nodes/agents/MRLKAgentChat/MRLKAgentChat.ts new file mode 100644 index 00000000..207f9145 --- /dev/null +++ b/packages/components/nodes/agents/MRLKAgentChat/MRLKAgentChat.ts @@ -0,0 +1,58 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' + +class MRLKAgentChat_Agents implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'MRLK Agent for Chat Models' + this.name = 'mrlkAgentChat' + this.type = 'AgentExecutor' + this.category = 'Agents' + this.icon = 'agent.svg' + this.description = 'Agent that uses the ReAct Framework to decide what action to take, optimized to be used with Chat Models' + this.inputs = [ + { + label: 'Allowed Tools', + name: 'tools', + type: 'Tool', + list: true + }, + { + label: 'Chat Model', + name: 'model', + type: 'BaseChatModel' + } + ] + } + + async getBaseClasses(): Promise { + return ['AgentExecutor'] + } + + async init(nodeData: INodeData): Promise { + const { initializeAgentExecutor } = await import('langchain/agents') + + const model = nodeData.inputs?.model + const tools = nodeData.inputs?.tools + + const executor = await initializeAgentExecutor(tools, model, 'chat-zero-shot-react-description', true) + + return executor + } + + async run(nodeData: INodeData, input: string): Promise { + const executor = nodeData.instance + const result = await executor.call({ input }) + + return result?.output + } +} + +module.exports = { nodeClass: MRLKAgentChat_Agents } diff --git a/packages/components/nodes/agents/MRLKAgentChat/agent.svg b/packages/components/nodes/agents/MRLKAgentChat/agent.svg new file mode 100644 index 00000000..c87861e5 --- /dev/null +++ b/packages/components/nodes/agents/MRLKAgentChat/agent.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/agents/MRLKAgentLLM/MRLKAgentLLM.ts b/packages/components/nodes/agents/MRLKAgentLLM/MRLKAgentLLM.ts index 00ea31dd..1f5c636b 100644 --- a/packages/components/nodes/agents/MRLKAgentLLM/MRLKAgentLLM.ts +++ b/packages/components/nodes/agents/MRLKAgentLLM/MRLKAgentLLM.ts @@ -1,6 +1,6 @@ import { INode, INodeData, INodeParams } from '../../../src/Interface' -class MRLKAgentLLM implements INode { +class MRLKAgentLLM_Agents implements INode { label: string name: string description: string @@ -55,4 +55,4 @@ class MRLKAgentLLM implements INode { } } -module.exports = { nodeClass: MRLKAgentLLM } +module.exports = { nodeClass: MRLKAgentLLM_Agents } diff --git a/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts new file mode 100644 index 00000000..c23a4d92 --- /dev/null +++ b/packages/components/nodes/chains/ConversationalRetrievalQAChain/ConversationalRetrievalQAChain.ts @@ -0,0 +1,74 @@ +import { ICommonObject, IMessage, INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' + +class ConversationalRetrievalQAChain_Chains implements INode { + label: string + name: string + type: string + icon: string + category: string + baseClasses: string[] + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'Conversational Retrieval QA Chain' + this.name = 'conversationalRetrievalQAChain' + this.type = 'ConversationalRetrievalQAChain' + this.icon = 'chain.svg' + this.category = 'Chains' + this.description = 'Document QA - built on RetrievalQAChain to provide a chat history component' + this.inputs = [ + { + label: 'LLM', + name: 'llm', + type: 'BaseLanguageModel' + }, + { + label: 'Vector Store Retriever', + name: 'vectorStoreRetriever', + type: 'BaseRetriever' + } + ] + } + + async getBaseClasses(): Promise { + const { ConversationalRetrievalQAChain } = await import('langchain/chains') + return getBaseClasses(ConversationalRetrievalQAChain) + } + + async init(nodeData: INodeData): Promise { + const { ConversationalRetrievalQAChain } = await import('langchain/chains') + + const llm = nodeData.inputs?.llm + const vectorStoreRetriever = nodeData.inputs?.vectorStoreRetriever + + const chain = ConversationalRetrievalQAChain.fromLLM(llm, vectorStoreRetriever) + return chain + } + + async run(nodeData: INodeData, input: string, options: ICommonObject): Promise { + const chain = nodeData.instance + let chatHistory = '' + + if (options && options.chatHistory) { + const histories: IMessage[] = options.chatHistory + chatHistory = histories + .map((item) => { + return item.message + }) + .join('') + } + + const obj = { + question: input, + chat_history: chatHistory ? chatHistory : [] + } + + const res = await chain.call(obj) + + return res?.text + } +} + +module.exports = { nodeClass: ConversationalRetrievalQAChain_Chains } diff --git a/packages/components/nodes/chains/ConversationalRetrievalQAChain/chain.svg b/packages/components/nodes/chains/ConversationalRetrievalQAChain/chain.svg new file mode 100644 index 00000000..a5b32f90 --- /dev/null +++ b/packages/components/nodes/chains/ConversationalRetrievalQAChain/chain.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/chains/LLMChain/LLMChain.ts b/packages/components/nodes/chains/LLMChain/LLMChain.ts index 1dab8ea4..18376545 100644 --- a/packages/components/nodes/chains/LLMChain/LLMChain.ts +++ b/packages/components/nodes/chains/LLMChain/LLMChain.ts @@ -28,6 +28,17 @@ class LLMChain_Chains implements INode { label: 'Prompt', name: 'prompt', type: 'BasePromptTemplate' + }, + { + label: 'Format Prompt Values', + name: 'promptValues', + type: 'string', + rows: 5, + placeholder: `{ + "input_language": "English", + "output_language": "French" +}`, + optional: true } ] } @@ -48,13 +59,39 @@ class LLMChain_Chains implements INode { } async run(nodeData: INodeData, input: string): Promise { - const prompt = nodeData.instance.prompt.inputVariables // ["product"] - if (prompt.length > 1) throw new Error('Prompt can only contains 1 literal string {}. Multiples are found') - + const inputVariables = nodeData.instance.prompt.inputVariables // ["product"] const chain = nodeData.instance - const res = await chain.run(input) - return res + if (inputVariables.length === 1) { + const res = await chain.run(input) + return res + } else if (inputVariables.length > 1) { + const promptValuesStr = nodeData.inputs?.promptValues as string + if (!promptValuesStr) throw new Error('Please provide Prompt Values') + + const promptValues = JSON.parse(promptValuesStr.replace(/\s/g, '')) + + let seen = [] + + for (const variable of inputVariables) { + seen.push(variable) + if (promptValues[variable]) { + seen.pop() + } + } + + if (seen.length === 1) { + const options = { + ...promptValues, + [seen.pop()]: input + } + const res = await chain.call(options) + return res?.text + } else throw new Error('Please provide Prompt Values') + } else { + const res = await chain.run(input) + return res + } } } diff --git a/packages/components/nodes/chains/RetrievalQAChain/RetrievalQAChain.ts b/packages/components/nodes/chains/RetrievalQAChain/RetrievalQAChain.ts new file mode 100644 index 00000000..3bfce6fc --- /dev/null +++ b/packages/components/nodes/chains/RetrievalQAChain/RetrievalQAChain.ts @@ -0,0 +1,57 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' + +class RetrievalQAChain_Chains implements INode { + label: string + name: string + type: string + icon: string + category: string + baseClasses: string[] + description: string + inputs: INodeParams[] + + constructor() { + this.label = 'RetrievalQA Chain' + this.name = 'retrievalQAChain' + this.type = 'RetrievalQAChain' + this.icon = 'chain.svg' + this.category = 'Chains' + this.description = 'QA chain to answer a question based on the retrieved documents' + this.inputs = [ + { + label: 'LLM', + name: 'llm', + type: 'BaseLanguageModel' + }, + { + label: 'Vector Store Retriever', + name: 'vectorStoreRetriever', + type: 'BaseRetriever' + } + ] + } + + async getBaseClasses(): Promise { + return ['BaseChain'] + } + + async init(nodeData: INodeData): Promise { + const { RetrievalQAChain } = await import('langchain/chains') + const llm = nodeData.inputs?.llm + const vectorStoreRetriever = nodeData.inputs?.vectorStoreRetriever + + const chain = RetrievalQAChain.fromLLM(llm, vectorStoreRetriever) + return chain + } + + async run(nodeData: INodeData, input: string): Promise { + const chain = nodeData.instance + const obj = { + query: input + } + const res = await chain.call(obj) + return res?.text + } +} + +module.exports = { nodeClass: RetrievalQAChain_Chains } diff --git a/packages/components/nodes/chains/RetrievalQAChain/chain.svg b/packages/components/nodes/chains/RetrievalQAChain/chain.svg new file mode 100644 index 00000000..a5b32f90 --- /dev/null +++ b/packages/components/nodes/chains/RetrievalQAChain/chain.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts index e69de29b..9cb12592 100644 --- a/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts +++ b/packages/components/nodes/chatmodels/ChatOpenAI/ChatOpenAI.ts @@ -0,0 +1,75 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' + +class ChatOpenAI_ChatModels implements INode { + label: string + name: string + type: string + icon: string + category: string + description: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'ChatOpenAI' + this.name = 'chatOpenAI' + this.type = 'ChatOpenAI' + this.icon = 'openai.png' + this.category = 'Chat Models' + this.description = 'Wrapper around OpenAI large language models that use the Chat endpoint' + this.inputs = [ + { + label: 'OpenAI Api Key', + name: 'openAIApiKey', + type: 'password' + }, + { + label: 'Model Name', + name: 'modelName', + type: 'options', + options: [ + { + label: 'gpt-3.5-turbo', + name: 'gpt-3.5-turbo' + }, + { + label: 'gpt-3.5-turbo-0301', + name: 'gpt-3.5-turbo-0301' + } + ], + default: 'gpt-3.5-turbo', + optional: true + }, + { + label: 'Temperature', + name: 'temperature', + type: 'number', + default: 0.9, + optional: true + } + ] + } + + async getBaseClasses(): Promise { + const { ChatOpenAI } = await import('langchain/chat_models') + return getBaseClasses(ChatOpenAI) + } + + async init(nodeData: INodeData): Promise { + const { ChatOpenAI } = await import('langchain/chat_models') + + const temperature = nodeData.inputs?.temperature as string + const modelName = nodeData.inputs?.modelName as string + const openAIApiKey = nodeData.inputs?.openAIApiKey as string + + const model = new ChatOpenAI({ + temperature: parseInt(temperature, 10), + modelName, + openAIApiKey + }) + return model + } +} + +module.exports = { nodeClass: ChatOpenAI_ChatModels } diff --git a/packages/components/nodes/documentloaders/Github/Github.ts b/packages/components/nodes/documentloaders/Github/Github.ts new file mode 100644 index 00000000..ff4a5a7e --- /dev/null +++ b/packages/components/nodes/documentloaders/Github/Github.ts @@ -0,0 +1,81 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' + +class Github_DocumentLoaders implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Github' + this.name = 'github' + this.type = 'Github' + this.icon = 'github.png' + this.category = 'Document Loaders' + this.description = `Load data from a GitHub repository` + this.inputs = [ + { + label: 'Repo Link', + name: 'repoLink', + type: 'string', + placeholder: 'https://github.com/FlowiseAI/Flowise' + }, + { + label: 'Branch', + name: 'branch', + type: 'string', + default: 'main' + }, + { + label: 'Access Token', + name: 'accessToken', + type: 'password', + placeholder: '', + optional: true + }, + { + label: 'Text Splitter', + name: 'textSplitter', + type: 'TextSplitter', + optional: true + } + ] + } + + async getBaseClasses(): Promise { + return ['Document'] + } + + async init(nodeData: INodeData): Promise { + const { GithubRepoLoader } = await import('langchain/document_loaders') + + const repoLink = nodeData.inputs?.repoLink as string + const branch = nodeData.inputs?.branch as string + const accessToken = nodeData.inputs?.accessToken as string + const textSplitter = nodeData.inputs?.textSplitter + + const options = { + branch, + recursive: false, + unknown: 'warn' + } as any + + if (accessToken) options.accessToken = accessToken + + const loader = new GithubRepoLoader(repoLink, options) + + if (textSplitter) { + const docs = await loader.loadAndSplit(textSplitter) + return docs + } else { + const docs = await loader.load() + return docs + } + } +} + +module.exports = { nodeClass: Github_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/Github/github.png b/packages/components/nodes/documentloaders/Github/github.png new file mode 100644 index 0000000000000000000000000000000000000000..e440081876df135f6d27f5cf764233f85ac6194b GIT binary patch literal 16945 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 { + return ['Document'] + } + + async init(nodeData: INodeData): Promise { + const { PDFLoader } = await import('langchain/document_loaders') + + const textSplitter = nodeData.inputs?.textSplitter + const pdfFileBase64 = nodeData.inputs?.pdfFile as string + const usage = nodeData.inputs?.usage as string + + const splitDataURI = pdfFileBase64.split(',') + splitDataURI.pop() + const bf = Buffer.from(splitDataURI.pop() || '', 'base64') + const blob = new Blob([bf]) + + if (usage === 'perFile') { + const loader = new PDFLoader(blob, { splitPages: false }) + if (textSplitter) { + const docs = await loader.loadAndSplit(textSplitter) + return docs + } else { + const docs = await loader.load() + return docs + } + } else { + const loader = new PDFLoader(blob) + if (textSplitter) { + const docs = await loader.loadAndSplit(textSplitter) + return docs + } else { + const docs = await loader.load() + return docs + } + } + } +} + +module.exports = { nodeClass: Pdf_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/Pdf/pdf.svg b/packages/components/nodes/documentloaders/Pdf/pdf.svg new file mode 100644 index 00000000..20af94f8 --- /dev/null +++ b/packages/components/nodes/documentloaders/Pdf/pdf.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/documentloaders/Text/Text.ts b/packages/components/nodes/documentloaders/Text/Text.ts new file mode 100644 index 00000000..b174e230 --- /dev/null +++ b/packages/components/nodes/documentloaders/Text/Text.ts @@ -0,0 +1,61 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' + +class Text_DocumentLoaders implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Text File' + this.name = 'textFile' + this.type = 'Text' + this.icon = 'textFile.svg' + this.category = 'Document Loaders' + this.description = `Load data from text files` + this.inputs = [ + { + label: 'Txt File', + name: 'txtFile', + type: 'file', + fileType: '.txt' + }, + { + label: 'Text Splitter', + name: 'textSplitter', + type: 'TextSplitter', + optional: true + } + ] + } + + async getBaseClasses(): Promise { + return ['Document'] + } + + async init(nodeData: INodeData): Promise { + const { TextLoader } = await import('langchain/document_loaders') + const textSplitter = nodeData.inputs?.textSplitter + const txtFileBase64 = nodeData.inputs?.txtFile as string + const splitDataURI = txtFileBase64.split(',') + splitDataURI.pop() + const bf = Buffer.from(splitDataURI.pop() || '', 'base64') + + const blob = new Blob([bf]) + const loader = new TextLoader(blob) + + if (textSplitter) { + const docs = await loader.loadAndSplit(textSplitter) + return docs + } else { + const docs = await loader.load() + return docs + } + } +} + +module.exports = { nodeClass: Text_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/Text/textFile.svg b/packages/components/nodes/documentloaders/Text/textFile.svg new file mode 100644 index 00000000..200be563 --- /dev/null +++ b/packages/components/nodes/documentloaders/Text/textFile.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts b/packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts new file mode 100644 index 00000000..414259fe --- /dev/null +++ b/packages/components/nodes/embeddings/OpenAIEmbedding/OpenAIEmbedding.ts @@ -0,0 +1,44 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' + +class OpenAIEmbedding_Embeddings implements INode { + label: string + name: string + type: string + icon: string + category: string + description: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'OpenAI Embeddings' + this.name = 'openAIEmbeddings' + this.type = 'OpenAIEmbeddings' + this.icon = 'openai.png' + this.category = 'Embeddings' + this.description = 'OpenAI API to generate embeddings for a given text' + this.inputs = [ + { + label: 'OpenAI Api Key', + name: 'openAIApiKey', + type: 'password' + } + ] + } + + async getBaseClasses(): Promise { + const { OpenAIEmbeddings } = await import('langchain/embeddings') + return getBaseClasses(OpenAIEmbeddings) + } + + async init(nodeData: INodeData): Promise { + const { OpenAIEmbeddings } = await import('langchain/embeddings') + const openAIApiKey = nodeData.inputs?.openAIApiKey as string + + const model = new OpenAIEmbeddings({ openAIApiKey }) + return model + } +} + +module.exports = { nodeClass: OpenAIEmbedding_Embeddings } diff --git a/packages/components/nodes/embeddings/OpenAIEmbedding/openai.png b/packages/components/nodes/embeddings/OpenAIEmbedding/openai.png new file mode 100644 index 0000000000000000000000000000000000000000..de08a05b28979826c4cc669c4899789763a938a1 GIT binary patch literal 3991 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 literal 0 HcmV?d00001 diff --git a/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts new file mode 100644 index 00000000..5141781e --- /dev/null +++ b/packages/components/nodes/llms/HuggingFaceInference/HuggingFaceInference.ts @@ -0,0 +1,64 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' + +class HuggingFaceInference_LLMs implements INode { + label: string + name: string + type: string + icon: string + category: string + description: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'HuggingFace Inference' + this.name = 'huggingFaceInference_LLMs' + this.type = 'HuggingFaceInference' + this.icon = 'huggingface.png' + this.category = 'LLMs' + this.description = 'Wrapper around OpenAI large language models' + this.inputs = [ + { + label: 'Model', + name: 'model', + type: 'options', + options: [ + { + label: 'gpt2', + name: 'gpt2' + } + ], + default: 'gpt2', + optional: true + }, + { + label: 'Temperature', + name: 'temperature', + type: 'number', + default: 0.7, + optional: true + } + ] + } + + async getBaseClasses(): Promise { + const { HuggingFaceInference } = await import('langchain/llms') + return getBaseClasses(HuggingFaceInference) + } + + async init(nodeData: INodeData): Promise { + const { HuggingFaceInference } = await import('langchain/llms') + + const temperature = nodeData.inputs?.temperature as string + const model = nodeData.inputs?.model as string + + const huggingFace = new HuggingFaceInference({ + temperature: parseInt(temperature, 10), + model + }) + return huggingFace + } +} + +module.exports = { nodeClass: HuggingFaceInference_LLMs } diff --git a/packages/components/nodes/llms/HuggingFaceInference/huggingface.png b/packages/components/nodes/llms/HuggingFaceInference/huggingface.png new file mode 100644 index 0000000000000000000000000000000000000000..f8f202a46300c21e41bd782da959e43df5c73fd1 GIT binary patch literal 120391 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 { + const { BufferMemory } = await import('langchain/memory') + return getBaseClasses(BufferMemory) + } + + async init(nodeData: INodeData): Promise { + const { BufferMemory } = await import('langchain/memory') + const memoryKey = nodeData.inputs?.memoryKey as string + const inputKey = nodeData.inputs?.inputKey as string + return new BufferMemory({ + returnMessages: true, + memoryKey, + inputKey + }) + } +} + +module.exports = { nodeClass: BufferMemory_Memory } diff --git a/packages/components/nodes/memory/BufferMemory/memory.svg b/packages/components/nodes/memory/BufferMemory/memory.svg new file mode 100644 index 00000000..ca8e17da --- /dev/null +++ b/packages/components/nodes/memory/BufferMemory/memory.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts b/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts index e69de29b..c5084a55 100644 --- a/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts +++ b/packages/components/nodes/prompts/ChatPromptTemplate/ChatPromptTemplate.ts @@ -0,0 +1,57 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' + +class ChatPromptTemplate_Prompts implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Chat Prompt Template' + this.name = 'chatPromptTemplate' + this.type = 'ChatPromptTemplate' + this.icon = 'prompt.svg' + this.category = 'Prompts' + this.description = 'Schema to represent a chat prompt' + this.inputs = [ + { + label: 'System Message', + name: 'systemMessagePrompt', + type: 'string', + rows: 3, + placeholder: `You are a helpful assistant that translates {input_language} to {output_language}.` + }, + { + label: 'Human Message', + name: 'humanMessagePrompt', + type: 'string', + rows: 3, + placeholder: `{text}` + } + ] + } + + async getBaseClasses(): Promise { + const { ChatPromptTemplate } = await import('langchain/prompts') + return getBaseClasses(ChatPromptTemplate) + } + + async init(nodeData: INodeData): Promise { + const { ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate } = await import('langchain/prompts') + const systemMessagePrompt = nodeData.inputs?.systemMessagePrompt as string + const humanMessagePrompt = nodeData.inputs?.humanMessagePrompt as string + + const prompt = ChatPromptTemplate.fromPromptMessages([ + SystemMessagePromptTemplate.fromTemplate(systemMessagePrompt), + HumanMessagePromptTemplate.fromTemplate(humanMessagePrompt) + ]) + return prompt + } +} + +module.exports = { nodeClass: ChatPromptTemplate_Prompts } diff --git a/packages/components/nodes/prompts/ChatPromptTemplate/prompt.svg b/packages/components/nodes/prompts/ChatPromptTemplate/prompt.svg new file mode 100644 index 00000000..7e486118 --- /dev/null +++ b/packages/components/nodes/prompts/ChatPromptTemplate/prompt.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/prompts/FewShotPromptTemplate/FewShotPromptTemplate.ts b/packages/components/nodes/prompts/FewShotPromptTemplate/FewShotPromptTemplate.ts new file mode 100644 index 00000000..d2c3e1af --- /dev/null +++ b/packages/components/nodes/prompts/FewShotPromptTemplate/FewShotPromptTemplate.ts @@ -0,0 +1,112 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses, getInputVariables } from '../../../src/utils' + +class FewShotPromptTemplate_Prompts implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Few Shot Prompt Template' + this.name = 'fewShotPromptTemplate' + this.type = 'FewShotPromptTemplate' + this.icon = 'prompt.svg' + this.category = 'Prompts' + this.description = 'Prompt template you can build with examples' + this.inputs = [ + { + label: 'Examples', + name: 'examples', + type: 'string', + rows: 5, + placeholder: `[ + { "word": "happy", "antonym": "sad" }, + { "word": "tall", "antonym": "short" }, +]` + }, + { + label: 'Example Prompt', + name: 'examplePrompt', + type: 'BasePromptTemplate' + }, + { + label: 'Prefix', + name: 'prefix', + type: 'string', + rows: 3, + placeholder: `Give the antonym of every input` + }, + { + label: 'Suffix', + name: 'suffix', + type: 'string', + rows: 3, + placeholder: `Word: {input}\nAntonym:` + }, + { + label: 'Example Seperator', + name: 'exampleSeparator', + type: 'string', + placeholder: `\n\n` + }, + { + label: 'Template Format', + name: 'templateFormat', + type: 'options', + options: [ + { + label: 'f-string', + name: 'f-string' + }, + { + label: 'jinja-2', + name: 'jinja-2' + } + ], + default: `f-string` + } + ] + } + + async getBaseClasses(): Promise { + const { FewShotPromptTemplate } = await import('langchain/prompts') + return getBaseClasses(FewShotPromptTemplate) + } + + async init(nodeData: INodeData): Promise { + const { FewShotPromptTemplate } = await import('langchain/prompts') + + const examplesStr = nodeData.inputs?.examples as string + + const prefix = nodeData.inputs?.prefix as string + const suffix = nodeData.inputs?.suffix as string + const exampleSeparator = nodeData.inputs?.exampleSeparator as string + const templateFormat = nodeData.inputs?.templateFormat + const examplePrompt = nodeData.inputs?.examplePrompt + + const inputVariables = getInputVariables(suffix) + const examples = JSON.parse(examplesStr.replace(/\s/g, '')) + + try { + const prompt = new FewShotPromptTemplate({ + examples, + examplePrompt, + prefix, + suffix, + inputVariables, + exampleSeparator, + templateFormat + }) + return prompt + } catch (e) { + throw new Error(e) + } + } +} + +module.exports = { nodeClass: FewShotPromptTemplate_Prompts } diff --git a/packages/components/nodes/prompts/FewShotPromptTemplate/prompt.svg b/packages/components/nodes/prompts/FewShotPromptTemplate/prompt.svg new file mode 100644 index 00000000..7e486118 --- /dev/null +++ b/packages/components/nodes/prompts/FewShotPromptTemplate/prompt.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/prompts/HumanMessagePromptTemplate/HumanMessagePromptTemplate.ts b/packages/components/nodes/prompts/HumanMessagePromptTemplate/HumanMessagePromptTemplate.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/components/nodes/prompts/PromptTemplate/PromptTemplate.ts b/packages/components/nodes/prompts/PromptTemplate/PromptTemplate.ts index 11fd26f1..672362a5 100644 --- a/packages/components/nodes/prompts/PromptTemplate/PromptTemplate.ts +++ b/packages/components/nodes/prompts/PromptTemplate/PromptTemplate.ts @@ -17,15 +17,14 @@ class PromptTemplate_Prompts implements INode { this.type = 'PromptTemplate' this.icon = 'prompt.svg' this.category = 'Prompts' - this.description = 'Schema to represent a basic prompt for an LLM. Template can only contains 1 literal string {}' + this.description = 'Schema to represent a basic prompt for an LLM' this.inputs = [ { label: 'Template', name: 'template', type: 'string', rows: 5, - default: 'What is a good name for a company that makes {product}?', - placeholder: 'What is a good name for a company that makes {product}?' + placeholder: `What is a good name for a company that makes {product}?` } ] } @@ -42,10 +41,11 @@ class PromptTemplate_Prompts implements INode { const inputVariables = getInputVariables(template) try { - const prompt = new PromptTemplate({ + const options = { template, - inputVariables: inputVariables - }) + inputVariables + } + const prompt = new PromptTemplate(options) return prompt } catch (e) { throw new Error(e) diff --git a/packages/components/nodes/prompts/SysmtemMessagePromptTemplate/SysmtemMessagePromptTemplate.ts b/packages/components/nodes/prompts/SysmtemMessagePromptTemplate/SysmtemMessagePromptTemplate.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts b/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts new file mode 100644 index 00000000..d19ba342 --- /dev/null +++ b/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/RecursiveCharacterTextSplitter.ts @@ -0,0 +1,59 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { getBaseClasses } from '../../../src/utils' + +class RecursiveCharacterTextSplitter_TextSplitters implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Recursive Character Text Splitter' + this.name = 'recursiveCharacterTextSplitter' + this.type = 'RecursiveCharacterTextSplitter' + this.icon = 'textsplitter.svg' + this.category = 'Text Splitters' + this.description = `Split documents recursively by different characters - starting with "\n\n", then "\n", then " "` + this.inputs = [ + { + label: 'Chunk Size', + name: 'chunkSize', + type: 'number', + default: 1000, + optional: true + }, + { + label: 'Chunk Overlap', + name: 'chunkOverlap', + type: 'number', + optional: true + } + ] + } + + async getBaseClasses(): Promise { + const { RecursiveCharacterTextSplitter } = await import('langchain/text_splitter') + return getBaseClasses(RecursiveCharacterTextSplitter) + } + + async init(nodeData: INodeData): Promise { + const { RecursiveCharacterTextSplitter } = await import('langchain/text_splitter') + const chunkSize = nodeData.inputs?.chunkSize as string + const chunkOverlap = nodeData.inputs?.chunkOverlap as string + + const obj = {} as any + + if (chunkSize) obj.chunkSize = parseInt(chunkSize, 10) + if (chunkOverlap) obj.chunkOverlap = parseInt(chunkOverlap, 10) + + const splitter = new RecursiveCharacterTextSplitter(obj) + + return splitter + } +} + +module.exports = { nodeClass: RecursiveCharacterTextSplitter_TextSplitters } diff --git a/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/textsplitter.svg b/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/textsplitter.svg new file mode 100644 index 00000000..73145e2d --- /dev/null +++ b/packages/components/nodes/textsplitters/RecursiveCharacterTextSplitter/textsplitter.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/components/nodes/vectorstores/Chroma_Existing/Chroma_Existing.ts b/packages/components/nodes/vectorstores/Chroma_Existing/Chroma_Existing.ts new file mode 100644 index 00000000..c8fd81af --- /dev/null +++ b/packages/components/nodes/vectorstores/Chroma_Existing/Chroma_Existing.ts @@ -0,0 +1,52 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' + +class Chroma_Existing_VectorStores implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Chroma Load Existing Index' + this.name = 'chromaExistingIndex' + this.type = 'Chroma' + this.icon = 'chroma.svg' + this.category = 'Vector Stores' + this.description = 'Load existing index from Chroma (i.e: Document has been upserted)' + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Collection Name', + name: 'collectionName', + type: 'string' + } + ] + } + + async getBaseClasses(): Promise { + return ['BaseRetriever'] + } + + async init(nodeData: INodeData): Promise { + const { Chroma } = await import('langchain/vectorstores') + + const collectionName = nodeData.inputs?.collectionName as string + const embeddings = nodeData.inputs?.embeddings + + const vectorStore = await Chroma.fromExistingCollection(embeddings, { + collectionName + }) + const retriever = vectorStore.asRetriever() + return retriever + } +} + +module.exports = { nodeClass: Chroma_Existing_VectorStores } diff --git a/packages/components/nodes/vectorstores/Chroma_Existing/chroma.svg b/packages/components/nodes/vectorstores/Chroma_Existing/chroma.svg new file mode 100644 index 00000000..64090685 --- /dev/null +++ b/packages/components/nodes/vectorstores/Chroma_Existing/chroma.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/components/nodes/vectorstores/Chroma_Upsert/Chroma_Upsert.ts b/packages/components/nodes/vectorstores/Chroma_Upsert/Chroma_Upsert.ts new file mode 100644 index 00000000..8b039bd2 --- /dev/null +++ b/packages/components/nodes/vectorstores/Chroma_Upsert/Chroma_Upsert.ts @@ -0,0 +1,65 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' + +class ChromaUpsert_VectorStores implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Chroma Upsert Document' + this.name = 'chromaUpsert' + this.type = 'Chroma' + this.icon = 'chroma.svg' + this.category = 'Vector Stores' + this.description = 'Upsert documents to Chroma' + this.inputs = [ + { + label: 'Document', + name: 'document', + type: 'Document' + }, + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Collection Name', + name: 'collectionName', + type: 'string' + } + ] + } + + async getBaseClasses(): Promise { + return ['BaseRetriever'] + } + + async init(nodeData: INodeData): Promise { + const { Chroma } = await import('langchain/vectorstores') + const { Document } = await import('langchain/document') + + const collectionName = nodeData.inputs?.collectionName as string + const docs = nodeData.inputs?.document + const embeddings = nodeData.inputs?.embeddings + + const finalDocs = [] + for (let i = 0; i < docs.length; i += 1) { + finalDocs.push(new Document(docs[i])) + } + + const result = await Chroma.fromDocuments(finalDocs, embeddings, { + collectionName + }) + + const retriever = result.asRetriever() + return retriever + } +} + +module.exports = { nodeClass: ChromaUpsert_VectorStores } diff --git a/packages/components/nodes/vectorstores/Chroma_Upsert/chroma.svg b/packages/components/nodes/vectorstores/Chroma_Upsert/chroma.svg new file mode 100644 index 00000000..64090685 --- /dev/null +++ b/packages/components/nodes/vectorstores/Chroma_Upsert/chroma.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/packages/components/nodes/vectorstores/Pinecone_Existing/Pinecone_Existing.ts b/packages/components/nodes/vectorstores/Pinecone_Existing/Pinecone_Existing.ts new file mode 100644 index 00000000..2d4f459d --- /dev/null +++ b/packages/components/nodes/vectorstores/Pinecone_Existing/Pinecone_Existing.ts @@ -0,0 +1,73 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { PineconeClient } from '@pinecone-database/pinecone' + +class Pinecone_Existing_VectorStores implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Pinecone Load Existing Index' + this.name = 'pineconeExistingIndex' + this.type = 'Pinecone' + this.icon = 'pinecone.png' + this.category = 'Vector Stores' + this.description = 'Load existing index from Pinecone (i.e: Document has been upserted)' + this.inputs = [ + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Pinecone Api Key', + name: 'pineconeApiKey', + type: 'password' + }, + { + label: 'Pinecone Environment', + name: 'pineconeEnv', + type: 'string' + }, + { + label: 'Pinecone Index', + name: 'pineconeIndex', + type: 'string' + } + ] + } + + async getBaseClasses(): Promise { + return ['BaseRetriever'] + } + + async init(nodeData: INodeData): Promise { + const { PineconeStore } = await import('langchain/vectorstores') + + const pineconeApiKey = nodeData.inputs?.pineconeApiKey as string + const pineconeEnv = nodeData.inputs?.pineconeEnv as string + const index = nodeData.inputs?.pineconeIndex as string + const embeddings = nodeData.inputs?.embeddings + + const client = new PineconeClient() + await client.init({ + apiKey: pineconeApiKey, + environment: pineconeEnv + }) + + const pineconeIndex = client.Index(index) + + const vectorStore = await PineconeStore.fromExistingIndex(embeddings, { + pineconeIndex + }) + const retriever = vectorStore.asRetriever() + return retriever + } +} + +module.exports = { nodeClass: Pinecone_Existing_VectorStores } diff --git a/packages/components/nodes/vectorstores/Pinecone_Existing/pinecone.png b/packages/components/nodes/vectorstores/Pinecone_Existing/pinecone.png new file mode 100644 index 0000000000000000000000000000000000000000..1ae189fdcc3b672a629d34c271a3d963bfaa1d70 GIT binary patch literal 2423 zcmeH{XE@vI8^?c9t0{`0#EM!)X~b-5rIJI8P!fs`BUX)2)M#r{J(La(6%9qJdW_57 zdfHO6(ilZ^)E=dR4iYg=`ttwc|Ngu<*L6S7_j>N<`n;>070xJ z+JU2R&N1LW!ntoxo)zQ>w=c>T1pqZ!$M!sUIB%GjrGqU1#Hav3d@=y+a#Hat01&|e zSKR>snFjzTLJC?h7y$rRk-ZHb^NW#{`!D`;;9uy#;o;$#f^7p%kA4n!z&Qed#8thc zzRL$pTb}dXt8kE7(e|K>U~J{Fgps}d%p;QP-*crK%4yz0!m_+UjYuy3nGmf7V-rek z-MbH?ALsPN%+o;DU z6*jx~&<%H>X*TCd^F6rHKYd^izWOWXh(v*vU;OSoP^=ODIsGE*$FN`1v(9_%iCw#o z$kT4oD^8}_N*0b(`PrqdMN!w29Xh%xRpu`l>c5?S{Jf?=5L@t8DqzUSU|w@9CL=P~ zir}Simw4?{93nZ}fwsu06y#}bfu5%L5C0l(zHqE9hHsghPXMOpy}`@->z{NThX+xM zBl9`aKZQl3@RmI}PAqdgL9DanuXYekl^-+I8_xww>ICsj=9-CRd-PobOM&`$5He0j zg}HfiZJ-E{`!iFq3Pk4o%e$`D~4HLroyO^4C84Rh9VKYDj{lap+tKw^KbnOg`93H&0LpS5jhx5^BRsA#A-I!RA*=)i|kJgS&BqA#<>61%ULEfL{ zcd`uo8<52IW^TxKYN!fqbA`++;r2zlUg}`!8U;F^j1JZvc`mhOEk@~oO@nw1Ce0Rq#M9@<~zaLOF|EPbVl`JLo zn$X}k^Qf!QHM?GdAR{@f#E$SOo(a0d*C>{zCJ^-OrDJxafupq98;cEOx%7u`n8e;GC6W7yH>th3gbKY^*A{1H^~29z=HiuctkiD3>6}iFCrX6RXsgu&#M{3tB zyg!YmFl4uOC18^YT6Ql1M(?shb%!6~R#~oCM{j#~Bru;rT+?%Bnpl4l+D*7O=h z^6bO~OE;P;J*9G(=}`aqt=5+ossx28`oqnj)ljQ5RFqyLZQ)ywm)fa*$~W#2O4|e6 zMM?T8U4C&4uu2QC+%V=hOB$du6^x=bMAy_sq*r9L%MA7s(-HO2{2|VTW1#$C>6yl( z0=73)8lu{s?$gKY?bX!xCI+FIECQ4s(ZDY4S^!;?yCAeHm#!o*Lr)5Y)-;Rh22)f& zJJwo}iPiFwLT+B_=jiS=4`-$hrJ*sp`v>SNVDXHu#m7G6HwBT(mJ1tM+ns8GMuOQf z{Xm=p`;$fOTumS0Y5^?MNOVcndASyXe>z6b&=G+c4!Pye0|g7NUXCxU1}o_{X4{h6 z^U1uUI#=Emm3~W_kY8OBFuiUAEtWEla*MyYXXD%zx>{XRHfneKPD*+kmQa3HTm%zW zmpl8dz!ay)YM+P)YQhtf!>*0Yz%;h45Y>5;MXRL}S?jkUNL^F2!+2NbK~mv9NG+v5 z^@iRHdGPlm%(yRW!pbT%qaR8nUH`u)ADxC#y6xtz`+E00=ljM-#5A2{*uNBak`>q@Ioj9FBy;4bS#Y{SOdCBKrG8 V|9=2W4DsLq02YHoSDklH{0AMUaoGR> literal 0 HcmV?d00001 diff --git a/packages/components/nodes/vectorstores/Pinecone_Upsert/Pinecone_Upsert.ts b/packages/components/nodes/vectorstores/Pinecone_Upsert/Pinecone_Upsert.ts new file mode 100644 index 00000000..14921ac2 --- /dev/null +++ b/packages/components/nodes/vectorstores/Pinecone_Upsert/Pinecone_Upsert.ts @@ -0,0 +1,86 @@ +import { INode, INodeData, INodeParams } from '../../../src/Interface' +import { PineconeClient } from '@pinecone-database/pinecone' + +class PineconeUpsert_VectorStores implements INode { + label: string + name: string + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + + constructor() { + this.label = 'Pinecone Upsert Document' + this.name = 'pineconeUpsert' + this.type = 'Pinecone' + this.icon = 'pinecone.png' + this.category = 'Vector Stores' + this.description = 'Upsert documents to Pinecone' + this.inputs = [ + { + label: 'Document', + name: 'document', + type: 'Document' + }, + { + label: 'Embeddings', + name: 'embeddings', + type: 'Embeddings' + }, + { + label: 'Pinecone Api Key', + name: 'pineconeApiKey', + type: 'password' + }, + { + label: 'Pinecone Environment', + name: 'pineconeEnv', + type: 'string' + }, + { + label: 'Pinecone Index', + name: 'pineconeIndex', + type: 'string' + } + ] + } + + async getBaseClasses(): Promise { + return ['BaseRetriever'] + } + + async init(nodeData: INodeData): Promise { + const { PineconeStore } = await import('langchain/vectorstores') + const { Document } = await import('langchain/document') + + const pineconeApiKey = nodeData.inputs?.pineconeApiKey as string + const pineconeEnv = nodeData.inputs?.pineconeEnv as string + const index = nodeData.inputs?.pineconeIndex as string + const docs = nodeData.inputs?.document + const embeddings = nodeData.inputs?.embeddings + + const client = new PineconeClient() + await client.init({ + apiKey: pineconeApiKey, + environment: pineconeEnv + }) + + const pineconeIndex = client.Index(index) + + const finalDocs = [] + for (let i = 0; i < docs.length; i += 1) { + finalDocs.push(new Document(docs[i])) + } + + const result = await PineconeStore.fromDocuments(finalDocs, embeddings, { + pineconeIndex + }) + + const retriever = result.asRetriever() + return retriever + } +} + +module.exports = { nodeClass: PineconeUpsert_VectorStores } diff --git a/packages/components/nodes/vectorstores/Pinecone_Upsert/pinecone.png b/packages/components/nodes/vectorstores/Pinecone_Upsert/pinecone.png new file mode 100644 index 0000000000000000000000000000000000000000..1ae189fdcc3b672a629d34c271a3d963bfaa1d70 GIT binary patch literal 2423 zcmeH{XE@vI8^?c9t0{`0#EM!)X~b-5rIJI8P!fs`BUX)2)M#r{J(La(6%9qJdW_57 zdfHO6(ilZ^)E=dR4iYg=`ttwc|Ngu<*L6S7_j>N<`n;>070xJ z+JU2R&N1LW!ntoxo)zQ>w=c>T1pqZ!$M!sUIB%GjrGqU1#Hav3d@=y+a#Hat01&|e zSKR>snFjzTLJC?h7y$rRk-ZHb^NW#{`!D`;;9uy#;o;$#f^7p%kA4n!z&Qed#8thc zzRL$pTb}dXt8kE7(e|K>U~J{Fgps}d%p;QP-*crK%4yz0!m_+UjYuy3nGmf7V-rek z-MbH?ALsPN%+o;DU z6*jx~&<%H>X*TCd^F6rHKYd^izWOWXh(v*vU;OSoP^=ODIsGE*$FN`1v(9_%iCw#o z$kT4oD^8}_N*0b(`PrqdMN!w29Xh%xRpu`l>c5?S{Jf?=5L@t8DqzUSU|w@9CL=P~ zir}Simw4?{93nZ}fwsu06y#}bfu5%L5C0l(zHqE9hHsghPXMOpy}`@->z{NThX+xM zBl9`aKZQl3@RmI}PAqdgL9DanuXYekl^-+I8_xww>ICsj=9-CRd-PobOM&`$5He0j zg}HfiZJ-E{`!iFq3Pk4o%e$`D~4HLroyO^4C84Rh9VKYDj{lap+tKw^KbnOg`93H&0LpS5jhx5^BRsA#A-I!RA*=)i|kJgS&BqA#<>61%ULEfL{ zcd`uo8<52IW^TxKYN!fqbA`++;r2zlUg}`!8U;F^j1JZvc`mhOEk@~oO@nw1Ce0Rq#M9@<~zaLOF|EPbVl`JLo zn$X}k^Qf!QHM?GdAR{@f#E$SOo(a0d*C>{zCJ^-OrDJxafupq98;cEOx%7u`n8e;GC6W7yH>th3gbKY^*A{1H^~29z=HiuctkiD3>6}iFCrX6RXsgu&#M{3tB zyg!YmFl4uOC18^YT6Ql1M(?shb%!6~R#~oCM{j#~Bru;rT+?%Bnpl4l+D*7O=h z^6bO~OE;P;J*9G(=}`aqt=5+ossx28`oqnj)ljQ5RFqyLZQ)ywm)fa*$~W#2O4|e6 zMM?T8U4C&4uu2QC+%V=hOB$du6^x=bMAy_sq*r9L%MA7s(-HO2{2|VTW1#$C>6yl( z0=73)8lu{s?$gKY?bX!xCI+FIECQ4s(ZDY4S^!;?yCAeHm#!o*Lr)5Y)-;Rh22)f& zJJwo}iPiFwLT+B_=jiS=4`-$hrJ*sp`v>SNVDXHu#m7G6HwBT(mJ1tM+ns8GMuOQf z{Xm=p`;$fOTumS0Y5^?MNOVcndASyXe>z6b&=G+c4!Pye0|g7NUXCxU1}o_{X4{h6 z^U1uUI#=Emm3~W_kY8OBFuiUAEtWEla*MyYXXD%zx>{XRHfneKPD*+kmQa3HTm%zW zmpl8dz!ay)YM+P)YQhtf!>*0Yz%;h45Y>5;MXRL}S?jkUNL^F2!+2NbK~mv9NG+v5 z^@iRHdGPlm%(yRW!pbT%qaR8nUH`u)ADxC#y6xtz`+E00=ljM-#5A2{*uNBak`>q@Ioj9FBy;4bS#Y{SOdCBKrG8 V|9=2W4DsLq02YHoSDklH{0AMUaoGR> literal 0 HcmV?d00001 diff --git a/packages/components/package.json b/packages/components/package.json index d5e3f653..0a211553 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -16,13 +16,18 @@ }, "license": "SEE LICENSE IN LICENSE.md", "dependencies": { + "@dqbd/tiktoken": "^1.0.4", + "@huggingface/inference": "^1.6.3", + "@pinecone-database/pinecone": "^0.0.12", "axios": "^0.27.2", + "chromadb": "^1.3.1", "dotenv": "^16.0.0", "express": "^4.17.3", "form-data": "^4.0.0", "langchain": "^0.0.44", "moment": "^2.29.3", "node-fetch": "2", + "pdfjs-dist": "^3.5.141", "ws": "^8.9.0" }, "devDependencies": { diff --git a/packages/components/src/Interface.ts b/packages/components/src/Interface.ts index 6d1d8ea0..7e4159ed 100644 --- a/packages/components/src/Interface.ts +++ b/packages/components/src/Interface.ts @@ -17,6 +17,8 @@ export type NodeParamsType = export type CommonType = string | number | boolean | undefined | null +export type MessageType = 'apiMessage' | 'userMessage' + /** * Others */ @@ -49,6 +51,7 @@ export interface INodeParams { rows?: number list?: boolean placeholder?: string + fileType?: string } export interface INodeExecutionData { @@ -74,10 +77,15 @@ export interface INode extends INodeProperties { inputs?: INodeParams[] getBaseClasses?(): Promise getInstance?(nodeData: INodeData): Promise - run?(nodeData: INodeData, input: string): Promise + run?(nodeData: INodeData, input: string, options?: ICommonObject): Promise } export interface INodeData extends INodeProperties { inputs?: ICommonObject instance?: any } + +export interface IMessage { + message: string + type: MessageType +} diff --git a/packages/components/src/utils.ts b/packages/components/src/utils.ts index 9e462572..7a2a4d25 100644 --- a/packages/components/src/utils.ts +++ b/packages/components/src/utils.ts @@ -4,6 +4,13 @@ import * as path from 'path' export const numberOrExpressionRegex = '^(\\d+\\.?\\d*|{{.*}})$' //return true if string consists only numbers OR expression {{}} export const notEmptyRegex = '(.|\\s)*\\S(.|\\s)*' //return true if string is not empty or blank +/** + * Get base classes of components + * + * @export + * @param {any} targetClass + * @returns {string[]} + */ export const getBaseClasses = (targetClass: any) => { const baseClasses: string[] = [] diff --git a/packages/server/src/ChatflowPool.ts b/packages/server/src/ChatflowPool.ts new file mode 100644 index 00000000..cc738e03 --- /dev/null +++ b/packages/server/src/ChatflowPool.ts @@ -0,0 +1,43 @@ +import { INodeData } from 'flowise-components' +import { IActiveChatflows } from './Interface' + +/** + * This pool is to keep track of active test triggers (event listeners), + * so we can clear the event listeners whenever user refresh or exit page + */ +export class ChatflowPool { + activeChatflows: IActiveChatflows = {} + + /** + * Add to the pool + * @param {string} chatflowid + * @param {INodeData} endingNodeData + */ + add(chatflowid: string, endingNodeData: INodeData) { + this.activeChatflows[chatflowid] = { + endingNodeData, + inSync: true + } + } + + /** + * Update to the pool + * @param {string} chatflowid + * @param {boolean} inSync + */ + updateInSync(chatflowid: string, inSync: boolean) { + if (Object.prototype.hasOwnProperty.call(this.activeChatflows, chatflowid)) { + this.activeChatflows[chatflowid].inSync = inSync + } + } + + /** + * Remove from the pool + * @param {string} chatflowid + */ + async remove(chatflowid: string) { + if (Object.prototype.hasOwnProperty.call(this.activeChatflows, chatflowid)) { + delete this.activeChatflows[chatflowid] + } + } +} diff --git a/packages/server/src/Interface.ts b/packages/server/src/Interface.ts index 3419b781..08906d44 100644 --- a/packages/server/src/Interface.ts +++ b/packages/server/src/Interface.ts @@ -22,7 +22,7 @@ export interface IChatMessage { createdDate: Date } -export interface IComponentNodesPool { +export interface IComponentNodes { [key: string]: INode } @@ -95,7 +95,19 @@ export interface INodeQueue { depth: number } +export interface IMessage { + message: string + type: MessageType +} + export interface IncomingInput { question: string - history: string[] + history: IMessage[] +} + +export interface IActiveChatflows { + [key: string]: { + endingNodeData: INodeData + inSync: boolean + } } diff --git a/packages/server/src/NodesPool.ts b/packages/server/src/NodesPool.ts index 8b630458..1485ffe5 100644 --- a/packages/server/src/NodesPool.ts +++ b/packages/server/src/NodesPool.ts @@ -1,4 +1,4 @@ -import { IComponentNodesPool } from './Interface' +import { IComponentNodes } from './Interface' import path from 'path' import { Dirent } from 'fs' @@ -6,7 +6,7 @@ import { getNodeModulesPackagePath } from './utils' import { promises } from 'fs' export class NodesPool { - componentNodes: IComponentNodesPool = {} + componentNodes: IComponentNodes = {} /** * Initialize to get all nodes diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 0794d701..ec953d3b 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -3,17 +3,20 @@ import path from 'path' import cors from 'cors' import http from 'http' -import { IChatFlow, IComponentNodesPool, IncomingInput, IReactFlowNode, IReactFlowObject } from './Interface' +import { IChatFlow, IncomingInput, IReactFlowNode, IReactFlowObject } from './Interface' import { getNodeModulesPackagePath, getStartingNode, buildLangchain, getEndingNode, constructGraphs } from './utils' import { cloneDeep } from 'lodash' import { getDataSource } from './DataSource' import { NodesPool } from './NodesPool' import { ChatFlow } from './entity/ChatFlow' import { ChatMessage } from './entity/ChatMessage' +import { ChatflowPool } from './ChatflowPool' +import { INodeData } from 'flowise-components' export class App { app: express.Application - componentNodes: IComponentNodesPool = {} + nodesPool: NodesPool + chatflowPool: ChatflowPool AppDataSource = getDataSource() constructor() { @@ -26,10 +29,11 @@ export class App { .then(async () => { console.info('📦[server]: Data Source has been initialized!') - // Initialize node instances - const nodesPool = new NodesPool() - await nodesPool.initialize() - this.componentNodes = nodesPool.componentNodes + // Initialize pools + this.nodesPool = new NodesPool() + await this.nodesPool.initialize() + + this.chatflowPool = new ChatflowPool() }) .catch((err) => { console.error('❌[server]: Error during Data Source initialization:', err) @@ -53,8 +57,8 @@ export class App { // Get all component nodes this.app.get('/api/v1/nodes', (req: Request, res: Response) => { const returnData = [] - for (const nodeName in this.componentNodes) { - const clonedNode = cloneDeep(this.componentNodes[nodeName]) + for (const nodeName in this.nodesPool.componentNodes) { + const clonedNode = cloneDeep(this.nodesPool.componentNodes[nodeName]) returnData.push(clonedNode) } return res.json(returnData) @@ -62,8 +66,8 @@ export class App { // Get specific component node via name this.app.get('/api/v1/nodes/:name', (req: Request, res: Response) => { - if (Object.prototype.hasOwnProperty.call(this.componentNodes, req.params.name)) { - return res.json(this.componentNodes[req.params.name]) + if (Object.prototype.hasOwnProperty.call(this.nodesPool.componentNodes, req.params.name)) { + return res.json(this.nodesPool.componentNodes[req.params.name]) } else { throw new Error(`Node ${req.params.name} not found`) } @@ -71,8 +75,8 @@ export class App { // Returns specific component node icon via name this.app.get('/api/v1/node-icon/:name', (req: Request, res: Response) => { - if (Object.prototype.hasOwnProperty.call(this.componentNodes, req.params.name)) { - const nodeInstance = this.componentNodes[req.params.name] + if (Object.prototype.hasOwnProperty.call(this.nodesPool.componentNodes, req.params.name)) { + const nodeInstance = this.nodesPool.componentNodes[req.params.name] if (nodeInstance.icon === undefined) { throw new Error(`Node ${req.params.name} icon not found`) } @@ -137,6 +141,9 @@ export class App { this.AppDataSource.getRepository(ChatFlow).merge(chatflow, updateChatFlow) const result = await this.AppDataSource.getRepository(ChatFlow).save(chatflow) + // Update chatflowpool inSync to false, to build Langchain again because data has been changed + this.chatflowPool.updateInSync(chatflow.id, false) + return res.json(result) }) @@ -183,30 +190,45 @@ export class App { // Send input message and get prediction result this.app.post('/api/v1/prediction/:id', async (req: Request, res: Response) => { try { + const chatflowid = req.params.id const incomingInput: IncomingInput = req.body - const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({ - id: req.params.id - }) - if (!chatflow) return res.status(404).send(`Chatflow ${req.params.id} not found`) + let nodeToExecuteData: INodeData - const flowData = chatflow.flowData - const parsedFlowData: IReactFlowObject = JSON.parse(flowData) - const { graph, nodeDependencies } = constructGraphs(parsedFlowData.nodes, parsedFlowData.edges) + if ( + Object.prototype.hasOwnProperty.call(this.chatflowPool.activeChatflows, chatflowid) && + this.chatflowPool.activeChatflows[chatflowid].inSync + ) { + nodeToExecuteData = this.chatflowPool.activeChatflows[chatflowid].endingNodeData + } else { + const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({ + id: chatflowid + }) + if (!chatflow) return res.status(404).send(`Chatflow ${chatflowid} not found`) - const startingNodeIds = getStartingNode(nodeDependencies) - const endingNodeId = getEndingNode(nodeDependencies, graph) - if (!endingNodeId) return res.status(500).send(`Ending node must be either Chain or Agent`) + const flowData = chatflow.flowData + const parsedFlowData: IReactFlowObject = JSON.parse(flowData) + const { graph, nodeDependencies } = constructGraphs(parsedFlowData.nodes, parsedFlowData.edges) - const reactFlowNodes = await buildLangchain(startingNodeIds, parsedFlowData.nodes, graph, this.componentNodes) - const nodeToExecute = reactFlowNodes.find((node: IReactFlowNode) => node.id === endingNodeId) - if (!nodeToExecute) return res.status(404).send(`Node ${endingNodeId} not found`) + const startingNodeIds = getStartingNode(nodeDependencies) + const endingNodeId = getEndingNode(nodeDependencies, graph) + if (!endingNodeId) return res.status(500).send(`Ending node must be either Chain or Agent`) - const nodeInstanceFilePath = this.componentNodes[nodeToExecute.data.name].filePath as string + const reactFlowNodes = await buildLangchain(startingNodeIds, parsedFlowData.nodes, graph, this.nodesPool.componentNodes) + + const nodeToExecute = reactFlowNodes.find((node: IReactFlowNode) => node.id === endingNodeId) + if (!nodeToExecute) return res.status(404).send(`Node ${endingNodeId} not found`) + + nodeToExecuteData = nodeToExecute.data + + this.chatflowPool.add(chatflowid, nodeToExecuteData) + } + + const nodeInstanceFilePath = this.nodesPool.componentNodes[nodeToExecuteData.name].filePath as string const nodeModule = await import(nodeInstanceFilePath) const nodeInstance = new nodeModule.nodeClass() - const result = await nodeInstance.run(nodeToExecute.data, incomingInput.question) + const result = await nodeInstance.run(nodeToExecuteData, incomingInput.question, { chatHistory: incomingInput.history }) return res.json(result) } catch (e: any) { diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 316218b6..bc50aff2 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -1,7 +1,7 @@ import path from 'path' import fs from 'fs' import { - IComponentNodesPool, + IComponentNodes, IExploredNode, INodeDependencies, INodeDirectedGraph, @@ -98,8 +98,13 @@ export const getStartingNode = (nodeDependencies: INodeDependencies) => { return startingNodeIds } +/** + * Get ending node and check if flow is valid + * @param {INodeDependencies} nodeDependencies + * @param {INodeDirectedGraph} graph + */ export const getEndingNode = (nodeDependencies: INodeDependencies, graph: INodeDirectedGraph) => { - // Find starting node + // Find ending node let endingNodeId = '' Object.keys(graph).forEach((nodeId) => { if (!graph[nodeId].length && nodeDependencies[nodeId] > 0) { @@ -113,17 +118,14 @@ export const getEndingNode = (nodeDependencies: INodeDependencies, graph: INodeD * Build langchain from start to end * @param {string} startingNodeId * @param {IReactFlowNode[]} reactFlowNodes - * @param {IReactFlowEdge[]} reactFlowEdges * @param {INodeDirectedGraph} graph - * @param {IComponentNodesPool} componentNodes - * @param {string} clientId - * @param {any} io + * @param {IComponentNodes} componentNodes */ export const buildLangchain = async ( startingNodeIds: string[], reactFlowNodes: IReactFlowNode[], graph: INodeDirectedGraph, - componentNodes: IComponentNodesPool + componentNodes: IComponentNodes ) => { const flowNodes = cloneDeep(reactFlowNodes) @@ -190,8 +192,6 @@ export const buildLangchain = async ( * Get variable value from outputResponses.output * @param {string} paramValue * @param {IReactFlowNode[]} reactFlowNodes - * @param {string} key - * @param {number} loopIndex * @returns {string} */ export const getVariableValue = (paramValue: string, reactFlowNodes: IReactFlowNode[]) => { diff --git a/packages/ui/src/store/actions.js b/packages/ui/src/store/actions.js index e0600ffd..306c5cb0 100644 --- a/packages/ui/src/store/actions.js +++ b/packages/ui/src/store/actions.js @@ -8,7 +8,6 @@ export const SET_LAYOUT = '@customization/SET_LAYOUT ' export const SET_DARKMODE = '@customization/SET_DARKMODE' // action - canvas reducer -export const REMOVE_EDGE = '@canvas/REMOVE_EDGE' export const SET_DIRTY = '@canvas/SET_DIRTY' export const REMOVE_DIRTY = '@canvas/REMOVE_DIRTY' export const SET_CHATFLOW = '@canvas/SET_CHATFLOW' diff --git a/packages/ui/src/store/context/ReactFlowContext.js b/packages/ui/src/store/context/ReactFlowContext.js index 1620c2ea..b8b32606 100644 --- a/packages/ui/src/store/context/ReactFlowContext.js +++ b/packages/ui/src/store/context/ReactFlowContext.js @@ -4,7 +4,8 @@ import PropTypes from 'prop-types' const initialValue = { reactFlowInstance: null, setReactFlowInstance: () => {}, - deleteNode: () => {} + deleteNode: () => {}, + deleteEdge: () => {} } export const flowContext = createContext(initialValue) @@ -17,12 +18,17 @@ export const ReactFlowContext = ({ children }) => { reactFlowInstance.setEdges(reactFlowInstance.getEdges().filter((ns) => ns.source !== id && ns.target !== id)) } + const deleteEdge = (id) => { + reactFlowInstance.setEdges(reactFlowInstance.getEdges().filter((edge) => edge.id !== id)) + } + return ( {children} diff --git a/packages/ui/src/store/reducers/canvasReducer.js b/packages/ui/src/store/reducers/canvasReducer.js index c16904aa..e98805bb 100644 --- a/packages/ui/src/store/reducers/canvasReducer.js +++ b/packages/ui/src/store/reducers/canvasReducer.js @@ -2,7 +2,6 @@ import * as actionTypes from '../actions' export const initialState = { - removeEdgeId: '', isDirty: false, chatflow: null } @@ -11,11 +10,6 @@ export const initialState = { const canvasReducer = (state = initialState, action) => { switch (action.type) { - case actionTypes.REMOVE_EDGE: - return { - ...state, - removeEdgeId: action.edgeId - } case actionTypes.SET_DIRTY: return { ...state, diff --git a/packages/ui/src/ui-component/file/File.js b/packages/ui/src/ui-component/file/File.js new file mode 100644 index 00000000..1a467fe9 --- /dev/null +++ b/packages/ui/src/ui-component/file/File.js @@ -0,0 +1,57 @@ +import { useState } from 'react' +import PropTypes from 'prop-types' +import { useTheme } from '@mui/material/styles' +import { FormControl, Button } from '@mui/material' +import { IconUpload } from '@tabler/icons' +import { getFileName } from 'utils/genericHelper' + +export const File = ({ value, fileType, onChange }) => { + const theme = useTheme() + + const [myValue, setMyValue] = useState(value ?? '') + + const handleFileUpload = (e) => { + if (!e.target.files) return + + const file = e.target.files[0] + const { name } = file + + const reader = new FileReader() + reader.onload = (evt) => { + if (!evt?.target?.result) { + return + } + const { result } = evt.target + + const value = result + `,filename:${name}` + + setMyValue(value) + onChange(value) + } + reader.readAsDataURL(file) + } + + return ( + + + {myValue ? getFileName(myValue) : 'Choose a file to upload'} + + + + ) +} + +File.propTypes = { + value: PropTypes.string, + fileType: PropTypes.string, + onChange: PropTypes.func +} diff --git a/packages/ui/src/views/canvas/ButtonEdge.js b/packages/ui/src/views/canvas/ButtonEdge.js index 827d51ec..0d819f81 100644 --- a/packages/ui/src/views/canvas/ButtonEdge.js +++ b/packages/ui/src/views/canvas/ButtonEdge.js @@ -1,7 +1,9 @@ import { getBezierPath, EdgeText } from 'reactflow' import PropTypes from 'prop-types' import { useDispatch } from 'react-redux' -import { REMOVE_EDGE } from 'store/actions' +import { useContext } from 'react' +import { SET_DIRTY } from 'store/actions' +import { flowContext } from 'store/context/ReactFlowContext' import './index.css' @@ -17,11 +19,14 @@ const ButtonEdge = ({ id, sourceX, sourceY, targetX, targetY, sourcePosition, ta targetPosition }) + const { deleteEdge } = useContext(flowContext) + const dispatch = useDispatch() const onEdgeClick = (evt, id) => { evt.stopPropagation() - dispatch({ type: REMOVE_EDGE, edgeId: `${id}:${Date.now()}` }) + deleteEdge(id) + dispatch({ type: SET_DIRTY }) } return ( diff --git a/packages/ui/src/views/canvas/CanvasNode.js b/packages/ui/src/views/canvas/CanvasNode.js index a264c924..1d473521 100644 --- a/packages/ui/src/views/canvas/CanvasNode.js +++ b/packages/ui/src/views/canvas/CanvasNode.js @@ -47,7 +47,7 @@ const CanvasNode = ({ data }) => { >
- +
{ {inputParam.label} {!inputParam.optional &&  *} + {inputParam.type === 'file' && ( + (data.inputs[inputParam.name] = newValue)} + value={data.inputs[inputParam.name] ?? inputParam.default ?? 'Choose a file to upload'} + /> + )} {(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && ( { ) setEdges((eds) => addEdge(newEdge, eds)) - setDirty() } const handleLoadFlow = (file) => { @@ -389,18 +388,6 @@ const Canvas = () => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [testChatflowApi.error]) - // Listen to edge button click remove redux event - useEffect(() => { - if (reactFlowInstance) { - const edges = reactFlowInstance.getEdges() - const toRemoveEdgeId = canvasDataStore.removeEdgeId.split(':')[0] - setEdges(edges.filter((edge) => edge.id !== toRemoveEdgeId)) - setDirty() - } - - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [canvasDataStore.removeEdgeId]) - useEffect(() => setChatflow(canvasDataStore.chatflow), [canvasDataStore.chatflow]) // Initialization diff --git a/packages/ui/src/views/chatmessage/ChatMessage.js b/packages/ui/src/views/chatmessage/ChatMessage.js index fd7c5ab1..45cd3873 100644 --- a/packages/ui/src/views/chatmessage/ChatMessage.js +++ b/packages/ui/src/views/chatmessage/ChatMessage.js @@ -46,7 +46,6 @@ export const ChatMessage = ({ chatflowid }) => { const [open, setOpen] = useState(false) const [userInput, setUserInput] = useState('') - const [history, setHistory] = useState([]) const [loading, setLoading] = useState(false) const [messages, setMessages] = useState([ { @@ -157,7 +156,10 @@ export const ChatMessage = ({ chatflowid }) => { // Send user question and history to API try { - const response = await predictionApi.sendMessageAndGetPrediction(chatflowid, { question: userInput, history: history }) + const response = await predictionApi.sendMessageAndGetPrediction(chatflowid, { + question: userInput, + history: messages.filter((msg) => msg.message !== 'Hi there! How can I help?') + }) if (response.data) { const data = response.data setMessages((prevMessages) => [...prevMessages, { message: data, type: 'apiMessage' }]) @@ -203,13 +205,6 @@ export const ChatMessage = ({ chatflowid }) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [getChatmessageApi.data]) - // Keep history in sync with messages - useEffect(() => { - if (messages.length >= 3) { - setHistory([[messages[messages.length - 2].message, messages[messages.length - 1].message]]) - } - }, [messages]) - // Auto scroll chat to bottom useEffect(() => { scrollToBottom() @@ -229,7 +224,6 @@ export const ChatMessage = ({ chatflowid }) => { return () => { setUserInput('') - setHistory([]) setLoading(false) setMessages([ {