Lunary: feedback tracking (#3332)

* Lunary: feedback tracking

* fix incorrect param order
This commit is contained in:
Vincelwt 2024-10-21 18:32:51 +08:00 committed by GitHub
parent 2c6cf12d2c
commit 4a9ffe7b99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 80 additions and 36 deletions

View File

@ -243,12 +243,14 @@ class ExtendedLunaryHandler extends LunaryHandler {
databaseEntities: IDatabaseEntity databaseEntities: IDatabaseEntity
currentRunId: string | null currentRunId: string | null
thread: any thread: any
apiMessageId: string
constructor({ flowiseOptions, ...options }: any) { constructor({ flowiseOptions, ...options }: any) {
super(options) super(options)
this.appDataSource = flowiseOptions.appDataSource this.appDataSource = flowiseOptions.appDataSource
this.databaseEntities = flowiseOptions.databaseEntities this.databaseEntities = flowiseOptions.databaseEntities
this.chatId = flowiseOptions.chatId this.chatId = flowiseOptions.chatId
this.apiMessageId = flowiseOptions.apiMessageId
} }
async initThread() { async initThread() {
@ -258,14 +260,18 @@ class ExtendedLunaryHandler extends LunaryHandler {
} }
}) })
const userId = entity?.email ?? entity?.id
this.thread = lunary.openThread({ this.thread = lunary.openThread({
id: this.chatId, id: this.chatId,
userId: entity?.email ?? entity?.id, userId,
userProps: { userProps: userId
? {
name: entity?.name ?? undefined, name: entity?.name ?? undefined,
email: entity?.email ?? undefined, email: entity?.email ?? undefined,
phone: entity?.phone ?? undefined phone: entity?.phone ?? undefined
} }
: undefined
}) })
} }
@ -298,6 +304,7 @@ class ExtendedLunaryHandler extends LunaryHandler {
const answer = outputs.output const answer = outputs.output
this.thread.trackMessage({ this.thread.trackMessage({
id: this.apiMessageId,
content: answer, content: answer,
role: 'assistant' role: 'assistant'
}) })

View File

@ -54,7 +54,8 @@ const executeAgentTool = async (req: Request, res: Response, next: NextFunction)
req.params.id, req.params.id,
req.body.chatId, req.body.chatId,
req.body.toolName, req.body.toolName,
req.body.inputArgs req.body.inputArgs,
req.body.apiMessageId
) )
return res.json(apiResponse) return res.json(apiResponse)
} catch (error) { } catch (error) {

View File

@ -12,7 +12,7 @@ import { v4 as uuidv4 } from 'uuid'
const SOURCE_DOCUMENTS_PREFIX = '\n\n----FLOWISE_SOURCE_DOCUMENTS----\n\n' const SOURCE_DOCUMENTS_PREFIX = '\n\n----FLOWISE_SOURCE_DOCUMENTS----\n\n'
const ARTIFACTS_PREFIX = '\n\n----FLOWISE_ARTIFACTS----\n\n' const ARTIFACTS_PREFIX = '\n\n----FLOWISE_ARTIFACTS----\n\n'
const buildAndInitTool = async (chatflowid: string, _chatId?: string) => { const buildAndInitTool = async (chatflowid: string, _chatId?: string, _apiMessageId?: string) => {
const appServer = getRunningExpressApp() const appServer = getRunningExpressApp()
const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({
id: chatflowid id: chatflowid
@ -22,6 +22,7 @@ const buildAndInitTool = async (chatflowid: string, _chatId?: string) => {
} }
const chatId = _chatId || uuidv4() const chatId = _chatId || uuidv4()
const apiMessageId = _apiMessageId || uuidv4()
const flowData = JSON.parse(chatflow.flowData) const flowData = JSON.parse(chatflow.flowData)
const nodes = flowData.nodes const nodes = flowData.nodes
const edges = flowData.edges const edges = flowData.edges
@ -62,6 +63,7 @@ const buildAndInitTool = async (chatflowid: string, _chatId?: string) => {
chatId: chatId, chatId: chatId,
sessionId: chatId, sessionId: chatId,
chatflowid, chatflowid,
apiMessageId,
appDataSource: appServer.AppDataSource appDataSource: appServer.AppDataSource
}) })
@ -113,9 +115,15 @@ const getAgentTools = async (chatflowid: string): Promise<any> => {
} }
} }
const executeAgentTool = async (chatflowid: string, chatId: string, toolName: string, inputArgs: string): Promise<any> => { const executeAgentTool = async (
chatflowid: string,
chatId: string,
toolName: string,
inputArgs: string,
apiMessageId?: string
): Promise<any> => {
try { try {
const agent = await buildAndInitTool(chatflowid, chatId) const agent = await buildAndInitTool(chatflowid, chatId, apiMessageId)
const tools = agent.tools const tools = agent.tools
const tool = tools.find((tool: any) => tool.name === toolName) const tool = tools.find((tool: any) => tool.name === toolName)

View File

@ -57,6 +57,7 @@ import logger from './logger'
export const buildAgentGraph = async ( export const buildAgentGraph = async (
chatflow: IChatFlow, chatflow: IChatFlow,
chatId: string, chatId: string,
apiMessageId: string,
sessionId: string, sessionId: string,
incomingInput: IncomingInput, incomingInput: IncomingInput,
isInternal: boolean, isInternal: boolean,
@ -114,6 +115,7 @@ export const buildAgentGraph = async (
startingNodeIds, startingNodeIds,
reactFlowNodes: nodes, reactFlowNodes: nodes,
reactFlowEdges: edges, reactFlowEdges: edges,
apiMessageId,
graph, graph,
depthQueue, depthQueue,
componentNodes: appServer.nodesPool.componentNodes, componentNodes: appServer.nodesPool.componentNodes,

View File

@ -202,6 +202,8 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
const nodes = parsedFlowData.nodes const nodes = parsedFlowData.nodes
const edges = parsedFlowData.edges const edges = parsedFlowData.edges
const apiMessageId = uuidv4()
/*** Get session ID ***/ /*** Get session ID ***/
const memoryNode = findMemoryNode(nodes, edges) const memoryNode = findMemoryNode(nodes, edges)
const memoryType = memoryNode?.data.label const memoryType = memoryNode?.data.label
@ -217,6 +219,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
chatflow, chatflow,
isInternal, isInternal,
chatId, chatId,
apiMessageId,
memoryType ?? '', memoryType ?? '',
sessionId, sessionId,
userMessageDateTime, userMessageDateTime,
@ -339,6 +342,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
reactFlowEdges: edges, reactFlowEdges: edges,
graph, graph,
depthQueue, depthQueue,
apiMessageId,
componentNodes: appServer.nodesPool.componentNodes, componentNodes: appServer.nodesPool.componentNodes,
question: incomingInput.question, question: incomingInput.question,
chatHistory, chatHistory,
@ -369,6 +373,7 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
chatflowid, chatflowid,
chatId, chatId,
sessionId, sessionId,
apiMessageId,
chatHistory, chatHistory,
...incomingInput.overrideConfig ...incomingInput.overrideConfig
} }
@ -394,29 +399,23 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
isStreamValid = (req.body.streaming === 'true' || req.body.streaming === true) && isStreamValid isStreamValid = (req.body.streaming === 'true' || req.body.streaming === true) && isStreamValid
let result = isStreamValid const runParams = {
? await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatId,
chatflowid,
logger,
appDataSource: appServer.AppDataSource,
databaseEntities,
analytic: chatflow.analytic,
uploads: incomingInput.uploads,
prependMessages,
sseStreamer: appServer.sseStreamer,
shouldStreamResponse: isStreamValid
})
: await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
chatId, chatId,
chatflowid, chatflowid,
apiMessageId,
logger, logger,
appDataSource: appServer.AppDataSource, appDataSource: appServer.AppDataSource,
databaseEntities, databaseEntities,
analytic: chatflow.analytic, analytic: chatflow.analytic,
uploads: incomingInput.uploads, uploads: incomingInput.uploads,
prependMessages prependMessages
}
let result = await nodeInstance.run(nodeToExecuteData, incomingInput.question, {
...runParams,
...(isStreamValid && { sseStreamer: appServer.sseStreamer, shouldStreamResponse: true })
}) })
result = typeof result === 'string' ? { text: result } : result result = typeof result === 'string' ? { text: result } : result
// Retrieve threadId from assistant if exists // Retrieve threadId from assistant if exists
@ -443,7 +442,8 @@ export const utilBuildChatflow = async (req: Request, isInternal: boolean = fals
else if (result.json) resultText = '```json\n' + JSON.stringify(result.json, null, 2) else if (result.json) resultText = '```json\n' + JSON.stringify(result.json, null, 2)
else resultText = JSON.stringify(result, null, 2) else resultText = JSON.stringify(result, null, 2)
const apiMessage: Omit<IChatMessage, 'id' | 'createdDate'> = { const apiMessage: Omit<IChatMessage, 'createdDate'> = {
id: apiMessageId,
role: 'apiMessage', role: 'apiMessage',
content: resultText, content: resultText,
chatflowid, chatflowid,
@ -507,6 +507,7 @@ const utilBuildAgentResponse = async (
agentflow: IChatFlow, agentflow: IChatFlow,
isInternal: boolean, isInternal: boolean,
chatId: string, chatId: string,
apiMessageId: string,
memoryType: string, memoryType: string,
sessionId: string, sessionId: string,
userMessageDateTime: Date, userMessageDateTime: Date,
@ -523,6 +524,7 @@ const utilBuildAgentResponse = async (
const streamResults = await buildAgentGraph( const streamResults = await buildAgentGraph(
agentflow, agentflow,
chatId, chatId,
apiMessageId,
sessionId, sessionId,
incomingInput, incomingInput,
isInternal, isInternal,
@ -546,7 +548,8 @@ const utilBuildAgentResponse = async (
} }
await utilAddChatMessage(userMessage) await utilAddChatMessage(userMessage)
const apiMessage: Omit<IChatMessage, 'id' | 'createdDate'> = { const apiMessage: Omit<IChatMessage, 'createdDate'> = {
id: apiMessageId,
role: 'apiMessage', role: 'apiMessage',
content: finalResult, content: finalResult,
chatflowid: agentflow.id, chatflowid: agentflow.id,

View File

@ -430,6 +430,7 @@ type BuildFlowParams = {
chatId: string chatId: string
sessionId: string sessionId: string
chatflowid: string chatflowid: string
apiMessageId: string
appDataSource: DataSource appDataSource: DataSource
overrideConfig?: ICommonObject overrideConfig?: ICommonObject
cachePool?: CachePool cachePool?: CachePool
@ -452,6 +453,7 @@ export const buildFlow = async ({
componentNodes, componentNodes,
question, question,
chatHistory, chatHistory,
apiMessageId,
chatId, chatId,
sessionId, sessionId,
chatflowid, chatflowid,
@ -524,6 +526,7 @@ export const buildFlow = async ({
sessionId, sessionId,
chatflowid, chatflowid,
chatHistory, chatHistory,
apiMessageId,
logger, logger,
appDataSource, appDataSource,
databaseEntities, databaseEntities,

View File

@ -1,6 +1,8 @@
import { IChatMessageFeedback } from '../Interface' import { IChatMessageFeedback } from '../Interface'
import { getRunningExpressApp } from '../utils/getRunningExpressApp' import { getRunningExpressApp } from '../utils/getRunningExpressApp'
import { ChatMessageFeedback } from '../database/entities/ChatMessageFeedback' import { ChatMessageFeedback } from '../database/entities/ChatMessageFeedback'
import { ChatFlow } from '../database/entities/ChatFlow'
import lunary from 'lunary'
/** /**
* Method that updates chat message feedback. * Method that updates chat message feedback.
@ -11,6 +13,21 @@ export const utilUpdateChatMessageFeedback = async (id: string, chatMessageFeedb
const appServer = getRunningExpressApp() const appServer = getRunningExpressApp()
const newChatMessageFeedback = new ChatMessageFeedback() const newChatMessageFeedback = new ChatMessageFeedback()
Object.assign(newChatMessageFeedback, chatMessageFeedback) Object.assign(newChatMessageFeedback, chatMessageFeedback)
await appServer.AppDataSource.getRepository(ChatMessageFeedback).update({ id }, chatMessageFeedback) await appServer.AppDataSource.getRepository(ChatMessageFeedback).update({ id }, chatMessageFeedback)
// Fetch the updated entity
const updatedFeedback = await appServer.AppDataSource.getRepository(ChatMessageFeedback).findOne({ where: { id } })
const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOne({ where: { id: updatedFeedback?.chatflowid } })
const analytic = JSON.parse(chatflow?.analytic ?? '{}')
if (analytic?.lunary?.status === true && updatedFeedback?.rating) {
lunary.trackFeedback(updatedFeedback.messageId, {
comment: updatedFeedback?.content,
thumb: updatedFeedback?.rating === 'THUMBS_UP' ? 'up' : 'down'
})
}
return { status: 'OK' } return { status: 'OK' }
} }

View File

@ -23,7 +23,7 @@ import { UpsertHistory } from '../database/entities/UpsertHistory'
import { InternalFlowiseError } from '../errors/internalFlowiseError' import { InternalFlowiseError } from '../errors/internalFlowiseError'
import { StatusCodes } from 'http-status-codes' import { StatusCodes } from 'http-status-codes'
import { getErrorMessage } from '../errors/utils' import { getErrorMessage } from '../errors/utils'
import { v4 as uuidv4 } from 'uuid'
/** /**
* Upsert documents * Upsert documents
* @param {Request} req * @param {Request} req
@ -108,6 +108,8 @@ export const upsertVector = async (req: Request, isInternal: boolean = false) =>
const nodes = parsedFlowData.nodes const nodes = parsedFlowData.nodes
const edges = parsedFlowData.edges const edges = parsedFlowData.edges
const apiMessageId = req.body.apiMessageId ?? uuidv4()
let stopNodeId = incomingInput?.stopNodeId ?? '' let stopNodeId = incomingInput?.stopNodeId ?? ''
let chatHistory: IMessage[] = [] let chatHistory: IMessage[] = []
let chatId = incomingInput.chatId ?? '' let chatId = incomingInput.chatId ?? ''
@ -162,6 +164,7 @@ export const upsertVector = async (req: Request, isInternal: boolean = false) =>
question: incomingInput.question, question: incomingInput.question,
chatHistory, chatHistory,
chatId, chatId,
apiMessageId,
sessionId: sessionId ?? '', sessionId: sessionId ?? '',
chatflowid, chatflowid,
appDataSource: appServer.AppDataSource, appDataSource: appServer.AppDataSource,