mirror of
https://github.com/farcasclaudiu/Flowise.git
synced 2026-06-28 17:01:00 +03:00
Merge pull request #611 from FlowiseAI/bugfix/StartsWith-Undefined
Bugfix/StartsWith Undefined
This commit is contained in:
+45
-13
@@ -1,9 +1,9 @@
|
||||
import { BaseLanguageModel } from 'langchain/base_language'
|
||||
import { ICommonObject, IMessage, INode, INodeData, INodeParams } from '../../../src/Interface'
|
||||
import { getBaseClasses } from '../../../src/utils'
|
||||
import { ConversationalRetrievalQAChain } from 'langchain/chains'
|
||||
import { ConversationalRetrievalQAChain, QAChainParams } from 'langchain/chains'
|
||||
import { AIMessage, BaseRetriever, HumanMessage } from 'langchain/schema'
|
||||
import { BaseChatMemory, BufferMemory, ChatMessageHistory } from 'langchain/memory'
|
||||
import { BaseChatMemory, BufferMemory, ChatMessageHistory, BufferMemoryInput } from 'langchain/memory'
|
||||
import { PromptTemplate } from 'langchain/prompts'
|
||||
import { ConsoleCallbackHandler, CustomChainHandler } from '../../../src/handler'
|
||||
import {
|
||||
@@ -11,7 +11,9 @@ import {
|
||||
default_qa_template,
|
||||
qa_template,
|
||||
map_reduce_template,
|
||||
CUSTOM_QUESTION_GENERATOR_CHAIN_PROMPT
|
||||
CUSTOM_QUESTION_GENERATOR_CHAIN_PROMPT,
|
||||
refine_question_template,
|
||||
refine_template
|
||||
} from './prompts'
|
||||
|
||||
class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
@@ -46,9 +48,9 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
{
|
||||
label: 'Memory',
|
||||
name: 'memory',
|
||||
type: 'DynamoDBChatMemory | RedisBackedChatMemory | ZepMemory',
|
||||
type: 'BaseMemory',
|
||||
optional: true,
|
||||
description: 'If no memory connected, default BufferMemory will be used'
|
||||
description: 'If left empty, a default BufferMemory will be used'
|
||||
},
|
||||
{
|
||||
label: 'Return Source Documents',
|
||||
@@ -115,28 +117,43 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
combinePrompt: PromptTemplate.fromTemplate(
|
||||
systemMessagePrompt ? `${systemMessagePrompt}\n${map_reduce_template}` : default_map_reduce_template
|
||||
)
|
||||
}
|
||||
} as QAChainParams
|
||||
} else if (chainOption === 'refine') {
|
||||
// TODO: Add custom system message
|
||||
const qprompt = new PromptTemplate({
|
||||
inputVariables: ['context', 'question'],
|
||||
template: refine_question_template(systemMessagePrompt)
|
||||
})
|
||||
const rprompt = new PromptTemplate({
|
||||
inputVariables: ['context', 'question', 'existing_answer'],
|
||||
template: refine_template
|
||||
})
|
||||
obj.qaChainOptions = {
|
||||
type: 'refine',
|
||||
questionPrompt: qprompt,
|
||||
refinePrompt: rprompt
|
||||
} as QAChainParams
|
||||
} else {
|
||||
obj.qaChainOptions = {
|
||||
type: 'stuff',
|
||||
prompt: PromptTemplate.fromTemplate(systemMessagePrompt ? `${systemMessagePrompt}\n${qa_template}` : default_qa_template)
|
||||
}
|
||||
} as QAChainParams
|
||||
}
|
||||
|
||||
if (memory) {
|
||||
memory.inputKey = 'question'
|
||||
memory.outputKey = 'text'
|
||||
memory.memoryKey = 'chat_history'
|
||||
if (chainOption === 'refine') memory.outputKey = 'output_text'
|
||||
else memory.outputKey = 'text'
|
||||
obj.memory = memory
|
||||
} else {
|
||||
obj.memory = new BufferMemory({
|
||||
const fields: BufferMemoryInput = {
|
||||
memoryKey: 'chat_history',
|
||||
inputKey: 'question',
|
||||
outputKey: 'text',
|
||||
returnMessages: true
|
||||
})
|
||||
}
|
||||
if (chainOption === 'refine') fields.outputKey = 'output_text'
|
||||
else fields.outputKey = 'text'
|
||||
obj.memory = new BufferMemory(fields)
|
||||
}
|
||||
|
||||
const chain = ConversationalRetrievalQAChain.fromLLM(model, vectorStoreRetriever, obj)
|
||||
@@ -147,6 +164,7 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
const chain = nodeData.instance as ConversationalRetrievalQAChain
|
||||
const returnSourceDocuments = nodeData.inputs?.returnSourceDocuments as boolean
|
||||
const memory = nodeData.inputs?.memory
|
||||
const chainOption = nodeData.inputs?.chainOption as string
|
||||
|
||||
let model = nodeData.inputs?.model
|
||||
|
||||
@@ -176,8 +194,22 @@ class ConversationalRetrievalQAChain_Chains implements INode {
|
||||
const loggerHandler = new ConsoleCallbackHandler(options.logger)
|
||||
|
||||
if (options.socketIO && options.socketIOClientId) {
|
||||
const handler = new CustomChainHandler(options.socketIO, options.socketIOClientId, undefined, returnSourceDocuments)
|
||||
const handler = new CustomChainHandler(
|
||||
options.socketIO,
|
||||
options.socketIOClientId,
|
||||
chainOption === 'refine' ? 4 : undefined,
|
||||
returnSourceDocuments
|
||||
)
|
||||
const res = await chain.call(obj, [loggerHandler, handler])
|
||||
if (chainOption === 'refine') {
|
||||
if (res.output_text && res.sourceDocuments) {
|
||||
return {
|
||||
text: res.output_text,
|
||||
sourceDocuments: res.sourceDocuments
|
||||
}
|
||||
}
|
||||
return res?.output_text
|
||||
}
|
||||
if (res.text && res.sourceDocuments) return res
|
||||
return res?.text
|
||||
} else {
|
||||
|
||||
@@ -27,7 +27,36 @@ export const map_reduce_template = `Given the following extracted parts of a lon
|
||||
Question: {question}
|
||||
Helpful Answer:`
|
||||
|
||||
export const CUSTOM_QUESTION_GENERATOR_CHAIN_PROMPT = `Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language. include it in the standalone question.
|
||||
export const refine_question_template = (sysPrompt?: string) => {
|
||||
let returnPrompt = ''
|
||||
if (sysPrompt)
|
||||
returnPrompt = `Context information is below.
|
||||
---------------------
|
||||
{context}
|
||||
---------------------
|
||||
Given the context information and not prior knowledge, ${sysPrompt}
|
||||
Answer the question: {question}.
|
||||
Answer:`
|
||||
if (!sysPrompt)
|
||||
returnPrompt = `Context information is below.
|
||||
---------------------
|
||||
{context}
|
||||
---------------------
|
||||
Given the context information and not prior knowledge, answer the question: {question}.
|
||||
Answer:`
|
||||
return returnPrompt
|
||||
}
|
||||
|
||||
export const refine_template = `The original question is as follows: {question}
|
||||
We have provided an existing answer: {existing_answer}
|
||||
We have the opportunity to refine the existing answer (only if needed) with some more context below.
|
||||
------------
|
||||
{context}
|
||||
------------
|
||||
Given the new context, refine the original answer to better answer the question.
|
||||
If you can't find answer from the context, return the original answer.`
|
||||
|
||||
export const CUSTOM_QUESTION_GENERATOR_CHAIN_PROMPT = `Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, answer in the same language as the follow up question. include it in the standalone question.
|
||||
|
||||
Chat History:
|
||||
{chat_history}
|
||||
|
||||
@@ -58,70 +58,6 @@
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 300,
|
||||
"height": 392,
|
||||
"id": "textFile_1",
|
||||
"position": {
|
||||
"x": 810.6456923854021,
|
||||
"y": 61.45989039390216
|
||||
},
|
||||
"type": "customNode",
|
||||
"data": {
|
||||
"id": "textFile_1",
|
||||
"label": "Text File",
|
||||
"name": "textFile",
|
||||
"type": "Document",
|
||||
"baseClasses": ["Document"],
|
||||
"category": "Document Loaders",
|
||||
"description": "Load data from text files",
|
||||
"inputParams": [
|
||||
{
|
||||
"label": "Txt File",
|
||||
"name": "txtFile",
|
||||
"type": "file",
|
||||
"fileType": ".txt",
|
||||
"id": "textFile_1-input-txtFile-file"
|
||||
},
|
||||
{
|
||||
"label": "Metadata",
|
||||
"name": "metadata",
|
||||
"type": "json",
|
||||
"optional": true,
|
||||
"additionalParams": true,
|
||||
"id": "textFile_1-input-metadata-json"
|
||||
}
|
||||
],
|
||||
"inputAnchors": [
|
||||
{
|
||||
"label": "Text Splitter",
|
||||
"name": "textSplitter",
|
||||
"type": "TextSplitter",
|
||||
"optional": true,
|
||||
"id": "textFile_1-input-textSplitter-TextSplitter"
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"textSplitter": "{{recursiveCharacterTextSplitter_1.data.instance}}"
|
||||
},
|
||||
"outputAnchors": [
|
||||
{
|
||||
"id": "textFile_1-output-textFile-Document",
|
||||
"name": "textFile",
|
||||
"label": "Document",
|
||||
"type": "Document"
|
||||
}
|
||||
],
|
||||
"outputs": {},
|
||||
"selected": false
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": 810.6456923854021,
|
||||
"y": 61.45989039390216
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 300,
|
||||
"height": 330,
|
||||
@@ -203,118 +139,6 @@
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 300,
|
||||
"height": 702,
|
||||
"id": "pineconeUpsert_1",
|
||||
"position": {
|
||||
"x": 1201.3427203075867,
|
||||
"y": 545.1800202023215
|
||||
},
|
||||
"type": "customNode",
|
||||
"data": {
|
||||
"id": "pineconeUpsert_1",
|
||||
"label": "Pinecone Upsert Document",
|
||||
"name": "pineconeUpsert",
|
||||
"type": "Pinecone",
|
||||
"baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"],
|
||||
"category": "Vector Stores",
|
||||
"description": "Upsert documents to Pinecone",
|
||||
"inputParams": [
|
||||
{
|
||||
"label": "Pinecone Api Key",
|
||||
"name": "pineconeApiKey",
|
||||
"type": "password",
|
||||
"id": "pineconeUpsert_1-input-pineconeApiKey-password"
|
||||
},
|
||||
{
|
||||
"label": "Pinecone Environment",
|
||||
"name": "pineconeEnv",
|
||||
"type": "string",
|
||||
"id": "pineconeUpsert_1-input-pineconeEnv-string"
|
||||
},
|
||||
{
|
||||
"label": "Pinecone Index",
|
||||
"name": "pineconeIndex",
|
||||
"type": "string",
|
||||
"id": "pineconeUpsert_1-input-pineconeIndex-string"
|
||||
},
|
||||
{
|
||||
"label": "Pinecone Namespace",
|
||||
"name": "pineconeNamespace",
|
||||
"type": "string",
|
||||
"placeholder": "my-first-namespace",
|
||||
"optional": true,
|
||||
"additionalParams": true,
|
||||
"id": "pineconeUpsert_1-input-pineconeNamespace-string"
|
||||
},
|
||||
{
|
||||
"label": "Top K",
|
||||
"name": "topK",
|
||||
"description": "Number of top results to fetch. Default to 4",
|
||||
"placeholder": "4",
|
||||
"type": "number",
|
||||
"additionalParams": true,
|
||||
"optional": true,
|
||||
"id": "pineconeUpsert_1-input-topK-number"
|
||||
}
|
||||
],
|
||||
"inputAnchors": [
|
||||
{
|
||||
"label": "Document",
|
||||
"name": "document",
|
||||
"type": "Document",
|
||||
"list": true,
|
||||
"id": "pineconeUpsert_1-input-document-Document"
|
||||
},
|
||||
{
|
||||
"label": "Embeddings",
|
||||
"name": "embeddings",
|
||||
"type": "Embeddings",
|
||||
"id": "pineconeUpsert_1-input-embeddings-Embeddings"
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"document": ["{{textFile_1.data.instance}}"],
|
||||
"embeddings": "{{openAIEmbeddings_1.data.instance}}",
|
||||
"pineconeEnv": "us-west4-gcp",
|
||||
"pineconeIndex": "myindex",
|
||||
"pineconeNamespace": "mynamespace"
|
||||
},
|
||||
"outputAnchors": [
|
||||
{
|
||||
"name": "output",
|
||||
"label": "Output",
|
||||
"type": "options",
|
||||
"options": [
|
||||
{
|
||||
"id": "pineconeUpsert_1-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever",
|
||||
"name": "retriever",
|
||||
"label": "Pinecone Retriever",
|
||||
"type": "Pinecone | VectorStoreRetriever | BaseRetriever"
|
||||
},
|
||||
{
|
||||
"id": "pineconeUpsert_1-output-vectorStore-Pinecone|VectorStore",
|
||||
"name": "vectorStore",
|
||||
"label": "Pinecone Vector Store",
|
||||
"type": "Pinecone | VectorStore"
|
||||
}
|
||||
],
|
||||
"default": "retriever"
|
||||
}
|
||||
],
|
||||
"outputs": {
|
||||
"output": "retriever"
|
||||
},
|
||||
"selected": false
|
||||
},
|
||||
"selected": false,
|
||||
"dragging": false,
|
||||
"positionAbsolute": {
|
||||
"x": 1201.3427203075867,
|
||||
"y": 545.1800202023215
|
||||
}
|
||||
},
|
||||
{
|
||||
"width": 300,
|
||||
"height": 524,
|
||||
@@ -468,7 +292,7 @@
|
||||
},
|
||||
{
|
||||
"width": 300,
|
||||
"height": 280,
|
||||
"height": 480,
|
||||
"id": "conversationalRetrievalQAChain_0",
|
||||
"position": {
|
||||
"x": 1627.1855024401737,
|
||||
@@ -551,7 +375,7 @@
|
||||
],
|
||||
"inputs": {
|
||||
"model": "{{chatOpenAI_0.data.instance}}",
|
||||
"vectorStoreRetriever": "{{pineconeUpsert_1.data.instance}}"
|
||||
"vectorStoreRetriever": "{{pineconeUpsert_0.data.instance}}"
|
||||
},
|
||||
"outputAnchors": [
|
||||
{
|
||||
@@ -570,42 +394,186 @@
|
||||
"y": 394.42287890442145
|
||||
},
|
||||
"dragging": false
|
||||
},
|
||||
{
|
||||
"width": 300,
|
||||
"height": 411,
|
||||
"id": "textFile_0",
|
||||
"position": {
|
||||
"x": 806.1207502345,
|
||||
"y": 98.75458062792087
|
||||
},
|
||||
"type": "customNode",
|
||||
"data": {
|
||||
"id": "textFile_0",
|
||||
"label": "Text File",
|
||||
"name": "textFile",
|
||||
"type": "Document",
|
||||
"baseClasses": ["Document"],
|
||||
"category": "Document Loaders",
|
||||
"description": "Load data from text files",
|
||||
"inputParams": [
|
||||
{
|
||||
"label": "Txt File",
|
||||
"name": "txtFile",
|
||||
"type": "file",
|
||||
"fileType": ".txt",
|
||||
"id": "textFile_0-input-txtFile-file"
|
||||
},
|
||||
{
|
||||
"label": "Metadata",
|
||||
"name": "metadata",
|
||||
"type": "json",
|
||||
"optional": true,
|
||||
"additionalParams": true,
|
||||
"id": "textFile_0-input-metadata-json"
|
||||
}
|
||||
],
|
||||
"inputAnchors": [
|
||||
{
|
||||
"label": "Text Splitter",
|
||||
"name": "textSplitter",
|
||||
"type": "TextSplitter",
|
||||
"optional": true,
|
||||
"id": "textFile_0-input-textSplitter-TextSplitter"
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"textSplitter": "{{recursiveCharacterTextSplitter_1.data.instance}}",
|
||||
"metadata": ""
|
||||
},
|
||||
"outputAnchors": [
|
||||
{
|
||||
"id": "textFile_0-output-textFile-Document",
|
||||
"name": "textFile",
|
||||
"label": "Document",
|
||||
"type": "Document"
|
||||
}
|
||||
],
|
||||
"outputs": {},
|
||||
"selected": false
|
||||
},
|
||||
"positionAbsolute": {
|
||||
"x": 806.1207502345,
|
||||
"y": 98.75458062792087
|
||||
},
|
||||
"selected": false
|
||||
},
|
||||
{
|
||||
"width": 300,
|
||||
"height": 655,
|
||||
"id": "pineconeUpsert_0",
|
||||
"position": {
|
||||
"x": 1206.7979889462367,
|
||||
"y": 526.4616330622748
|
||||
},
|
||||
"type": "customNode",
|
||||
"data": {
|
||||
"id": "pineconeUpsert_0",
|
||||
"label": "Pinecone Upsert Document",
|
||||
"name": "pineconeUpsert",
|
||||
"type": "Pinecone",
|
||||
"baseClasses": ["Pinecone", "VectorStoreRetriever", "BaseRetriever"],
|
||||
"category": "Vector Stores",
|
||||
"description": "Upsert documents to Pinecone",
|
||||
"inputParams": [
|
||||
{
|
||||
"label": "Pinecone Api Key",
|
||||
"name": "pineconeApiKey",
|
||||
"type": "password",
|
||||
"id": "pineconeUpsert_0-input-pineconeApiKey-password"
|
||||
},
|
||||
{
|
||||
"label": "Pinecone Environment",
|
||||
"name": "pineconeEnv",
|
||||
"type": "string",
|
||||
"id": "pineconeUpsert_0-input-pineconeEnv-string"
|
||||
},
|
||||
{
|
||||
"label": "Pinecone Index",
|
||||
"name": "pineconeIndex",
|
||||
"type": "string",
|
||||
"id": "pineconeUpsert_0-input-pineconeIndex-string"
|
||||
},
|
||||
{
|
||||
"label": "Pinecone Namespace",
|
||||
"name": "pineconeNamespace",
|
||||
"type": "string",
|
||||
"placeholder": "my-first-namespace",
|
||||
"additionalParams": true,
|
||||
"optional": true,
|
||||
"id": "pineconeUpsert_0-input-pineconeNamespace-string"
|
||||
},
|
||||
{
|
||||
"label": "Top K",
|
||||
"name": "topK",
|
||||
"description": "Number of top results to fetch. Default to 4",
|
||||
"placeholder": "4",
|
||||
"type": "number",
|
||||
"additionalParams": true,
|
||||
"optional": true,
|
||||
"id": "pineconeUpsert_0-input-topK-number"
|
||||
}
|
||||
],
|
||||
"inputAnchors": [
|
||||
{
|
||||
"label": "Document",
|
||||
"name": "document",
|
||||
"type": "Document",
|
||||
"list": true,
|
||||
"id": "pineconeUpsert_0-input-document-Document"
|
||||
},
|
||||
{
|
||||
"label": "Embeddings",
|
||||
"name": "embeddings",
|
||||
"type": "Embeddings",
|
||||
"id": "pineconeUpsert_0-input-embeddings-Embeddings"
|
||||
}
|
||||
],
|
||||
"inputs": {
|
||||
"document": ["{{textFile_0.data.instance}}"],
|
||||
"embeddings": "{{openAIEmbeddings_1.data.instance}}",
|
||||
"pineconeEnv": "",
|
||||
"pineconeIndex": "",
|
||||
"pineconeNamespace": "",
|
||||
"topK": ""
|
||||
},
|
||||
"outputAnchors": [
|
||||
{
|
||||
"name": "output",
|
||||
"label": "Output",
|
||||
"type": "options",
|
||||
"options": [
|
||||
{
|
||||
"id": "pineconeUpsert_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever",
|
||||
"name": "retriever",
|
||||
"label": "Pinecone Retriever",
|
||||
"type": "Pinecone | VectorStoreRetriever | BaseRetriever"
|
||||
},
|
||||
{
|
||||
"id": "pineconeUpsert_0-output-vectorStore-Pinecone|VectorStore",
|
||||
"name": "vectorStore",
|
||||
"label": "Pinecone Vector Store",
|
||||
"type": "Pinecone | VectorStore"
|
||||
}
|
||||
],
|
||||
"default": "retriever"
|
||||
}
|
||||
],
|
||||
"outputs": {
|
||||
"output": "retriever"
|
||||
},
|
||||
"selected": false
|
||||
},
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": 1206.7979889462367,
|
||||
"y": 526.4616330622748
|
||||
},
|
||||
"dragging": false
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"source": "openAIEmbeddings_1",
|
||||
"sourceHandle": "openAIEmbeddings_1-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings",
|
||||
"target": "pineconeUpsert_1",
|
||||
"targetHandle": "pineconeUpsert_1-input-embeddings-Embeddings",
|
||||
"type": "buttonedge",
|
||||
"id": "openAIEmbeddings_1-openAIEmbeddings_1-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings-pineconeUpsert_1-pineconeUpsert_1-input-embeddings-Embeddings",
|
||||
"data": {
|
||||
"label": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "textFile_1",
|
||||
"sourceHandle": "textFile_1-output-textFile-Document",
|
||||
"target": "pineconeUpsert_1",
|
||||
"targetHandle": "pineconeUpsert_1-input-document-Document",
|
||||
"type": "buttonedge",
|
||||
"id": "textFile_1-textFile_1-output-textFile-Document-pineconeUpsert_1-pineconeUpsert_1-input-document-Document",
|
||||
"data": {
|
||||
"label": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "recursiveCharacterTextSplitter_1",
|
||||
"sourceHandle": "recursiveCharacterTextSplitter_1-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter",
|
||||
"target": "textFile_1",
|
||||
"targetHandle": "textFile_1-input-textSplitter-TextSplitter",
|
||||
"type": "buttonedge",
|
||||
"id": "recursiveCharacterTextSplitter_1-recursiveCharacterTextSplitter_1-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter-textFile_1-textFile_1-input-textSplitter-TextSplitter",
|
||||
"data": {
|
||||
"label": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "chatOpenAI_0",
|
||||
"sourceHandle": "chatOpenAI_0-output-chatOpenAI-ChatOpenAI|BaseChatModel|BaseLanguageModel|BaseLangChain",
|
||||
@@ -618,12 +586,45 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "pineconeUpsert_1",
|
||||
"sourceHandle": "pineconeUpsert_1-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever",
|
||||
"source": "recursiveCharacterTextSplitter_1",
|
||||
"sourceHandle": "recursiveCharacterTextSplitter_1-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter",
|
||||
"target": "textFile_0",
|
||||
"targetHandle": "textFile_0-input-textSplitter-TextSplitter",
|
||||
"type": "buttonedge",
|
||||
"id": "recursiveCharacterTextSplitter_1-recursiveCharacterTextSplitter_1-output-recursiveCharacterTextSplitter-RecursiveCharacterTextSplitter|TextSplitter-textFile_0-textFile_0-input-textSplitter-TextSplitter",
|
||||
"data": {
|
||||
"label": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "textFile_0",
|
||||
"sourceHandle": "textFile_0-output-textFile-Document",
|
||||
"target": "pineconeUpsert_0",
|
||||
"targetHandle": "pineconeUpsert_0-input-document-Document",
|
||||
"type": "buttonedge",
|
||||
"id": "textFile_0-textFile_0-output-textFile-Document-pineconeUpsert_0-pineconeUpsert_0-input-document-Document",
|
||||
"data": {
|
||||
"label": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "openAIEmbeddings_1",
|
||||
"sourceHandle": "openAIEmbeddings_1-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings",
|
||||
"target": "pineconeUpsert_0",
|
||||
"targetHandle": "pineconeUpsert_0-input-embeddings-Embeddings",
|
||||
"type": "buttonedge",
|
||||
"id": "openAIEmbeddings_1-openAIEmbeddings_1-output-openAIEmbeddings-OpenAIEmbeddings|Embeddings-pineconeUpsert_0-pineconeUpsert_0-input-embeddings-Embeddings",
|
||||
"data": {
|
||||
"label": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"source": "pineconeUpsert_0",
|
||||
"sourceHandle": "pineconeUpsert_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever",
|
||||
"target": "conversationalRetrievalQAChain_0",
|
||||
"targetHandle": "conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever",
|
||||
"type": "buttonedge",
|
||||
"id": "pineconeUpsert_1-pineconeUpsert_1-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever",
|
||||
"id": "pineconeUpsert_0-pineconeUpsert_0-output-retriever-Pinecone|VectorStoreRetriever|BaseRetriever-conversationalRetrievalQAChain_0-conversationalRetrievalQAChain_0-input-vectorStoreRetriever-BaseRetriever",
|
||||
"data": {
|
||||
"label": ""
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import path from 'path'
|
||||
import { IChildProcessMessage, IReactFlowNode, IReactFlowObject, IRunChatflowMessageValue, INodeData } from './Interface'
|
||||
import { buildLangchain, constructGraphs, getEndingNode, getStartingNodes, getUserHome, resolveVariables } from './utils'
|
||||
import {
|
||||
buildLangchain,
|
||||
constructGraphs,
|
||||
getEndingNode,
|
||||
getStartingNodes,
|
||||
getUserHome,
|
||||
replaceInputsWithConfig,
|
||||
resolveVariables
|
||||
} from './utils'
|
||||
import { DataSource } from 'typeorm'
|
||||
import { ChatFlow } from './entity/ChatFlow'
|
||||
import { ChatMessage } from './entity/ChatMessage'
|
||||
@@ -109,6 +117,8 @@ export class ChildProcess {
|
||||
return
|
||||
}
|
||||
|
||||
if (incomingInput.overrideConfig)
|
||||
nodeToExecute.data = replaceInputsWithConfig(nodeToExecute.data, incomingInput.overrideConfig)
|
||||
const reactFlowNodeData: INodeData = resolveVariables(nodeToExecute.data, reactFlowNodes, incomingInput.question)
|
||||
nodeToExecuteData = reactFlowNodeData
|
||||
|
||||
|
||||
@@ -40,7 +40,8 @@ import {
|
||||
isVectorStoreFaiss,
|
||||
databaseEntities,
|
||||
getApiKey,
|
||||
clearSessionMemory
|
||||
clearSessionMemory,
|
||||
replaceInputsWithConfig
|
||||
} from './utils'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { getDataSource } from './DataSource'
|
||||
@@ -819,6 +820,8 @@ export class App {
|
||||
const nodeToExecute = reactFlowNodes.find((node: IReactFlowNode) => node.id === endingNodeId)
|
||||
if (!nodeToExecute) return res.status(404).send(`Node ${endingNodeId} not found`)
|
||||
|
||||
if (incomingInput.overrideConfig)
|
||||
nodeToExecute.data = replaceInputsWithConfig(nodeToExecute.data, incomingInput.overrideConfig)
|
||||
const reactFlowNodeData: INodeData = resolveVariables(nodeToExecute.data, reactFlowNodes, incomingInput.question)
|
||||
nodeToExecuteData = reactFlowNodeData
|
||||
|
||||
|
||||
@@ -428,9 +428,12 @@ export const replaceInputsWithConfig = (flowNodeData: INodeData, overrideConfig:
|
||||
const types = 'inputs'
|
||||
|
||||
const getParamValues = (paramsObj: ICommonObject) => {
|
||||
for (const key in paramsObj) {
|
||||
const paramValue: string = paramsObj[key]
|
||||
paramsObj[key] = overrideConfig[key] ?? paramValue
|
||||
for (const config in overrideConfig) {
|
||||
let paramValue = overrideConfig[config] ?? paramsObj[config]
|
||||
// Check if boolean
|
||||
if (paramValue === 'true') paramValue = true
|
||||
else if (paramValue === 'false') paramValue = false
|
||||
paramsObj[config] = paramValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,8 +90,8 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
||||
}
|
||||
|
||||
const onAPIDialogClick = () => {
|
||||
// If file type is file, isFormDataRequired = true
|
||||
let isFormDataRequired = false
|
||||
|
||||
try {
|
||||
const flowData = JSON.parse(chatflow.flowData)
|
||||
const nodes = flowData.nodes
|
||||
@@ -105,11 +105,27 @@ const CanvasHeader = ({ chatflow, handleSaveFlow, handleDeleteFlow, handleLoadFl
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
// If sessionId memory, isSessionMemory = true
|
||||
let isSessionMemory = false
|
||||
try {
|
||||
const flowData = JSON.parse(chatflow.flowData)
|
||||
const nodes = flowData.nodes
|
||||
for (const node of nodes) {
|
||||
if (node.data.inputParams.find((param) => param.name === 'sessionId')) {
|
||||
isSessionMemory = true
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
setAPIDialogProps({
|
||||
title: 'Embed in website or use as API',
|
||||
chatflowid: chatflow.id,
|
||||
chatflowApiKeyId: chatflow.apikeyid,
|
||||
isFormDataRequired
|
||||
isFormDataRequired,
|
||||
isSessionMemory
|
||||
})
|
||||
setAPIDialogOpen(true)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ const ChatbotFull = () => {
|
||||
const [loginDialogOpen, setLoginDialogOpen] = useState(false)
|
||||
const [loginDialogProps, setLoginDialogProps] = useState({})
|
||||
const [isLoading, setLoading] = useState(true)
|
||||
const [chatbotOverrideConfig, setChatbotOverrideConfig] = useState({})
|
||||
|
||||
const getSpecificChatflowFromPublicApi = useApi(chatflowsApi.getSpecificChatflowFromPublicEndpoint)
|
||||
const getSpecificChatflowApi = useApi(chatflowsApi.getSpecificChatflow)
|
||||
@@ -77,10 +78,19 @@ const ChatbotFull = () => {
|
||||
setChatflow(chatflowData)
|
||||
if (chatflowData.chatbotConfig) {
|
||||
try {
|
||||
setChatbotTheme(JSON.parse(chatflowData.chatbotConfig))
|
||||
const parsedConfig = JSON.parse(chatflowData.chatbotConfig)
|
||||
setChatbotTheme(parsedConfig)
|
||||
if (parsedConfig.overrideConfig) {
|
||||
// Generate new sessionId
|
||||
if (parsedConfig.overrideConfig.generateNewSession) {
|
||||
parsedConfig.overrideConfig.sessionId = Date.now().toString()
|
||||
}
|
||||
setChatbotOverrideConfig(parsedConfig.overrideConfig)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
setChatbotTheme({})
|
||||
setChatbotOverrideConfig({})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -97,7 +107,12 @@ const ChatbotFull = () => {
|
||||
{!chatflow || chatflow.apikeyid ? (
|
||||
<p>Invalid Chatbot</p>
|
||||
) : (
|
||||
<FullPageChat chatflowid={chatflow.id} apiHost={baseURL} theme={{ chatWindow: chatbotTheme }} />
|
||||
<FullPageChat
|
||||
chatflowid={chatflow.id}
|
||||
apiHost={baseURL}
|
||||
chatflowConfig={chatbotOverrideConfig}
|
||||
theme={{ chatWindow: chatbotTheme }}
|
||||
/>
|
||||
)}
|
||||
<LoginDialog show={loginDialogOpen} dialogProps={loginDialogProps} onConfirm={onLoginClick} />
|
||||
</>
|
||||
|
||||
@@ -612,7 +612,9 @@ query({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{codeLang === 'Share Chatbot' && !chatflowApiKeyId && <ShareChatbot />}
|
||||
{codeLang === 'Share Chatbot' && !chatflowApiKeyId && (
|
||||
<ShareChatbot isSessionMemory={dialogProps.isSessionMemory} />
|
||||
)}
|
||||
</TabPanel>
|
||||
))}
|
||||
</DialogContent>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useState } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions'
|
||||
import { SketchPicker } from 'react-color'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import { Box, Typography, Button, Switch, OutlinedInput, Popover, Stack, IconButton } from '@mui/material'
|
||||
import { useTheme } from '@mui/material/styles'
|
||||
@@ -41,7 +42,7 @@ const defaultConfig = {
|
||||
}
|
||||
}
|
||||
|
||||
const ShareChatbot = () => {
|
||||
const ShareChatbot = ({ isSessionMemory }) => {
|
||||
const dispatch = useDispatch()
|
||||
const theme = useTheme()
|
||||
const chatflow = useSelector((state) => state.canvas.chatflow)
|
||||
@@ -54,6 +55,7 @@ const ShareChatbot = () => {
|
||||
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
|
||||
|
||||
const [isPublicChatflow, setChatflowIsPublic] = useState(chatflow.isPublic ?? false)
|
||||
const [generateNewSession, setGenerateNewSession] = useState(chatbotConfig?.generateNewSession ?? false)
|
||||
|
||||
const [welcomeMessage, setWelcomeMessage] = useState(chatbotConfig?.welcomeMessage ?? '')
|
||||
const [backgroundColor, setBackgroundColor] = useState(chatbotConfig?.backgroundColor ?? defaultConfig.backgroundColor)
|
||||
@@ -103,7 +105,8 @@ const ShareChatbot = () => {
|
||||
userMessage: {
|
||||
showAvatar: false
|
||||
},
|
||||
textInput: {}
|
||||
textInput: {},
|
||||
overrideConfig: {}
|
||||
}
|
||||
if (welcomeMessage) obj.welcomeMessage = welcomeMessage
|
||||
if (backgroundColor) obj.backgroundColor = backgroundColor
|
||||
@@ -125,6 +128,8 @@ const ShareChatbot = () => {
|
||||
if (textInputPlaceholder) obj.textInput.placeholder = textInputPlaceholder
|
||||
if (textInputSendButtonColor) obj.textInput.sendButtonColor = textInputSendButtonColor
|
||||
|
||||
if (isSessionMemory) obj.overrideConfig.generateNewSession = generateNewSession
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
@@ -273,6 +278,9 @@ const ShareChatbot = () => {
|
||||
case 'userMessageShowAvatar':
|
||||
setUserMessageShowAvatar(value)
|
||||
break
|
||||
case 'generateNewSession':
|
||||
setGenerateNewSession(value)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -431,6 +439,16 @@ const ShareChatbot = () => {
|
||||
{textField(textInputPlaceholder, 'textInputPlaceholder', 'TextInput Placeholder', 'string', `Type question..`)}
|
||||
{colorField(textInputSendButtonColor, 'textInputSendButtonColor', 'TextIntput Send Button Color')}
|
||||
|
||||
{/*Session Memory Input*/}
|
||||
{isSessionMemory && (
|
||||
<>
|
||||
<Typography variant='h4' sx={{ mb: 1, mt: 2 }}>
|
||||
Session Memory
|
||||
</Typography>
|
||||
{booleanField(generateNewSession, 'generateNewSession', 'Start new session when chatbot link is opened or refreshed')}
|
||||
</>
|
||||
)}
|
||||
|
||||
<StyledButton style={{ marginBottom: 10, marginTop: 10 }} variant='contained' onClick={() => onSave()}>
|
||||
Save Changes
|
||||
</StyledButton>
|
||||
@@ -470,4 +488,8 @@ const ShareChatbot = () => {
|
||||
)
|
||||
}
|
||||
|
||||
ShareChatbot.propTypes = {
|
||||
isSessionMemory: PropTypes.bool
|
||||
}
|
||||
|
||||
export default ShareChatbot
|
||||
|
||||
Reference in New Issue
Block a user