|
|
|
|
@@ -1,12 +1,12 @@
|
|
|
|
|
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
|
|
|
|
import prisma from '@/lib/prisma'
|
|
|
|
|
import { SessionState } from '@typebot.io/schemas'
|
|
|
|
|
import { Block, BubbleBlockType, SessionState } from '@typebot.io/schemas'
|
|
|
|
|
import {
|
|
|
|
|
ChatCompletionOpenAIOptions,
|
|
|
|
|
OpenAICredentials,
|
|
|
|
|
chatCompletionMessageRoles,
|
|
|
|
|
} from '@typebot.io/schemas/features/blocks/integrations/openai'
|
|
|
|
|
import { isEmpty } from '@typebot.io/lib'
|
|
|
|
|
import { byId, isEmpty } from '@typebot.io/lib'
|
|
|
|
|
import { decrypt, isCredentialsV2 } from '@typebot.io/lib/api/encryption'
|
|
|
|
|
import { updateVariables } from '@/features/variables/updateVariables'
|
|
|
|
|
import { parseVariableNumber } from '@/features/variables/parseVariableNumber'
|
|
|
|
|
@@ -20,7 +20,12 @@ export const createChatCompletionOpenAI = async (
|
|
|
|
|
{
|
|
|
|
|
outgoingEdgeId,
|
|
|
|
|
options,
|
|
|
|
|
}: { outgoingEdgeId?: string; options: ChatCompletionOpenAIOptions }
|
|
|
|
|
blockId,
|
|
|
|
|
}: {
|
|
|
|
|
outgoingEdgeId?: string
|
|
|
|
|
options: ChatCompletionOpenAIOptions
|
|
|
|
|
blockId: string
|
|
|
|
|
}
|
|
|
|
|
): Promise<ExecuteIntegrationResponse> => {
|
|
|
|
|
let newSessionState = state
|
|
|
|
|
const noCredentialsError = {
|
|
|
|
|
@@ -60,7 +65,14 @@ export const createChatCompletionOpenAI = async (
|
|
|
|
|
isPlaneteScale() &&
|
|
|
|
|
isCredentialsV2(credentials) &&
|
|
|
|
|
newSessionState.isStreamEnabled
|
|
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
const assistantMessageVariableName = state.typebot.variables.find(
|
|
|
|
|
(variable) =>
|
|
|
|
|
options.responseMapping.find(
|
|
|
|
|
(m) => m.valueToExtract === 'Message content'
|
|
|
|
|
)?.variableId === variable.id
|
|
|
|
|
)?.name
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
clientSideActions: [
|
|
|
|
|
{
|
|
|
|
|
@@ -69,12 +81,17 @@ export const createChatCompletionOpenAI = async (
|
|
|
|
|
content?: string
|
|
|
|
|
role: (typeof chatCompletionMessageRoles)[number]
|
|
|
|
|
}[],
|
|
|
|
|
displayStream: isNextBubbleMessageWithAssistantMessage(
|
|
|
|
|
state.typebot
|
|
|
|
|
)(blockId, assistantMessageVariableName),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
outgoingEdgeId,
|
|
|
|
|
newSessionState,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const { response, logs } = await executeChatCompletionOpenAIRequest({
|
|
|
|
|
apiKey,
|
|
|
|
|
messages,
|
|
|
|
|
@@ -98,3 +115,40 @@ export const createChatCompletionOpenAI = async (
|
|
|
|
|
logs,
|
|
|
|
|
})(messageContent, totalTokens)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isNextBubbleMessageWithAssistantMessage =
|
|
|
|
|
(typebot: SessionState['typebot']) =>
|
|
|
|
|
(blockId: string, assistantVariableName?: string): boolean => {
|
|
|
|
|
if (!assistantVariableName) return false
|
|
|
|
|
const nextBlock = getNextBlock(typebot)(blockId)
|
|
|
|
|
if (!nextBlock) return false
|
|
|
|
|
return (
|
|
|
|
|
nextBlock.type === BubbleBlockType.TEXT &&
|
|
|
|
|
nextBlock.content.richText?.length > 0 &&
|
|
|
|
|
nextBlock.content.richText?.at(0)?.children.at(0).text ===
|
|
|
|
|
`{{${assistantVariableName}}}`
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getNextBlock =
|
|
|
|
|
(typebot: SessionState['typebot']) =>
|
|
|
|
|
(blockId: string): Block | undefined => {
|
|
|
|
|
const group = typebot.groups.find((group) =>
|
|
|
|
|
group.blocks.find(byId(blockId))
|
|
|
|
|
)
|
|
|
|
|
if (!group) return
|
|
|
|
|
const blockIndex = group.blocks.findIndex(byId(blockId))
|
|
|
|
|
const nextBlockInGroup = group.blocks.at(blockIndex + 1)
|
|
|
|
|
if (nextBlockInGroup) return nextBlockInGroup
|
|
|
|
|
const outgoingEdgeId = group.blocks.at(blockIndex)?.outgoingEdgeId
|
|
|
|
|
if (!outgoingEdgeId) return
|
|
|
|
|
const outgoingEdge = typebot.edges.find(byId(outgoingEdgeId))
|
|
|
|
|
if (!outgoingEdge) return
|
|
|
|
|
const connectedGroup = typebot.groups.find(byId(outgoingEdge?.to.groupId))
|
|
|
|
|
if (!connectedGroup) return
|
|
|
|
|
return outgoingEdge.to.blockId
|
|
|
|
|
? connectedGroup.blocks.find(
|
|
|
|
|
(block) => block.id === outgoingEdge.to.blockId
|
|
|
|
|
)
|
|
|
|
|
: connectedGroup?.blocks.at(0)
|
|
|
|
|
}
|
|
|
|
|
|