- add refine chain type custom system message

- allow all memory type to conver_re_qa_chain
- fix startsWith undefined where override config file is not passed
- ability to generate new session id when sharing chatbot
This commit is contained in:
Henry
2023-07-24 19:11:39 +01:00
parent e237a5f18c
commit bcf3946efb
10 changed files with 373 additions and 240 deletions
@@ -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": ""
}
+11 -1
View File
@@ -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
+4 -1
View File
@@ -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
+6 -3
View File
@@ -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
}
}
+18 -2
View File
@@ -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)
}
+17 -2
View File
@@ -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