fix chat history

This commit is contained in:
Henry
2023-11-30 16:01:16 +00:00
parent 5a5097e997
commit 4b5f7028e3
12 changed files with 262 additions and 98 deletions
+29 -9
View File
@@ -42,7 +42,8 @@ import {
getEncryptionKey,
checkMemorySessionId,
clearSessionMemoryFromViewMessageDialog,
getUserHome
getUserHome,
replaceChatHistory
} from './utils'
import { cloneDeep, omit, uniqWith, isEqual } from 'lodash'
import { getDataSource } from './DataSource'
@@ -54,7 +55,7 @@ import { Tool } from './database/entities/Tool'
import { Assistant } from './database/entities/Assistant'
import { ChatflowPool } from './ChatflowPool'
import { CachePool } from './CachePool'
import { ICommonObject, INodeOptionsValue } from 'flowise-components'
import { ICommonObject, IMessage, INodeOptionsValue } from 'flowise-components'
import { createRateLimiter, getRateLimiter, initializeRateLimiter } from './utils/rateLimit'
import { addAPIKey, compareKeys, deleteAPIKey, getApiKey, getAPIKeys, updateAPIKey } from './utils/apiKey'
@@ -1267,14 +1268,14 @@ export class App {
* @param {IReactFlowEdge[]} edges
* @returns {string | undefined}
*/
findMemoryLabel(nodes: IReactFlowNode[], edges: IReactFlowEdge[]): string | undefined {
findMemoryLabel(nodes: IReactFlowNode[], edges: IReactFlowEdge[]): IReactFlowNode | undefined {
const memoryNodes = nodes.filter((node) => node.data.category === 'Memory')
const memoryNodeIds = memoryNodes.map((mem) => mem.data.id)
for (const edge of edges) {
if (memoryNodeIds.includes(edge.source)) {
const memoryNode = nodes.find((node) => node.data.id === edge.source)
return memoryNode ? memoryNode.data.label : undefined
return memoryNode
}
}
return undefined
@@ -1395,6 +1396,19 @@ export class App {
isStreamValid = isFlowValidForStream(nodes, endingNodeData)
let chatHistory: IMessage[] | string = incomingInput.history
if (
endingNodeData.inputs?.memory &&
!incomingInput.history &&
(incomingInput.chatId || incomingInput.overrideConfig?.sessionId)
) {
const memoryNodeId = endingNodeData.inputs?.memory.split('.')[0].replace('{{', '')
const memoryNode = nodes.find((node) => node.data.id === memoryNodeId)
if (memoryNode) {
chatHistory = await replaceChatHistory(memoryNode, incomingInput, this.AppDataSource, databaseEntities, logger)
}
}
/*** Get Starting Nodes with Non-Directed Graph ***/
const constructedObj = constructGraphs(nodes, edges, true)
const nonDirectedGraph = constructedObj.graph
@@ -1409,7 +1423,7 @@ export class App {
depthQueue,
this.nodesPool.componentNodes,
incomingInput.question,
incomingInput.history,
chatHistory,
chatId,
chatflowid,
this.AppDataSource,
@@ -1429,7 +1443,7 @@ export class App {
nodeToExecute.data,
reactFlowNodes,
incomingInput.question,
incomingInput.history
chatHistory
)
nodeToExecuteData = reactFlowNodeData
@@ -1446,11 +1460,17 @@ export class App {
let sessionId = undefined
if (nodeToExecuteData.instance) sessionId = checkMemorySessionId(nodeToExecuteData.instance, chatId)
const memoryType = this.findMemoryLabel(nodes, edges)
const memoryNode = this.findMemoryLabel(nodes, edges)
const memoryType = memoryNode?.data.label
let chatHistory: IMessage[] | string = incomingInput.history
if (memoryNode && !incomingInput.history && (incomingInput.chatId || incomingInput.overrideConfig?.sessionId)) {
chatHistory = await replaceChatHistory(memoryNode, incomingInput, this.AppDataSource, databaseEntities, logger)
}
let result = isStreamValid
? await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatHistory: incomingInput.history,
chatHistory,
socketIO,
socketIOClientId: incomingInput.socketIOClientId,
logger,
@@ -1460,7 +1480,7 @@ export class App {
chatId
})
: await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatHistory: incomingInput.history,
chatHistory,
logger,
appDataSource: this.AppDataSource,
databaseEntities,
+49 -9
View File
@@ -15,7 +15,8 @@ import {
IOverrideConfig,
IReactFlowEdge,
IReactFlowNode,
IVariableDict
IVariableDict,
IncomingInput
} from '../Interface'
import { cloneDeep, get, isEqual } from 'lodash'
import {
@@ -216,7 +217,7 @@ export const buildLangchain = async (
depthQueue: IDepthQueue,
componentNodes: IComponentNodes,
question: string,
chatHistory: IMessage[],
chatHistory: IMessage[] | string,
chatId: string,
chatflowid: string,
appDataSource: DataSource,
@@ -347,8 +348,8 @@ export const clearAllSessionMemory = async (
node.data.inputs.sessionId = sessionId
}
if (newNodeInstance.clearSessionMemory) {
await newNodeInstance?.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
if (newNodeInstance.memoryMethods && newNodeInstance.memoryMethods.clearSessionMemory) {
await newNodeInstance.memoryMethods.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
}
}
}
@@ -380,8 +381,8 @@ export const clearSessionMemoryFromViewMessageDialog = async (
if (sessionId && node.data.inputs) node.data.inputs.sessionId = sessionId
if (newNodeInstance.clearSessionMemory) {
await newNodeInstance?.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
if (newNodeInstance.memoryMethods && newNodeInstance.memoryMethods.clearSessionMemory) {
await newNodeInstance.memoryMethods.clearSessionMemory(node.data, { chatId, appDataSource, databaseEntities, logger })
return
}
}
@@ -399,7 +400,7 @@ export const getVariableValue = (
paramValue: string,
reactFlowNodes: IReactFlowNode[],
question: string,
chatHistory: IMessage[],
chatHistory: IMessage[] | string,
isAcceptVariable = false
) => {
let returnVal = paramValue
@@ -432,7 +433,10 @@ export const getVariableValue = (
}
if (isAcceptVariable && variableFullPath === CHAT_HISTORY_VAR_PREFIX) {
variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(convertChatHistoryToText(chatHistory), false)
variableDict[`{{${variableFullPath}}}`] = handleEscapeCharacters(
typeof chatHistory === 'string' ? chatHistory : convertChatHistoryToText(chatHistory),
false
)
}
// Split by first occurrence of '.' to get just nodeId
@@ -475,7 +479,7 @@ export const resolveVariables = (
reactFlowNodeData: INodeData,
reactFlowNodes: IReactFlowNode[],
question: string,
chatHistory: IMessage[]
chatHistory: IMessage[] | string
): INodeData => {
let flowNodeData = cloneDeep(reactFlowNodeData)
const types = 'inputs'
@@ -873,3 +877,39 @@ export const checkMemorySessionId = (instance: any, chatId: string): string | un
return instance.memory.chatHistory.sessionId
return undefined
}
/**
* Replace chatHistory if incomingInput.history is empty and sessionId/chatId is provided
* @param {IReactFlowNode} memoryNode
* @param {IncomingInput} incomingInput
* @param {DataSource} appDataSource
* @param {IDatabaseEntity} databaseEntities
* @param {any} logger
* @returns {string}
*/
export const replaceChatHistory = async (
memoryNode: IReactFlowNode,
incomingInput: IncomingInput,
appDataSource: DataSource,
databaseEntities: IDatabaseEntity,
logger: any
): Promise<string> => {
const nodeInstanceFilePath = memoryNode.data.filePath as string
const nodeModule = await import(nodeInstanceFilePath)
const newNodeInstance = new nodeModule.nodeClass()
if (incomingInput.overrideConfig?.sessionId && memoryNode.data.inputs) {
memoryNode.data.inputs.sessionId = incomingInput.overrideConfig.sessionId
}
if (newNodeInstance.memoryMethods && newNodeInstance.memoryMethods.getChatMessages) {
return await newNodeInstance.memoryMethods.getChatMessages(memoryNode.data, {
chatId: incomingInput.chatId,
appDataSource,
databaseEntities,
logger
})
}
return ''
}