Feature/Buffer Memory SessionId (#2111)

* add sessionId to buffer memory, add conversation summary buffer memory

* add fix for conv retrieval qa chain
This commit is contained in:
Henry Heng
2024-04-11 11:18:39 +01:00
committed by GitHub
parent 57b716c7d7
commit c33642cdf9
39 changed files with 784 additions and 574 deletions
+12 -17
View File
@@ -132,7 +132,6 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
incomingInput = {
question: req.body.question ?? 'hello',
overrideConfig,
history: [],
socketIOClientId: req.body.socketIOClientId
}
}
@@ -146,8 +145,7 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
// Get session ID
const memoryNode = findMemoryNode(nodes, edges)
const memoryType = memoryNode?.data.label
let sessionId = undefined
if (memoryNode) sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal)
let sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal)
/* Reuse the flow without having to rebuild (to avoid duplicated upsert, recomputation, reinitialization of memory) when all these conditions met:
* - Node Data already exists in pool
@@ -225,9 +223,9 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
// Once custom function ending node exists, flow is always unavailable to stream
isStreamValid = isEndingNodeExists ? false : isStreamValid
let chatHistory: IMessage[] = incomingInput.history ?? []
let chatHistory: IMessage[] = []
// When {{chat_history}} is used in Prompt Template, fetch the chat conversations from memory node
// When {{chat_history}} is used in Format Prompt Value, fetch the chat conversations from memory node
for (const endingNode of endingNodes) {
const endingNodeData = endingNode.data
@@ -238,16 +236,15 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
if (!memoryNode) continue
if (!chatHistory.length && (incomingInput.chatId || incomingInput.overrideConfig?.sessionId)) {
chatHistory = await getSessionChatHistory(
memoryNode,
appServer.nodesPool.componentNodes,
incomingInput,
appServer.AppDataSource,
databaseEntities,
logger
)
}
chatHistory = await getSessionChatHistory(
chatflowid,
getMemorySessionId(memoryNode, incomingInput, chatId, isInternal),
memoryNode,
appServer.nodesPool.componentNodes,
appServer.AppDataSource,
databaseEntities,
logger
)
}
/*** Get Starting Nodes with Reversed Graph ***/
@@ -314,7 +311,6 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
? await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatId,
chatflowid,
chatHistory: incomingInput.history,
logger,
appDataSource: appServer.AppDataSource,
databaseEntities,
@@ -326,7 +322,6 @@ export const utilBuildChatflow = async (req: Request, socketIO?: Server, isInter
: await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatId,
chatflowid,
chatHistory: incomingInput.history,
logger,
appDataSource: appServer.AppDataSource,
databaseEntities,
+19 -14
View File
@@ -1144,16 +1144,18 @@ export const redactCredentialWithPasswordType = (
* API/Embed + UI:
* (3) Hard-coded sessionId in UI
* (4) Not specified on UI nor API, default to chatId
* @param {any} instance
* @param {IReactFlowNode | undefined} memoryNode
* @param {IncomingInput} incomingInput
* @param {string} chatId
* @param {boolean} isInternal
* @returns {string}
*/
export const getMemorySessionId = (
memoryNode: IReactFlowNode,
memoryNode: IReactFlowNode | undefined,
incomingInput: IncomingInput,
chatId: string,
isInternal: boolean
): string | undefined => {
): string => {
if (!isInternal) {
// Provided in API body - incomingInput.overrideConfig: { sessionId: 'abc' }
if (incomingInput.overrideConfig?.sessionId) {
@@ -1166,7 +1168,7 @@ export const getMemorySessionId = (
}
// Hard-coded sessionId in UI
if (memoryNode.data.inputs?.sessionId) {
if (memoryNode && memoryNode.data.inputs?.sessionId) {
return memoryNode.data.inputs.sessionId
}
@@ -1175,18 +1177,21 @@ export const getMemorySessionId = (
}
/**
* Replace chatHistory if incomingInput.history is empty and sessionId/chatId is provided
* Get chat messages from sessionId
* @param {IReactFlowNode} memoryNode
* @param {IncomingInput} incomingInput
* @param {string} sessionId
* @param {IReactFlowNode} memoryNode
* @param {IComponentNodes} componentNodes
* @param {DataSource} appDataSource
* @param {IDatabaseEntity} databaseEntities
* @param {any} logger
* @returns {string}
* @returns {IMessage[]}
*/
export const getSessionChatHistory = async (
chatflowid: string,
sessionId: string,
memoryNode: IReactFlowNode,
componentNodes: IComponentNodes,
incomingInput: IncomingInput,
appDataSource: DataSource,
databaseEntities: IDatabaseEntity,
logger: any
@@ -1196,19 +1201,18 @@ export const getSessionChatHistory = async (
const newNodeInstance = new nodeModule.nodeClass()
// Replace memory's sessionId/chatId
if (incomingInput.overrideConfig?.sessionId && memoryNode.data.inputs) {
memoryNode.data.inputs.sessionId = incomingInput.overrideConfig.sessionId
} else if (incomingInput.chatId && memoryNode.data.inputs) {
memoryNode.data.inputs.sessionId = incomingInput.chatId
if (memoryNode.data.inputs) {
memoryNode.data.inputs.sessionId = sessionId
}
const initializedInstance: FlowiseMemory = await newNodeInstance.init(memoryNode.data, '', {
chatflowid,
appDataSource,
databaseEntities,
logger
})
return (await initializedInstance.getChatMessages()) as IMessage[]
return (await initializedInstance.getChatMessages(sessionId)) as IMessage[]
}
/**
@@ -1216,7 +1220,7 @@ export const getSessionChatHistory = async (
* In a chatflow, there should only be 1 memory node
* @param {IReactFlowNode[]} nodes
* @param {IReactFlowEdge[]} edges
* @returns {string | undefined}
* @returns {IReactFlowNode | undefined}
*/
export const findMemoryNode = (nodes: IReactFlowNode[], edges: IReactFlowEdge[]): IReactFlowNode | undefined => {
const memoryNodes = nodes.filter((node) => node.data.category === 'Memory')
@@ -1228,6 +1232,7 @@ export const findMemoryNode = (nodes: IReactFlowNode[], edges: IReactFlowEdge[])
return memoryNode
}
}
return undefined
}
+3 -5
View File
@@ -1,7 +1,7 @@
import { Request } from 'express'
import * as fs from 'fs'
import { cloneDeep, omit } from 'lodash'
import { ICommonObject } from 'flowise-components'
import { ICommonObject, IMessage } from 'flowise-components'
import telemetryService from '../services/telemetry'
import logger from '../utils/logger'
import {
@@ -66,7 +66,6 @@ export const upsertVector = async (req: Request, isInternal: boolean = false) =>
incomingInput = {
question: req.body.question ?? 'hello',
overrideConfig,
history: [],
stopNodeId: req.body.stopNodeId
}
}
@@ -78,14 +77,13 @@ export const upsertVector = async (req: Request, isInternal: boolean = false) =>
const edges = parsedFlowData.edges
let stopNodeId = incomingInput?.stopNodeId ?? ''
let chatHistory = incomingInput?.history
let chatHistory: IMessage[] = []
let chatId = incomingInput.chatId ?? ''
let isUpsert = true
// Get session ID
const memoryNode = findMemoryNode(nodes, edges)
let sessionId = undefined
if (memoryNode) sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal)
let sessionId = getMemorySessionId(memoryNode, incomingInput, chatId, isInternal)
const vsNodes = nodes.filter(
(node) =>