From 94461025dc82ceae746f4f91aaad1608f84907d1 Mon Sep 17 00:00:00 2001 From: Henry Date: Wed, 16 Aug 2023 01:43:11 +0100 Subject: [PATCH] add vector to prompt --- .../ConversationChain/ConversationChain.ts | 3 +- .../VectorStoreToDocument.ts | 87 ++ .../VectorStoreToDocument/vectorretriever.svg | 7 + packages/components/src/utils.ts | 19 + .../Prompt Chaining with VectorStore.json | 966 ++++++++++++++++++ .../chatflows/Vectara LLM Chain Upload.json | 34 +- packages/server/src/index.ts | 24 +- packages/server/src/utils/index.ts | 42 +- packages/ui/src/assets/images/chathistory.png | Bin 0 -> 12068 bytes .../src/ui-component/dialog/NodeInfoDialog.js | 2 +- .../src/ui-component/json/SelectVariable.js | 50 +- 11 files changed, 1194 insertions(+), 40 deletions(-) create mode 100644 packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts create mode 100644 packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg create mode 100644 packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json create mode 100644 packages/ui/src/assets/images/chathistory.png diff --git a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts index cd42a6700..08663395e 100644 --- a/packages/components/nodes/chains/ConversationChain/ConversationChain.ts +++ b/packages/components/nodes/chains/ConversationChain/ConversationChain.ts @@ -45,7 +45,8 @@ class ConversationChain_Chains implements INode { label: 'Document', name: 'document', type: 'Document', - description: 'Include whole document into the context window', + description: + 'Include whole document into the context window, if you get maximum context length error, please use model with higher context window like Claude 100k, or gpt4 32k', optional: true, list: true }, diff --git a/packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts b/packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts new file mode 100644 index 000000000..b3f320ce4 --- /dev/null +++ b/packages/components/nodes/documentloaders/VectorStoreToDocument/VectorStoreToDocument.ts @@ -0,0 +1,87 @@ +import { VectorStore } from 'langchain/vectorstores/base' +import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface' +import { handleEscapeCharacters } from '../../../src/utils' + +class VectorStoreToDocument_DocumentLoaders implements INode { + label: string + name: string + version: number + description: string + type: string + icon: string + category: string + baseClasses: string[] + inputs: INodeParams[] + outputs: INodeOutputsValue[] + + constructor() { + this.label = 'VectorStore To Document' + this.name = 'vectorStoreToDocument' + this.version = 1.0 + this.type = 'Document' + this.icon = 'vectorretriever.svg' + this.category = 'Document Loaders' + this.description = 'Search documents with scores from vector store' + this.baseClasses = [this.type] + this.inputs = [ + { + label: 'Vector Store', + name: 'vectorStore', + type: 'VectorStore' + }, + { + label: 'Minimum Score (%)', + name: 'minScore', + type: 'number', + optional: true, + placeholder: '75', + step: 1, + description: 'Minumum score for embeddings documents to be included' + } + ] + this.outputs = [ + { + label: 'Document', + name: 'document', + baseClasses: this.baseClasses + }, + { + label: 'Text', + name: 'text', + baseClasses: ['string', 'json'] + } + ] + } + + async init(nodeData: INodeData, input: string): Promise { + const vectorStore = nodeData.inputs?.vectorStore as VectorStore + const minScore = nodeData.inputs?.minScore as number + const output = nodeData.outputs?.output as string + + const topK = (vectorStore as any)?.k ?? 4 + + const docs = await vectorStore.similaritySearchWithScore(input, topK) + // eslint-disable-next-line no-console + console.log('\x1b[94m\x1b[1m\n*****VectorStore Documents*****\n\x1b[0m\x1b[0m') + // eslint-disable-next-line no-console + console.log(docs) + + if (output === 'document') { + let finaldocs = [] + for (const doc of docs) { + if (minScore && doc[1] < minScore / 100) continue + finaldocs.push(doc[0]) + } + return finaldocs + } else { + let finaltext = '' + for (const doc of docs) { + if (minScore && doc[1] < minScore / 100) continue + finaltext += `${doc[0].pageContent}\n` + } + return handleEscapeCharacters(finaltext, false) + } + } +} + +module.exports = { nodeClass: VectorStoreToDocument_DocumentLoaders } diff --git a/packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg b/packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg new file mode 100644 index 000000000..208a59f14 --- /dev/null +++ b/packages/components/nodes/documentloaders/VectorStoreToDocument/vectorretriever.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/packages/components/src/utils.ts b/packages/components/src/utils.ts index bcca834ae..8d06a6501 100644 --- a/packages/components/src/utils.ts +++ b/packages/components/src/utils.ts @@ -520,3 +520,22 @@ export const mapChatHistory = (options: ICommonObject): ChatMessageHistory => { } return new ChatMessageHistory(chatHistory) } + +/** + * Convert incoming chat history to string + * @param {IMessage[]} chatHistory + * @returns {string} + */ +export const convertChatHistoryToText = (chatHistory: IMessage[]): string => { + return chatHistory + .map((chatMessage) => { + if (chatMessage.type === 'apiMessage') { + return `Assistant: ${chatMessage.message}` + } else if (chatMessage.type === 'userMessage') { + return `Human: ${chatMessage.message}` + } else { + return `${chatMessage.message}` + } + }) + .join('\n') +} diff --git a/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json new file mode 100644 index 000000000..9d6838eb3 --- /dev/null +++ b/packages/server/marketplaces/chatflows/Prompt Chaining with VectorStore.json @@ -0,0 +1,966 @@ +{ + "description": "Use chat history to rephrase user question, and answer the rephrased question using retrieved docs from vector store", + "nodes": [ + { + "width": 300, + "height": 503, + "id": "pineconeExistingIndex_0", + "position": { + "x": 1062.7418678410986, + "y": -109.27680365777141 + }, + "type": "customNode", + "data": { + "id": "pineconeExistingIndex_0", + "label": "Pinecone Load Existing Index", + "version": 1, + "name": "pineconeExistingIndex", + "type": "Pinecone", + "baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"], + "category": "Vector Stores", + "description": "Load existing index from Pinecone (i.e: Document has been upserted)", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["pineconeApi"], + "id": "pineconeExistingIndex_0-input-credential-credential" + }, + { + "label": "Pinecone Index", + "name": "pineconeIndex", + "type": "string", + "id": "pineconeExistingIndex_0-input-pineconeIndex-string" + }, + { + "label": "Pinecone Namespace", + "name": "pineconeNamespace", + "type": "string", + "placeholder": "my-first-namespace", + "additionalParams": true, + "optional": true, + "id": "pineconeExistingIndex_0-input-pineconeNamespace-string" + }, + { + "label": "Pinecone Metadata Filter", + "name": "pineconeMetadataFilter", + "type": "json", + "optional": true, + "additionalParams": true, + "id": "pineconeExistingIndex_0-input-pineconeMetadataFilter-json" + }, + { + "label": "Top K", + "name": "topK", + "description": "Number of top results to fetch. Default to 4", + "placeholder": "4", + "type": "number", + "additionalParams": true, + "optional": true, + "id": "pineconeExistingIndex_0-input-topK-number" + } + ], + "inputAnchors": [ + { + "label": "Embeddings", + "name": "embeddings", + "type": "Embeddings", + "id": "pineconeExistingIndex_0-input-embeddings-Embeddings" + } + ], + "inputs": { + "embeddings": "{{openAIEmbeddings_0.data.instance}}", + "pineconeIndex": "newindex", + "pineconeNamespace": "", + "pineconeMetadataFilter": "{}", + "topK": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "pineconeExistingIndex_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever", + "name": "retriever", + "label": "Pinecone Retriever", + "type": "Pinecone | VectorStoreRetriever | BaseRetriever" + }, + { + "id": "pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore", + "name": "vectorStore", + "label": "Pinecone Vector Store", + "type": "Pinecone | VectorStore" + } + ], + "default": "retriever" + } + ], + "outputs": { + "output": "vectorStore" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1062.7418678410986, + "y": -109.27680365777141 + }, + "dragging": false + }, + { + "width": 300, + "height": 327, + "id": "openAIEmbeddings_0", + "position": { + "x": 711.3971966563331, + "y": 7.7184225021727 + }, + "type": "customNode", + "data": { + "id": "openAIEmbeddings_0", + "label": "OpenAI Embeddings", + "version": 1, + "name": "openAIEmbeddings", + "type": "OpenAIEmbeddings", + "baseClasses": ["OpenAIEmbeddings", "Embeddings"], + "category": "Embeddings", + "description": "OpenAI API to generate embeddings for a given text", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "openAIEmbeddings_0-input-credential-credential" + }, + { + "label": "Strip New Lines", + "name": "stripNewLines", + "type": "boolean", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-stripNewLines-boolean" + }, + { + "label": "Batch Size", + "name": "batchSize", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-batchSize-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "openAIEmbeddings_0-input-basepath-string" + } + ], + "inputAnchors": [], + "inputs": { + "stripNewLines": "", + "batchSize": "", + "timeout": "", + "basepath": "" + }, + "outputAnchors": [ + { + "id": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings", + "name": "openAIEmbeddings", + "label": "OpenAIEmbeddings", + "type": "OpenAIEmbeddings | Embeddings" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 711.3971966563331, + "y": 7.7184225021727 + }, + "dragging": false + }, + { + "width": 300, + "height": 473, + "id": "promptTemplate_0", + "position": { + "x": 348.2881107399286, + "y": -97.74510214137423 + }, + "type": "customNode", + "data": { + "id": "promptTemplate_0", + "label": "Prompt Template", + "version": 1, + "name": "promptTemplate", + "type": "PromptTemplate", + "baseClasses": ["PromptTemplate", "BaseStringPromptTemplate", "BasePromptTemplate", "Runnable"], + "category": "Prompts", + "description": "Schema to represent a basic prompt for an LLM", + "inputParams": [ + { + "label": "Template", + "name": "template", + "type": "string", + "rows": 4, + "placeholder": "What is a good name for a company that makes {product}?", + "id": "promptTemplate_0-input-template-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "promptTemplate_0-input-promptValues-json" + } + ], + "inputAnchors": [], + "inputs": { + "template": "Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question.\n\nChat History:\n{chat_history}\nFollow Up Input: {question}\nStandalone question:", + "promptValues": "{\"question\":\"{{question}}\",\"chat_history\":\"{{chat_history}}\"}" + }, + "outputAnchors": [ + { + "id": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "name": "promptTemplate", + "label": "PromptTemplate", + "type": "PromptTemplate | BaseStringPromptTemplate | BasePromptTemplate | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 348.2881107399286, + "y": -97.74510214137423 + }, + "dragging": false + }, + { + "width": 300, + "height": 522, + "id": "chatOpenAI_0", + "position": { + "x": 335.7621848973805, + "y": -651.7411273245009 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_0", + "label": "ChatOpenAI", + "version": 1, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_0-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "gpt-4", + "name": "gpt-4" + }, + { + "label": "gpt-4-0613", + "name": "gpt-4-0613" + }, + { + "label": "gpt-4-32k", + "name": "gpt-4-32k" + }, + { + "label": "gpt-4-32k-0613", + "name": "gpt-4-32k-0613" + }, + { + "label": "gpt-3.5-turbo", + "name": "gpt-3.5-turbo" + }, + { + "label": "gpt-3.5-turbo-0613", + "name": "gpt-3.5-turbo-0613" + }, + { + "label": "gpt-3.5-turbo-16k", + "name": "gpt-3.5-turbo-16k" + }, + { + "label": "gpt-3.5-turbo-16k-0613", + "name": "gpt-3.5-turbo-16k-0613" + } + ], + "default": "gpt-3.5-turbo", + "optional": true, + "id": "chatOpenAI_0-input-modelName-options" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_0-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_0-input-basepath-string" + } + ], + "inputAnchors": [], + "inputs": { + "modelName": "gpt-3.5-turbo-16k", + "temperature": 0.9, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "dragging": false, + "positionAbsolute": { + "x": 335.7621848973805, + "y": -651.7411273245009 + } + }, + { + "width": 300, + "height": 522, + "id": "chatOpenAI_1", + "position": { + "x": 1765.2801848172305, + "y": -667.9261054149061 + }, + "type": "customNode", + "data": { + "id": "chatOpenAI_1", + "label": "ChatOpenAI", + "version": 1, + "name": "chatOpenAI", + "type": "ChatOpenAI", + "baseClasses": ["ChatOpenAI", "BaseChatModel", "BaseLanguageModel", "Runnable"], + "category": "Chat Models", + "description": "Wrapper around OpenAI large language models that use the Chat endpoint", + "inputParams": [ + { + "label": "Connect Credential", + "name": "credential", + "type": "credential", + "credentialNames": ["openAIApi"], + "id": "chatOpenAI_1-input-credential-credential" + }, + { + "label": "Model Name", + "name": "modelName", + "type": "options", + "options": [ + { + "label": "gpt-4", + "name": "gpt-4" + }, + { + "label": "gpt-4-0613", + "name": "gpt-4-0613" + }, + { + "label": "gpt-4-32k", + "name": "gpt-4-32k" + }, + { + "label": "gpt-4-32k-0613", + "name": "gpt-4-32k-0613" + }, + { + "label": "gpt-3.5-turbo", + "name": "gpt-3.5-turbo" + }, + { + "label": "gpt-3.5-turbo-0613", + "name": "gpt-3.5-turbo-0613" + }, + { + "label": "gpt-3.5-turbo-16k", + "name": "gpt-3.5-turbo-16k" + }, + { + "label": "gpt-3.5-turbo-16k-0613", + "name": "gpt-3.5-turbo-16k-0613" + } + ], + "default": "gpt-3.5-turbo", + "optional": true, + "id": "chatOpenAI_1-input-modelName-options" + }, + { + "label": "Temperature", + "name": "temperature", + "type": "number", + "step": 0.1, + "default": 0.9, + "optional": true, + "id": "chatOpenAI_1-input-temperature-number" + }, + { + "label": "Max Tokens", + "name": "maxTokens", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-maxTokens-number" + }, + { + "label": "Top Probability", + "name": "topP", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-topP-number" + }, + { + "label": "Frequency Penalty", + "name": "frequencyPenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-frequencyPenalty-number" + }, + { + "label": "Presence Penalty", + "name": "presencePenalty", + "type": "number", + "step": 0.1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-presencePenalty-number" + }, + { + "label": "Timeout", + "name": "timeout", + "type": "number", + "step": 1, + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-timeout-number" + }, + { + "label": "BasePath", + "name": "basepath", + "type": "string", + "optional": true, + "additionalParams": true, + "id": "chatOpenAI_1-input-basepath-string" + } + ], + "inputAnchors": [], + "inputs": { + "modelName": "gpt-3.5-turbo-16k", + "temperature": 0.9, + "maxTokens": "", + "topP": "", + "frequencyPenalty": "", + "presencePenalty": "", + "timeout": "", + "basepath": "" + }, + "outputAnchors": [ + { + "id": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "name": "chatOpenAI", + "label": "ChatOpenAI", + "type": "ChatOpenAI | BaseChatModel | BaseLanguageModel | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "dragging": false, + "positionAbsolute": { + "x": 1765.2801848172305, + "y": -667.9261054149061 + } + }, + { + "width": 300, + "height": 473, + "id": "promptTemplate_1", + "position": { + "x": 1773.720934090435, + "y": -116.71323227575395 + }, + "type": "customNode", + "data": { + "id": "promptTemplate_1", + "label": "Prompt Template", + "version": 1, + "name": "promptTemplate", + "type": "PromptTemplate", + "baseClasses": ["PromptTemplate", "BaseStringPromptTemplate", "BasePromptTemplate", "Runnable"], + "category": "Prompts", + "description": "Schema to represent a basic prompt for an LLM", + "inputParams": [ + { + "label": "Template", + "name": "template", + "type": "string", + "rows": 4, + "placeholder": "What is a good name for a company that makes {product}?", + "id": "promptTemplate_1-input-template-string" + }, + { + "label": "Format Prompt Values", + "name": "promptValues", + "type": "json", + "optional": true, + "acceptVariable": true, + "list": true, + "id": "promptTemplate_1-input-promptValues-json" + } + ], + "inputAnchors": [], + "inputs": { + "template": "Use the following pieces of context to answer the question at the end.\n\n{context}\n\nQuestion: {question}\nHelpful Answer:", + "promptValues": "{\"context\":\"{{vectorStoreToDocument_0.data.instance}}\",\"question\":\"{{llmChain_0.data.instance}}\"}" + }, + "outputAnchors": [ + { + "id": "promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "name": "promptTemplate", + "label": "PromptTemplate", + "type": "PromptTemplate | BaseStringPromptTemplate | BasePromptTemplate | Runnable" + } + ], + "outputs": {}, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1773.720934090435, + "y": -116.71323227575395 + }, + "dragging": false + }, + { + "width": 300, + "height": 404, + "id": "llmChain_0", + "position": { + "x": 756.1670091985342, + "y": -592.5151355056942 + }, + "type": "customNode", + "data": { + "id": "llmChain_0", + "label": "LLM Chain", + "version": 1, + "name": "llmChain", + "type": "LLMChain", + "baseClasses": ["LLMChain", "BaseChain", "Runnable"], + "category": "Chains", + "description": "Chain to run queries against LLMs", + "inputParams": [ + { + "label": "Chain Name", + "name": "chainName", + "type": "string", + "placeholder": "Name Your Chain", + "optional": true, + "id": "llmChain_0-input-chainName-string" + } + ], + "inputAnchors": [ + { + "label": "Language Model", + "name": "model", + "type": "BaseLanguageModel", + "id": "llmChain_0-input-model-BaseLanguageModel" + }, + { + "label": "Prompt", + "name": "prompt", + "type": "BasePromptTemplate", + "id": "llmChain_0-input-prompt-BasePromptTemplate" + } + ], + "inputs": { + "model": "{{chatOpenAI_0.data.instance}}", + "prompt": "{{promptTemplate_0.data.instance}}", + "chainName": "QuestionChain" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "llmChain_0-output-llmChain-LLMChain|BaseChain|Runnable", + "name": "llmChain", + "label": "LLM Chain", + "type": "LLMChain | BaseChain | Runnable" + }, + { + "id": "llmChain_0-output-outputPrediction-string|json", + "name": "outputPrediction", + "label": "Output Prediction", + "type": "string | json" + } + ], + "default": "llmChain" + } + ], + "outputs": { + "output": "outputPrediction" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 756.1670091985342, + "y": -592.5151355056942 + }, + "dragging": false + }, + { + "width": 300, + "height": 404, + "id": "llmChain_1", + "position": { + "x": 2200.1274896215496, + "y": -144.29167974642334 + }, + "type": "customNode", + "data": { + "id": "llmChain_1", + "label": "LLM Chain", + "version": 1, + "name": "llmChain", + "type": "LLMChain", + "baseClasses": ["LLMChain", "BaseChain", "Runnable"], + "category": "Chains", + "description": "Chain to run queries against LLMs", + "inputParams": [ + { + "label": "Chain Name", + "name": "chainName", + "type": "string", + "placeholder": "Name Your Chain", + "optional": true, + "id": "llmChain_1-input-chainName-string" + } + ], + "inputAnchors": [ + { + "label": "Language Model", + "name": "model", + "type": "BaseLanguageModel", + "id": "llmChain_1-input-model-BaseLanguageModel" + }, + { + "label": "Prompt", + "name": "prompt", + "type": "BasePromptTemplate", + "id": "llmChain_1-input-prompt-BasePromptTemplate" + } + ], + "inputs": { + "model": "{{chatOpenAI_1.data.instance}}", + "prompt": "{{promptTemplate_1.data.instance}}", + "chainName": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "llmChain_1-output-llmChain-LLMChain|BaseChain|Runnable", + "name": "llmChain", + "label": "LLM Chain", + "type": "LLMChain | BaseChain | Runnable" + }, + { + "id": "llmChain_1-output-outputPrediction-string|json", + "name": "outputPrediction", + "label": "Output Prediction", + "type": "string | json" + } + ], + "default": "llmChain" + } + ], + "outputs": { + "output": "llmChain" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 2200.1274896215496, + "y": -144.29167974642334 + }, + "dragging": false + }, + { + "width": 300, + "height": 353, + "id": "vectorStoreToDocument_0", + "position": { + "x": 1407.7038120189868, + "y": -26.16468811205081 + }, + "type": "customNode", + "data": { + "id": "vectorStoreToDocument_0", + "label": "VectorStore To Document", + "version": 1, + "name": "vectorStoreToDocument", + "type": "Document", + "baseClasses": ["Document"], + "category": "Document Loaders", + "description": "Search documents with scores from vector store", + "inputParams": [ + { + "label": "Minimum Score (%)", + "name": "minScore", + "type": "number", + "optional": true, + "placeholder": "75", + "step": 1, + "description": "Minumum score for embeddings documents to be included", + "id": "vectorStoreToDocument_0-input-minScore-number" + } + ], + "inputAnchors": [ + { + "label": "Vector Store", + "name": "vectorStore", + "type": "VectorStore", + "id": "vectorStoreToDocument_0-input-vectorStore-VectorStore" + } + ], + "inputs": { + "vectorStore": "{{pineconeExistingIndex_0.data.instance}}", + "minScore": "" + }, + "outputAnchors": [ + { + "name": "output", + "label": "Output", + "type": "options", + "options": [ + { + "id": "vectorStoreToDocument_0-output-document-Document", + "name": "document", + "label": "Document", + "type": "Document" + }, + { + "id": "vectorStoreToDocument_0-output-text-string|json", + "name": "text", + "label": "Text", + "type": "string | json" + } + ], + "default": "document" + } + ], + "outputs": { + "output": "text" + }, + "selected": false + }, + "selected": false, + "positionAbsolute": { + "x": 1407.7038120189868, + "y": -26.16468811205081 + }, + "dragging": false + } + ], + "edges": [ + { + "source": "openAIEmbeddings_0", + "sourceHandle": "openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings", + "target": "pineconeExistingIndex_0", + "targetHandle": "pineconeExistingIndex_0-input-embeddings-Embeddings", + "type": "buttonedge", + "id": "openAIEmbeddings_0-openAIEmbeddings_0-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings-pineconeExistingIndex_0-pineconeExistingIndex_0-input-embeddings-Embeddings", + "data": { + "label": "" + } + }, + { + "source": "pineconeExistingIndex_0", + "sourceHandle": "pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore", + "target": "vectorStoreToDocument_0", + "targetHandle": "vectorStoreToDocument_0-input-vectorStore-VectorStore", + "type": "buttonedge", + "id": "pineconeExistingIndex_0-pineconeExistingIndex_0-output-vectorStore-Pinecone|VectorStore-vectorStoreToDocument_0-vectorStoreToDocument_0-input-vectorStore-VectorStore", + "data": { + "label": "" + } + }, + { + "source": "vectorStoreToDocument_0", + "sourceHandle": "vectorStoreToDocument_0-output-text-string|json", + "target": "promptTemplate_1", + "targetHandle": "promptTemplate_1-input-promptValues-json", + "type": "buttonedge", + "id": "vectorStoreToDocument_0-vectorStoreToDocument_0-output-text-string|json-promptTemplate_1-promptTemplate_1-input-promptValues-json", + "data": { + "label": "" + } + }, + { + "source": "chatOpenAI_0", + "sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "llmChain_0", + "targetHandle": "llmChain_0-input-model-BaseLanguageModel", + "type": "buttonedge", + "id": "chatOpenAI_0-chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_0-llmChain_0-input-model-BaseLanguageModel", + "data": { + "label": "" + } + }, + { + "source": "promptTemplate_0", + "sourceHandle": "promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "target": "llmChain_0", + "targetHandle": "llmChain_0-input-prompt-BasePromptTemplate", + "type": "buttonedge", + "id": "promptTemplate_0-promptTemplate_0-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_0-llmChain_0-input-prompt-BasePromptTemplate", + "data": { + "label": "" + } + }, + { + "source": "llmChain_0", + "sourceHandle": "llmChain_0-output-outputPrediction-string|json", + "target": "promptTemplate_1", + "targetHandle": "promptTemplate_1-input-promptValues-json", + "type": "buttonedge", + "id": "llmChain_0-llmChain_0-output-outputPrediction-string|json-promptTemplate_1-promptTemplate_1-input-promptValues-json", + "data": { + "label": "" + } + }, + { + "source": "chatOpenAI_1", + "sourceHandle": "chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable", + "target": "llmChain_1", + "targetHandle": "llmChain_1-input-model-BaseLanguageModel", + "type": "buttonedge", + "id": "chatOpenAI_1-chatOpenAI_1-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|Runnable-llmChain_1-llmChain_1-input-model-BaseLanguageModel", + "data": { + "label": "" + } + }, + { + "source": "promptTemplate_1", + "sourceHandle": "promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable", + "target": "llmChain_1", + "targetHandle": "llmChain_1-input-prompt-BasePromptTemplate", + "type": "buttonedge", + "id": "promptTemplate_1-promptTemplate_1-output-promptTemplate-PromptTemplate|BaseStringPromptTemplate|BasePromptTemplate|Runnable-llmChain_1-llmChain_1-input-prompt-BasePromptTemplate", + "data": { + "label": "" + } + } + ] +} diff --git a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json index 2146aa125..0758ec9a7 100644 --- a/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json +++ b/packages/server/marketplaces/chatflows/Vectara LLM Chain Upload.json @@ -4,14 +4,14 @@ { "width": 300, "height": 408, - "id": "vectaraExisting_0", + "id": "vectaraUpsert_0", "position": { "x": 438, "y": 214 }, "type": "customNode", "data": { - "id": "vectaraExisting_0", + "id": "vectaraUpsert_0", "label": "Vectara Upsert Document", "version": 1, - "name": "vectaraExisting", + "name": "vectaraUpsert", "type": "Vectara", "baseClasses": ["Vectara", "VectorStoreRetriever", "BaseRetriever"], "category": "Vector Stores", @@ -22,7 +22,7 @@ "name": "credential", "type": "credential", "credentialNames": ["vectaraApi"], - "id": "vectaraExisting_0-input-credential-credential" + "id": "vectaraUpsert_0-input-credential-credential" }, { "label": "Filter", @@ -30,7 +30,7 @@ "type": "json", "additionalParams": true, "optional": true, - "id": "vectaraExisting_0-input-filter-json" + "id": "vectaraUpsert_0-input-filter-json" }, { "label": "Lambda", @@ -38,7 +38,7 @@ "type": "number", "additionalParams": true, "optional": true, - "id": "vectaraExisting_0-input-lambda-number" + "id": "vectaraUpsert_0-input-lambda-number" }, { "label": "Top K", @@ -48,7 +48,7 @@ "type": "number", "additionalParams": true, "optional": true, - "id": "vectaraExisting_0-input-topK-number" + "id": "vectaraUpsert_0-input-topK-number" } ], "inputAnchors": [ @@ -57,7 +57,7 @@ "name": "document", "type": "Document", "list": true, - "id": "vectaraExisting_0-input-document-Document" + "id": "vectaraUpsert_0-input-document-Document" } ], "inputs": { @@ -73,13 +73,13 @@ "type": "options", "options": [ { - "id": "vectaraExisting_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", + "id": "vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", "name": "retriever", "label": "Vectara Retriever", "type": "Vectara | VectorStoreRetriever | BaseRetriever" }, { - "id": "vectaraExisting_0-output-vectorStore-Vectara|VectorStore", + "id": "vectaraUpsert_0-output-vectorStore-Vectara|VectorStore", "name": "vectorStore", "label": "Vectara Vector Store", "type": "Vectara | VectorStore" @@ -392,7 +392,7 @@ ], "inputs": { "model": "{{chatOpenAI_0.data.instance}}", - "vectorStoreRetriever": "{{vectaraExisting_0.data.instance}}", + "vectorStoreRetriever": "{{vectaraUpsert_0.data.instance}}", "memory": "", "returnSourceDocuments": "", "systemMessagePrompt": "", @@ -418,19 +418,19 @@ { "source": "pdfFile_0", "sourceHandle": "pdfFile_0-output-pdfFile-Document", - "target": "vectaraExisting_0", - "targetHandle": "vectaraExisting_0-input-document-Document", + "target": "vectaraUpsert_0", + "targetHandle": "vectaraUpsert_0-input-document-Document", "type": "buttonedge", - "id": "pdfFile_0-pdfFile_0-output-pdfFile-Document-vectaraExisting_0-vectaraExisting_0-input-document-Document", + "id": "pdfFile_0-pdfFile_0-output-pdfFile-Document-vectaraUpsert_0-vectaraUpsert_0-input-document-Document", "data": { "label": "" } }, { - "source": "vectaraExisting_0", - "sourceHandle": "vectaraExisting_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", + "source": "vectaraUpsert_0", + "sourceHandle": "vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever", "target": "conversationalRetrievalQAChain_0", "targetHandle": "conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", "type": "buttonedge", - "id": "vectaraExisting_0-vectaraExisting_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", + "id": "vectaraUpsert_0-vectaraUpsert_0-output-retriever-Vectara|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever", "data": { "label": "" } }, { diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index b72891495..fbb61b00a 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -811,11 +811,17 @@ export class App { } } + /*** Get chatflows and prepare data ***/ + const flowData = chatflow.flowData + const parsedFlowData: IReactFlowObject = JSON.parse(flowData) + const nodes = parsedFlowData.nodes + const edges = parsedFlowData.edges + /* Reuse the flow without having to rebuild (to avoid duplicated upsert, recomputation) when all these conditions met: * - Node Data already exists in pool * - Still in sync (i.e the flow has not been modified since) * - Existing overrideConfig and new overrideConfig are the same - * - Flow doesn't start with nodes that depend on incomingInput.question + * - Flow doesn't start with/contain nodes that depend on incomingInput.question ***/ const isFlowReusable = () => { return ( @@ -826,16 +832,10 @@ export class App { this.chatflowPool.activeChatflows[chatflowid].overrideConfig, incomingInput.overrideConfig ) && - !isStartNodeDependOnInput(this.chatflowPool.activeChatflows[chatflowid].startingNodes) + !isStartNodeDependOnInput(this.chatflowPool.activeChatflows[chatflowid].startingNodes, nodes) ) } - /*** Get chatflows and prepare data ***/ - const flowData = chatflow.flowData - const parsedFlowData: IReactFlowObject = JSON.parse(flowData) - const nodes = parsedFlowData.nodes - const edges = parsedFlowData.edges - if (isFlowReusable()) { nodeToExecuteData = this.chatflowPool.activeChatflows[chatflowid].endingNodeData isStreamValid = isFlowValidForStream(nodes, nodeToExecuteData) @@ -884,6 +884,7 @@ export class App { depthQueue, this.nodesPool.componentNodes, incomingInput.question, + incomingInput.history, chatId, this.AppDataSource, incomingInput?.overrideConfig @@ -894,7 +895,12 @@ export class App { if (incomingInput.overrideConfig) nodeToExecute.data = replaceInputsWithConfig(nodeToExecute.data, incomingInput.overrideConfig) - const reactFlowNodeData: INodeData = resolveVariables(nodeToExecute.data, reactFlowNodes, incomingInput.question) + const reactFlowNodeData: INodeData = resolveVariables( + nodeToExecute.data, + reactFlowNodes, + incomingInput.question, + incomingInput.history + ) nodeToExecuteData = reactFlowNodeData const startingNodes = nodes.filter((nd) => startingNodeIds.includes(nd.id)) diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index cf4a9c3fe..788b7c0ec 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -19,7 +19,14 @@ import { ICredentialReqBody } from '../Interface' import { cloneDeep, get, omit, merge, isEqual } from 'lodash' -import { ICommonObject, getInputVariables, IDatabaseEntity, handleEscapeCharacters } from 'flowise-components' +import { + ICommonObject, + getInputVariables, + IDatabaseEntity, + handleEscapeCharacters, + IMessage, + convertChatHistoryToText +} from 'flowise-components' import { scryptSync, randomBytes, timingSafeEqual } from 'crypto' import { lib, PBKDF2, AES, enc } from 'crypto-js' @@ -30,6 +37,7 @@ import { Tool } from '../entity/Tool' import { DataSource } from 'typeorm' const QUESTION_VAR_PREFIX = 'question' +const CHAT_HISTORY_VAR_PREFIX = 'chat_history' const REDACTED_CREDENTIAL_VALUE = '_FLOWISE_BLANK_07167752-1a71-43b1-bf8f-4f32252165db' export const databaseEntities: IDatabaseEntity = { ChatFlow: ChatFlow, ChatMessage: ChatMessage, Tool: Tool, Credential: Credential } @@ -199,6 +207,7 @@ export const buildLangchain = async ( depthQueue: IDepthQueue, componentNodes: IComponentNodes, question: string, + chatHistory: IMessage[], chatId: string, appDataSource: DataSource, overrideConfig?: ICommonObject @@ -231,7 +240,7 @@ export const buildLangchain = async ( let flowNodeData = cloneDeep(reactFlowNode.data) if (overrideConfig) flowNodeData = replaceInputsWithConfig(flowNodeData, overrideConfig) - const reactFlowNodeData: INodeData = resolveVariables(flowNodeData, flowNodes, question) + const reactFlowNodeData: INodeData = resolveVariables(flowNodeData, flowNodes, question, chatHistory) logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`) flowNodes[nodeIndex].data.instance = await newNodeInstance.init(reactFlowNodeData, question, { @@ -315,7 +324,13 @@ export const clearSessionMemory = async ( * @param {boolean} isAcceptVariable * @returns {string} */ -export const getVariableValue = (paramValue: string, reactFlowNodes: IReactFlowNode[], question: string, isAcceptVariable = false) => { +export const getVariableValue = ( + paramValue: string, + reactFlowNodes: IReactFlowNode[], + question: string, + chatHistory: IMessage[], + isAcceptVariable = false +) => { let returnVal = paramValue const variableStack = [] const variableDict = {} as IVariableDict @@ -345,6 +360,10 @@ export const getVariableValue = (paramValue: string, reactFlowNodes: IReactFlowN variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(question, false) } + if (isAcceptVariable && variableFullPath === CHAT_HISTORY_VAR_PREFIX) { + variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(convertChatHistoryToText(chatHistory), false) + } + // Split by first occurrence of '.' to get just nodeId const [variableNodeId, _] = variableFullPath.split('.') const executedNode = reactFlowNodes.find((nd) => nd.id === variableNodeId) @@ -400,7 +419,12 @@ export const isVectorStoreFaiss = (flowNodeData: INodeData) => { * @param {string} question * @returns {INodeData} */ -export const resolveVariables = (reactFlowNodeData: INodeData, reactFlowNodes: IReactFlowNode[], question: string): INodeData => { +export const resolveVariables = ( + reactFlowNodeData: INodeData, + reactFlowNodes: IReactFlowNode[], + question: string, + chatHistory: IMessage[] +): INodeData => { let flowNodeData = cloneDeep(reactFlowNodeData) if (reactFlowNodeData.instance && isVectorStoreFaiss(reactFlowNodeData)) { // omit and merge because cloneDeep of instance gives "Illegal invocation" Exception @@ -415,13 +439,13 @@ export const resolveVariables = (reactFlowNodeData: INodeData, reactFlowNodes: I if (Array.isArray(paramValue)) { const resolvedInstances = [] for (const param of paramValue) { - const resolvedInstance = getVariableValue(param, reactFlowNodes, question) + const resolvedInstance = getVariableValue(param, reactFlowNodes, question, chatHistory) resolvedInstances.push(resolvedInstance) } paramsObj[key] = resolvedInstances } else { const isAcceptVariable = reactFlowNodeData.inputParams.find((param) => param.name === key)?.acceptVariable ?? false - const resolvedInstance = getVariableValue(paramValue, reactFlowNodes, question, isAcceptVariable) + const resolvedInstance = getVariableValue(paramValue, reactFlowNodes, question, chatHistory, isAcceptVariable) paramsObj[key] = resolvedInstance } } @@ -474,13 +498,17 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig: * @param {IReactFlowNode[]} startingNodes * @returns {boolean} */ -export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[]): boolean => { +export const isStartNodeDependOnInput = (startingNodes: IReactFlowNode[], nodes: IReactFlowNode[]): boolean => { for (const node of startingNodes) { for (const inputName in node.data.inputs) { const inputVariables = getInputVariables(node.data.inputs[inputName]) if (inputVariables.length > 0) return true } } + const whitelistNodeNames = ['vectorStoreToDocument'] + for (const node of nodes) { + if (whitelistNodeNames.includes(node.data.name)) return true + } return false } diff --git a/packages/ui/src/assets/images/chathistory.png b/packages/ui/src/assets/images/chathistory.png new file mode 100644 index 0000000000000000000000000000000000000000..52f496a89bafe01b39986a9ff63d19fd006972fe GIT binary patch literal 12068 zcmd_QhdW$f_%FHuAtIyqUV`XBFnXIr5JVfjj5^wA2|*AgMbscl zbP|2^E{5Uk`ToxR7w)~!IrBWsJbSP8u6KRjRX*$Ut|)Cy6>3UmN&o<;;ZGmy0stxa zlN7je8T>l%8^MELS6@Cg@d8L-hr~aUv@1SF;6o;avN1x>-5%jsO}_U4SgAKDvzzI(c#4beD;SWHaT)bpr4O0amCVwYUG z$$!n%J6Rb`^29_XG|oHY#wC?kIwT$n*Yjm@U+=)Wt`xj2s1v8sR^Wg8tRWkrm6W}* ze_E(~Lk;JdvoG6w>TS{T8M%1c7{xV!-mZm%&i$YB5y%XuLH>LKE$&>_{dLL6?RDp` z)vlm7y(&))g-*2jv6Sc=d@99$VZ9F4iF?Vxv&FabH$=0yGvn6&XkNIga$b7)@hdleOM4k6TCz=0^Skz!!2?=-rIS z`j%s`ID$c;0N8lnw9M3*d6qR9w9XD}+#V(?p5|?uTyD7uqZD8veRq>59s*~>z2=Pb#D$#`^A@qxNnu-VWb;``(yeL4-RM!zGk{II+;<$N-_Ec`N) zQ6?^M{ts>5PNtW~*<+>QgF;1$M<<2AS;}Z#-zUwz@{ay1$d}C18~ONUTuB7Y>%AYZ zG*QgM&_nyVq!X$9LZF?2uj3b&bOvmWCbc(l*)Slr=6eAz`mo2&g73U@w z_3&XO3KFF2{Uo=)nZTl12Llpce2@l_mPgP4<20kFI!|9wL0y7Qmf#f>zp-$bJ$aN;KDGOmgAP-~(;bo_gTj3%FMDeyJ5e z|AkJf89mNrkWU8T@v$fx3YyAS3+Ts`Se$2PowNFXw2W?6q9E&u?Zs*^&({Pr#!C#7 zpfc4wRt7P?55+a)%gPH6^9N0|nR{x05jI5srGX{6>#$B5W80cW-Lt}3fk4DeL0>dD zK~;Ybrppa-qxpvQ8{_n%Hd31=9C&nq_ZB^S!eG#t=8{i%l~%@SVjvfjf4ClQr|^oh zC`FR&9IvqqFWj@^@IH=#K;QK5`+p#e8 z9!|VaS$^a?yGNnD2rg@p2P)_AZaG0G<5iid9qoEqFHaDi5S|Z}b=>pV)ms9yVHc)J z!7yo?j{J$ZKH82i9DGcIFtPQT%}Ohc!TH?a zQ}j7tU5591isp}f8tTrq)zW_Ce*?y)SPbQAs~k>-y&$4*Nzm$T0M+2x9qe*iejt~YLxo-v=_}dte;)8`^){cSogQEl zuStpi>wT9XE^WdX-cOSE^0!b=#aq4IQ=UpN8ZlfhW2ZVGXnrXgB=`3VBSxHFbd@TCfIUc z;*@N@*He_b@@~wHXgw1;z(BcUPvd-H>qv@9F%r0Lm~vVIsiZ+G4N0>cohs~_vxFDu zGLW}d@YOfsy&kL(NS=am4Nct;1kGUgCTD%aXs%-LEy6F`@kqPAt`VlNTV&vl$Sctbl| zwG~*zI-Aj*S4L7NjmX;Q4ceU#xy|(fZwtfSATL^rJm#MP5KVs0N*p z#v{uh`NPuI)SiYWn?$*EkqUV)=ep!8qd=(9IoY^?Z!V+c>%)nNtFOfJuA~H!ysW+Y ziW?!k{VCAo&ov-AS-DI_(P772oC^$KE=mMgo|Jt-dSNnt0z{jDJ6;Kfo=Ys<_b)Ux7qxgKm)v16!syJ>`%$pPj$x+GSVfR_s^t5Qrqb zezf)*i!FMzLdF-uE<`OgI~^I39Y3#6L;g&m>#v8En?~0Opo;V#%)ND&7VmYlql}eO zL8I%h3&xuZtV8ml609Rz0Q}ibRw8*yj-JiHQNuVCeu>3Mgi~Mt2R5%OMF+B}_hEeC ze|=6OPo#efQbYyv0`RBytN#xkV-+a?0P^$L*)b&F`;t2@=(Dk^Xe3I6m!aaQr4v)%Pr3e&o+N`s`+0N{iGv{G1#?wNUK^Nc*~{>+4yQ4y0x?0_phSnQh1pWeRV~csP$6HQbqJu=9n;*l;txvj%LlQCu{e)>r4%X<;XJx)Ne3d)2a3UJ__#zNTvR?; z3XJ$XS-%%5wz5{?t~m!S@SnsCzEY(Jd#N3*i|UW1uY-P6Zwp!cJ{%cAqwh>~Lf3H9 zjd8{KvW(uCC_yRzTk=h!71j-Fx4Ck6P5Hq=M875Yl$7{1`}2U%*zBOFt?4RfM;zEk zK8bHLvcrR-gaBxwq1x>&5s!sj`Z9lsQG` z*V3^Ntxd;97ye6(NIl@s52L#^3p!bPDU7H2VkbW6G^;b`e7BRQyJ)uSqcE>`$(_n_ zRMW-&H8Td7W4<>TxjTQddj={ie!Y`m6)I0@QLJ;+v5yMtr$ zA_P5a%gKg*3kZwQ0*E*~n6}W8@ymjg?Y`A(IO6g~(TL&hr!C&Ctp1JfT{&H_$2%=% z1|OQ#e|#C0qy&arKii71>O;+JTGGN2Kb=F%aSsRaMJFd!wc50bAaMNxW5;cxqlP@J z&z5-@UX?Shks^&IA46#7W4Xyh?5P49Qiq)NY2ieO|Mi6UmKPrUJ17;2zn-+?5ig z)eg3DX~8POzuiU9+h)P53Qvjiz211NMUjdFowRKisWL=J`*|F{6!_QT5s29zYFO^S zM8lSP@wwh&b$mbAVswzm=UUJk;Pb1%3aj&-=95o?e}1YDLDNKb1{MSVqW`O>0lM;7 zjX^fEZ@x;zsQ&@@=D=efd_Trh#p8T^ZBH-UKSS-|L!!P!>v?T?*PmL!bIN+pl z4i{b$Qk<4{?;d{URqT4x;l|fo?Cy@!Knr!puOio5 zRxI;zjD)l!`Bh0}9RWmzt8?g?+>$3Ds&aeiogl+Md7g)VgorcZ(KU|7$ha*00BqrF zwc~*$#hbYO)ZgCKBimCPT8N0|s?!E3Ie}kX?usCsm!LKcS7DonN?OM8@s=S_a~nDmN_?SFfeX1uT)u z6D=x$Md@O70yoNs2QFx1$6dDvb?>O#=P=$>}2Z-=e%A(pm3 zG_J8NxyxLP*oNQsS}Z!oe+a)#Y>^I~NfL$_qNvg*thOksoWzU@T8%~<TI|EvDe!8^_E!8>Hcu?LUDv<{zgsO5<8>K$e?v$^7srueAk_R z|KvV3`@=hq5$2(}hSfop+6$WM&ep_*@_Bm3k*m~Q#5KFLiw~S$eTX1k7d_BN9=o~a z*DWF|LSQ^BOLc_cLh3{pl5g1ZI{wMCek4}Wd-v47UE(&OOlmga``7<`crZNP!V>nx zxFNvqi+z#v$IzSWpr8ZrI4o|RUP8~+hG=}TSN?F9r^fAO3@MO+`OED~3kx0oQ5Vj_ z;PgVYmlV*pS$ndxn!B#c(p1u<&zUBRs3fIy^Jn0^EF%m_~A0zNU(2cd;JEvuXI&WZWAJ{!{H> zuO|3VX#$fuUXN>e9Hud{{59+*ID3(o8mF%2iy3dIQHk>Dj_a|Fa}moYWN1;desOUL zOl5eEa?*XY%qc=NpU~8;*Qpj@^yjunOViFdHF*Xd#f5JNO&&Oo6$`K4ph=B~tXga%Kt)S9M!iYOdc__Hl+h@&v%?}W zyv>%M1a~_DtH$9dhx15_?^5oyxkUkT5JdtOEn z9Yzll$yfj3y3OQKXxO$|?L35{f}=_hvYE7a4H5$`3h&9DsKd8!be>ynS$;HXHLH+L zGQSvVl(Q_h@f*D1Ljn%8`fpuPCA2>c#?I7O*XJNC%&-A7PlCIV!!iz{g3-knH(%zF zBI^bh?DmHv8aXgIY_wcz5+Nq~@5H$~Z;=RZ#%nJ`vQ{*f@d3K)h41-*@%n}MYUV^XXtDh7@#IsW)=_)I zqcY=iMBL>Kfi!0bbz=FW#2@g7Iv+BZcDrsx%aPwHjajCaE)0oV__?L>rXmAr)8zWm=onq*F29QKW2{ndT% zB#hWi6OJ$1fWXt>-U*H6MkZmk6%0IoALyb@YE5$;IJ*~BSN+Mz%5&HsUJ(oS(9R7p zEFXu9!4D*@lkNG{r0tyFMOLn@RSwa^?**L%U4(AoU)*%zmZ4P0V4lsEgP??0^)A$< z7&k$Ryji=>@Y5u54mu-jmFL1^kvZnAqYv7&f4u+h`1_v7QpNhg+4)B23uoi*^7Xz*CUV6RfJ)1h3i!^~NhUVQ_~ET;J#SwN&O(1MyKB zMm>k;L6?=B3IMvsrm+5sTJuBbRud>#G;?F(7CQz`wN?dHzvoYdEPCsFL%)EANrHU-X%#viR&pS@u77W$W5(61wV{$0KXzhi{ zQI!u|k`Q!u+>#lvu)0NiKq4@Ue5Higqo^KQZK1isMs62JdY!ltOtkD9rqNKL$rb## zf5eSNIap!;a{q{kdrhf8a^-IV6?Q$aSzhRbvG0>M1@hy?qt3O};eI0nsQgXs+o1km zo+Y~ZZ2f15(a;xSK&k`U71+G+KCl9xI8C7?6P3CbQ4-RD-oMmn}>rxX`9Os%OtM@9w`PtAlX2b0qJ^MS3;HA_D7j@pJXhP1ROlw7=Ww|BKGQZK$<+kZO0VM#nY(noRx`PEvf1w2Gt0TgQZK)xpjZ|GX!pE&Bf zfvSt7xdc3AC;SkxjGm zhZacav8CV?1anT;l{eB7RaPq3(h2HB!}B_LX`r}j@J95=p<8BO<3tv3 z@B0X*JOneof^Y}hnE(*}sfW$qW=d4ouA=Q+)SG4uWE-0+597d07LZc%f(i-o_Wda5 zytVz%$sgoQ??K5DRNl$qyb6StR1hn8e>~Ssm3~}Y zLaO2cZ@>gd)FHe-%F#*oPT{C!LZ5!Q+xVOD1p_Gk)`$S8khK z(oY}!7lX9vhKKEEZ1bsD-S3L# zbEWiZAFS7)MT;E`+2=>mBD7^L7Mirv9S?_+a#wz&ZA`jC=;QHMytatUfkUQb2|=Z=oB7GtXDWqMG_D%0=i! z1iMHCfSCEBtw#eiCK|bDPAARzq&q@?Ct?7B8{~f~5%vMKx+Z5&+6r|&eh!V}zeU`a zHz4N&bSfNdM_stUqbp4j@h*T5cofWwZoYEe-QB-)rkAJkYQ~o$r)Cb%$vn);bE8$K zCHkQ!(RNG?_QCZZ% zHGuCSSS6)9gasCc;Xl+Eo=f{jR|1NTL`w$Q>lbZ~t1$tx>(0;)O_^JKRN)aE~zstDHfpyRE@Ye0EwybJ~w4{T#FSOM` zYJFEsu*Pd4L|JM7K;-U+Jt0QZT#QSSG0T5wOwpADh@k=$SNyosf~#8ne`u(d=$%*w zzHD$yTGu+UWc;5}A5Vm$LabItMAAOh6K8&6OONaD5RQFV+j#gBN3oBu zK!#Y{bJCmr4dzscWdaX=g)|035$_s2oQ30Zt3bipV9wKLxJuY(6A@@x{8;!QXib5n z-KYDgqD5n<9859ACS$yoJOYEg@KN|wTrR7W|C*b0^Z1_(q_kC7ILRxwxw_-=@t zIVM2|KJ_nM(8GFsV2W-ki&)(`P!pFI8XKT1lTA(a(-cu#Gv%(-b0|KpWJrhh&V$5P zT}%j-JQhPu!YNJ()SJ~&e<~UaJl7a19W?P7d?m`pH&?S%XE#@FiOL+FI{UsI67uBh zFJzmYJ+_Pu)1`}Lzpt%hkb=chlwz?@M(e`F9UWUP)4B{M{N;u^8iPMs^1pmz*4LAk zL?A#84Af5%Q~46&CDlGS7m!6Q^~``GV*q^U2enK6=|0wl0vj@7=?tof+&?t6zomOP z--kdA_A( zjdt5fl(?gD*ilYU`jMNAuI&#kl+I;=%jAG`QMHJ#lY#f>DNpPbG-2uhNrxH)?;of^PD8*h?iGTK$%3k3 zzwP?q2Jqr2r4qX7#gh>ObH z;TW_QUz}IIEm!YRu;MkDpoQ zU2SMl92>BKBBqU^WX@IK>mUzLsEBo`H9gx8gs!YJ;y(D#jjS1j(y(1^Mv@{e>aoFF zwJ71_MWR(p;j!wK9DK&|>_2|lhZkn1!*%x%kc~@}z}}syoRe46@+@G2^lQ{Yc8=LW zspyzh#YGmuyK*Z)2rLDFrS4As!qa!}v;bAyk7H^1gU zy+06A80g-l8fuAGUzPNu0_|8i6ickbEcS>OKdzLxO!Nl)36-mk+-iEVZd6UlMgi)_ z3ZgKvmI=5|Ri8U08_1VML`+KiVsoRVbN%l7tk~z6wNTNuROekvY>}iBH!Z! z0}FUV5P=6R7yowV=Ne?snS3p{aU}3*rQ27uNFUFG0(@1Od(N!T1U1T8afRf%W~lo> zvWjVS?m^e|dRua3RW3HX;lKhqb{xgs!kZfRU@S^>ckdNx9+1ZgCi*34-81X&*ML`L zf{C?9fW}tyxhz@fOqAUAn$r;mV+NVIZ-)ZjIvmj>Wf9;@lv(kiLo>8y*tM#Ym@mw}JcRkFRB>oL%Ni?ps$ zraO*}`2gpoZMRNovloRUc{_5!*p7Q+W+Q~363v>g={J=R7L3URp=7#tLU#EXdKroBm6wO442IpBf0YP z{6mwK8gu3_;~P!gI6i<+U`A`E_G5YFAs&qA+1JX6qa_+#(^qz`c87;5qQYtPX#U+Pcz(@YlLIAskfq@uz2!+U*C(xMb`$`Qt#_ckwUOC6&$lt^+1{Cw z?z6kZ%M4TsuNvdx=!GcR3P*PNo+W1!XK13hdoKr==bRBUMA$6Ce%YzG>=#DxHz@d* zQ?uobfG43n;x(>2xHzFuapD;@WZkK+QNxf`>#cfV^9u=hAtW|ITtBPrIPx+THSh|o z;FDT6(`Y%AWOfel*c*y}K56{x5nEC)J8M14V6dWIxY%0KF{xD3Vl&KsmyOe@2D3I8 zrIQKje%ku>9pzIgGkc7J4QJb^$`D7}ree)s&rPNax{A|Je@&jfH4mv@aNX4)1&Xj@ z!&5>+znA5GRfqn!M8~>f&zpYW2G@IS|M(Y}O;=ztX<^arht^W?TzeWHPKGG zrd5UCH|NG*gDF|Niqi~#5qOj3(BU`c;Zx_u0rt5%tdJNQLi1vHgD_3w+)PG;C1*v@M zXaN8Z&4x4lxxnQP*%zNQ!T{6yF!|AX<|dqq@_}ILP5*78GP&bh<60>{5NGW1w%O`l znKUBD=2j;mv=y9rYE?|Cs}cu7_)0BW-VgV|!tcG~YseU3Btm6L< zpN{haO~hGPtO$*1Ia>n?C(N^=gqg%CA=J@TG!IhV4ulzAJKumug5uMydEp<$7w@I4pElHv+K-+pt0_f8t7I>$QxTG$u)&m4uErBHpA@*zZG zj&YTtyKxq#397icYN;96{>=kdV!E)o>Vd^@Le0RZ(>A!kwCx^cHTP7G(`<&;*#YTX zd5<@?d6sK<3l+d4^V zTht;kbvgTd%HH?+6id7)P7&NFSGsHatK!Jalp?zrL1qs`-JV4pwerWfd*Hqgn(TeC z&})_!-B()aVg!|BPPpNiXmD|3u!XMD>V4^6%!$QjMp?es;w_M<1Mt1A`rp!68)%b@ z8~7Gi*V=l%589O=+9e+zOqMe%W-(`GgZ29Km^|NJHr3|i04i04(S4&9*iN}J^9D;Tcb^kTnuzxfX_pmZrh zB8>P5j4hRTja5}OE$g7z`e^vEJKtd6AL5WK&>xc_TuZVLa?(}gHXn+Yjh3Hk@!KkR zV^1dp;+N;g78+zgz$Q9mZRDE69-T-*2W|Hz+{)H#Tx+HG-dn=KH3U#q47Lr(*3IM} z3*=!FaN3~>3P@9z|1iE>G|gfDD}%p*k$&?&(b@qkXl*81M? { )} {getNodeConfigApi.data && getNodeConfigApi.data.length > 0 && ( - + )} diff --git a/packages/ui/src/ui-component/json/SelectVariable.js b/packages/ui/src/ui-component/json/SelectVariable.js index 1b891ed11..7a482baef 100644 --- a/packages/ui/src/ui-component/json/SelectVariable.js +++ b/packages/ui/src/ui-component/json/SelectVariable.js @@ -2,14 +2,15 @@ import { useSelector } from 'react-redux' import PropTypes from 'prop-types' import { Box, List, ListItemButton, ListItem, ListItemAvatar, ListItemText, Typography, Stack } from '@mui/material' import PerfectScrollbar from 'react-perfect-scrollbar' - +import robotPNG from 'assets/images/robot.png' +import chatPNG from 'assets/images/chathistory.png' import { baseURL } from 'store/constant' const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectAndReturnVal }) => { const customization = useSelector((state) => state.customization) - const onSelectOutputResponseClick = (node, isUserQuestion = false) => { - let variablePath = isUserQuestion ? `question` : `${node.id}.data.instance` + const onSelectOutputResponseClick = (node, prefix) => { + let variablePath = node ? `${node.id}.data.instance` : prefix const newInput = `{{${variablePath}}}` onSelectAndReturnVal(newInput) } @@ -32,7 +33,7 @@ const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectA mb: 1 }} disabled={disabled} - onClick={() => onSelectOutputResponseClick(null, true)} + onClick={() => onSelectOutputResponseClick(null, 'question')} > @@ -52,13 +53,52 @@ const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectA objectFit: 'contain' }} alt='AI' - src='https://raw.githubusercontent.com/zahidkhawaja/langchain-chat-nextjs/main/public/parroticon.png' + src={robotPNG} /> + onSelectOutputResponseClick(null, 'chat_history')} + > + + +
+ chatHistory +
+
+ +
+
{availableNodesForVariable && availableNodesForVariable.length > 0 && availableNodesForVariable.map((node, index) => {