Skip to content

Conversation

@wangerzi
Copy link
Contributor

Support https://docs.getzep.com/sdk/langchain/ in Flowise.

Some limits:

  • the unique session id should be changed manually in every conversion, because zep server doesn't support session id reuse now

image

@wangerzi
Copy link
Contributor Author

zep-test Chatflow.zip
a simple chatflow demo.

@HenryHengZJ
Copy link
Contributor

thanks @wangerzi for the Zep addition!
can you help me understand the session id? what do you mean by should be changed manually in every conversion?

@wangerzi
Copy link
Contributor Author

wangerzi commented Jun 10, 2023

thanks @wangerzi for the Zep addition! can you help me understand the session id? what do you mean by should be changed manually in every conversion?

@HenryHengZJ Flowise is an interesting project, I'm very happy to make some contributions.😀

The session id in zep just like a required unique identifier of a conversion, zep server use session id to find memory, make summary, etc...

But when we want to create a new conversion in flowise, we must change the session id (or automatic generate a uuid for new conversion), because we can't clear zep chat history in this session by api.
image

Talk is cheap, I'm already prepared a demo to explain it:

Execution Prepare:

// import { ZepMemory } from 'langchain/memory/zep'
// import { Memory, Message } from '@getzep/zep-js'
const { ZepMemory } = require('langchain/memory/zep')
const { Memory, Message } = require('@getzep/zep-js')

const sessionId = 'test-3'
const zepURL = 'http://localhost:8000'

const memory = new ZepMemory({
    sessionId,
    memoryKey: 'chat_history',
    returnMessages: true,
    baseURL: zepURL
})

async function init() {
    const history = [
        {
            role: 'human',
            content: 'Who was Octavia Butler?'
        },
        {
            role: 'ai',
            content: 'Octavia Estelle Butler (June 22, 1947 – February 24, 2006) was an American' + ' science fiction author.'
        }
    ]

    const messages = history.map(({ role, content }) => new Message({ role, content }))
    const zepMemory = new Memory({ messages })

    await memory.zepClient.addMemory(sessionId, zepMemory)
}

async function testSearch() {
    await init()
    const data = await memory.loadMemoryVariables({
        lastN: 10
    })
    console.log('search data:', data)
}

async function testClear() {
    await memory.clear()
}

async function testCase1() {
    console.log('first search')
    await testSearch()
    await testClear()
    console.log('already cleared')
    await testSearch()
}

testCase1()

Execution Result told us if we can't use official api memory.clear() to reuse a same session id:

$ node test-zep.js
first search
search data: {
  chat_history: [
    ChatMessage {
      text: 'Who was Octavia Butler?',
      name: undefined,
      role: 'human'
    },
    ChatMessage {
      text: 'Octavia Estelle Butler (June 22, 1947 – February 24, 2006) was an American science fiction author.',
      name: undefined,
      role: 'ai'
    }
  ]
}
already cleared
D:\phpStudy\WWW\github\Flowise\node_modules\@getzep\zep-js\dist\zep-client.js:143
                    throw new exceptions_1.UnexpectedResponseError(`addMemoryAsync got an Unexpected status code: ${error.response.status}`);
                          ^

UnexpectedResponseError: addMemoryAsync got an Unexpected status code: 400
    at ZepClient.<anonymous> (D:\phpStudy\WWW\github\Flowise\node_modules\@getzep\zep-js\dist\zep-client.js:143:27)
    at Generator.throw (<anonymous>)
    at rejected (D:\phpStudy\WWW\github\Flowise\node_modules\@getzep\zep-js\dist\zep-client.js:29:65)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
  responseData: undefined
}

Node.js v18.16.0

References:

@HenryHengZJ
Copy link
Contributor

@wangerzi oh okay in that case, can we just use timestamp string as session id? that way we can save user from inputting/changing session id everytime

@wangerzi
Copy link
Contributor Author

@HenryHengZJ Sounds like a great idea to solve this problem👏, I'll try to use the conversion start time as zep session after 8 hours (after wake up🌞)

@wangerzi
Copy link
Contributor Author

@HenryHengZJ According to the current data structure, I think the first chat message id is a better choice for chat_id

For generality, I found the first chat message in backend, and pass it by options in INode definition init?(nodeData: INodeData, input: string, options?: ICommonObject): Promise<any>

This is the minimum modification in my mind, but I'm not sure if you have better solution for this.

image

Key Code:

depthQueue,
componentNodes,
incomingInput.question,
'',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing, I have forgot the chatflow variable contains a correct chatflow.id we can use, I'll fix it later!👀

setLoading(true)
setMessages((prevMessages) => [...prevMessages, { message: userInput, type: 'userMessage' }])
addChatMessage(userInput, 'userMessage')
// waiting for first chatmessage uploaded, the first chatmessage id will be chatId for every components
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code await addChatMessage(userInput, 'userMessage') looks the same before and after changes, is the comment redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, maybe I should say goodmorning to you! Considering that when the chat message is sent for the first time, if the POST /chatmessage/{id} request and the POST /internal-prediction/${id} request are executed concurrently, the first message id ORM query will fail in the prediction request.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to remove await and make some test, as my last comment, it will trigger error from api /internal-prediction/{id} sometimes, because chatmessage can't be queried in database
image

@HenryHengZJ
Copy link
Contributor

@HenryHengZJ According to the current data structure, I think the first chat message id is a better choice for chat_id

For generality, I found the first chat message in backend, and pass it by options in INode definition init?(nodeData: INodeData, input: string, options?: ICommonObject): Promise<any>

This is the minimum modification in my mind, but I'm not sure if you have better solution for this.

image

Key Code:

i love the idea of using first chat id, that way when user clear the conversation, the session id will also be refreshed

@wangerzi
Copy link
Contributor Author

wangerzi commented Jun 11, 2023

@HenryHengZJ I'm already update the code based on our conversation, and I create a new function getChatId at index.ts, it's easy to use but I'm not sure if this is the best place.

label: 'Session Id',
name: 'sessionId',
type: 'string',
placeholder: 'if empty, chatId will be used automatically',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can use description for the message

const { startingNodeIds, depthQueue } = getStartingNodes(nonDirectedGraph, endingNodeId)

/*** BFS to traverse from Starting Nodes to Ending Node ***/
const chatId = await getChatId(chatflow.id)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will not work because child processes dont have access to DataSource. You'll have to get the chatid in startChildProcess() and pass it in the IRunChatflowMessageValue - https://github.com/FlowiseAI/Flowise/blob/main/packages/server/src/index.ts#L449. Then retrieve it here - https://github.com/FlowiseAI/Flowise/blob/main/packages/server/src/ChildProcess.ts#L26

@wangerzi
Copy link
Contributor Author

@HenryHengZJ Thank you very much for your patience and guidance, I have changed my code by your comment.😀

em, but I just have a little confusion, I don't known how to test ChildProcess.ts in the UI

@HenryHengZJ
Copy link
Contributor

@HenryHengZJ Thank you very much for your patience and guidance, I have changed my code by your comment.😀

em, but I just have a little confusion, I don't known how to test ChildProcess.ts in the UI

In the .env file in packages/server, you can specify the EXECUTION_MODE: https://github.com/FlowiseAI/Flowise/blob/main/packages/server/.env.example#L4

@wangerzi
Copy link
Contributor Author

@HenryHengZJ Thank you very much for your patience and guidance, I have changed my code by your comment.😀
em, but I just have a little confusion, I don't known how to test ChildProcess.ts in the UI

In the .env file in packages/server, you can specify the EXECUTION_MODE: https://github.com/FlowiseAI/Flowise/blob/main/packages/server/.env.example#L4

Thanks for answering, I've updated some code to remove a useless ORM query and tested the ChildProcess.ts by modify .env

@HenryHengZJ
Copy link
Contributor

thanks @wangerzi !! tested and it works like a charm!

really appreciate the ground work of session id using chat id, it makes it easy for other memory implementation thats using session id as well

@HenryHengZJ HenryHengZJ merged commit 9809919 into FlowiseAI:main Jun 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants