@botonic/plugin-flow-builder
Version:
Use Flow Builder to show your contents
157 lines (135 loc) • 4.39 kB
text/typescript
import { BotContext, ResolvedPlugins } from '@botonic/core'
import {
DISABLED_MEMORY_LENGTH,
FlowContent,
FlowKnowledgeBase,
} from '../content-fields'
import { HtNodeWithContent } from '../content-fields/hubtype-fields/nodes'
import { EventAction, KnowledgebaseFailReason, trackEvent } from '../tracking'
import { KnowledgeBaseFunction, KnowledgeBaseResponse } from '../types'
import { inputHasTextData, isKnowledgeBasesAllowed } from '../utils'
import { FlowBuilderContext } from './index'
export async function getContentsByKnowledgeBase({
cmsApi,
flowBuilderPlugin,
request,
}: FlowBuilderContext): Promise<FlowContent[]> {
if (isKnowledgeBasesAllowed(request)) {
const startNodeKnowledgeBaseFlow = cmsApi.getStartNodeKnowledgeBaseFlow()
const isKnowledgeBaseEnabled = cmsApi.isKnowledgeBaseEnabled()
if (!startNodeKnowledgeBaseFlow || !isKnowledgeBaseEnabled) {
return []
}
const contents = await flowBuilderPlugin.getContentsByNode(
startNodeKnowledgeBaseFlow
)
const knowledgeBaseContent = contents.find(
content => content instanceof FlowKnowledgeBase
) as FlowKnowledgeBase
if (!knowledgeBaseContent) {
return contents
}
const sourceIds = knowledgeBaseContent.sourcesData.map(source => source.id)
const flowId = cmsApi.getNodeById<HtNodeWithContent>(
knowledgeBaseContent.id
).flow_id
if (
flowBuilderPlugin.getKnowledgeBaseResponse &&
inputHasTextData(request.input) &&
sourceIds.length > 0
) {
const contentsWithKnowledgeResponse =
await getContentsWithKnowledgeResponse(
flowBuilderPlugin.getKnowledgeBaseResponse,
request,
contents,
knowledgeBaseContent,
flowId
)
if (contentsWithKnowledgeResponse) {
return contentsWithKnowledgeResponse
}
}
}
return []
}
async function getContentsWithKnowledgeResponse<
T extends ResolvedPlugins = ResolvedPlugins,
>(
getKnowledgeBaseResponse: KnowledgeBaseFunction<T>,
request: BotContext<T>,
contents: FlowContent[],
knowledgeBaseContent: FlowKnowledgeBase,
flowId: string
): Promise<FlowContent[] | undefined> {
const sourceIds = knowledgeBaseContent.sourcesData.map(source => source.id)
const instructions = knowledgeBaseContent.instructions
const messageId = request.input.message_id
const memoryLength = knowledgeBaseContent.hasMemory
? knowledgeBaseContent.memoryLength
: DISABLED_MEMORY_LENGTH
const knowledgeBaseResponse = await getKnowledgeBaseResponse(
request,
sourceIds,
instructions,
messageId,
memoryLength
)
await trackKnowledgeBase(
knowledgeBaseResponse,
request,
knowledgeBaseContent,
flowId
)
if (
!knowledgeBaseResponse.hasKnowledge ||
!knowledgeBaseResponse.isFaithful
) {
return undefined
}
return updateContentsWithResponse(contents, knowledgeBaseResponse)
}
function updateContentsWithResponse(
contents: FlowContent[],
response: KnowledgeBaseResponse
): FlowContent[] {
return contents.map(content => {
if (content instanceof FlowKnowledgeBase) {
content.text = response.answer
content.inferenceId = response.inferenceId
}
return content
})
}
async function trackKnowledgeBase(
response: KnowledgeBaseResponse,
request: BotContext,
knowledgeBaseContent: FlowKnowledgeBase,
flowId: string
) {
const sourceIds = knowledgeBaseContent.sourcesData.map(source => source.id)
const knowledgebaseInferenceId = response.inferenceId
const knowledgebaseSourcesIds = sourceIds
const knowledgebaseChunksIds = response.chunkIds
const knowledgebaseMessageId = request.input.message_id
const flowThreadId = request.session.flow_thread_id
const flowNodeId = knowledgeBaseContent.id
let knowledgebaseFailReason: KnowledgebaseFailReason | undefined
if (!response.isFaithful) {
knowledgebaseFailReason = KnowledgebaseFailReason.Hallucination
}
if (!response.hasKnowledge) {
knowledgebaseFailReason = KnowledgebaseFailReason.NoKnowledge
}
await trackEvent(request, EventAction.Knowledgebase, {
knowledgebaseInferenceId,
knowledgebaseFailReason,
knowledgebaseSourcesIds,
knowledgebaseChunksIds,
knowledgebaseMessageId,
userInput: request.input.data,
flowThreadId,
flowId,
flowNodeId,
})
}