2023-03-09 08:46:36 +01:00
|
|
|
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
|
|
|
import prisma from '@/lib/prisma'
|
2023-06-16 16:50:23 +02:00
|
|
|
import { SessionState } from '@typebot.io/schemas'
|
2023-03-09 08:46:36 +01:00
|
|
|
import {
|
|
|
|
ChatCompletionOpenAIOptions,
|
|
|
|
OpenAICredentials,
|
2023-07-12 12:28:58 +02:00
|
|
|
chatCompletionMessageRoles,
|
2023-03-15 08:35:16 +01:00
|
|
|
} from '@typebot.io/schemas/features/blocks/integrations/openai'
|
2023-06-16 16:50:23 +02:00
|
|
|
import { isEmpty } from '@typebot.io/lib'
|
2023-05-25 10:32:35 +02:00
|
|
|
import { decrypt, isCredentialsV2 } from '@typebot.io/lib/api/encryption'
|
2023-03-15 12:21:52 +01:00
|
|
|
import { updateVariables } from '@/features/variables/updateVariables'
|
2023-03-20 17:26:21 +01:00
|
|
|
import { parseVariableNumber } from '@/features/variables/parseVariableNumber'
|
2023-05-25 10:32:35 +02:00
|
|
|
import { resumeChatCompletion } from './resumeChatCompletion'
|
2023-06-16 16:50:23 +02:00
|
|
|
import { parseChatCompletionMessages } from './parseChatCompletionMessages'
|
|
|
|
import { executeChatCompletionOpenAIRequest } from './executeChatCompletionOpenAIRequest'
|
2023-06-16 19:26:29 +02:00
|
|
|
import { isPlaneteScale } from '@/helpers/api/isPlanetScale'
|
2023-03-09 08:46:36 +01:00
|
|
|
|
|
|
|
export const createChatCompletionOpenAI = async (
|
|
|
|
state: SessionState,
|
|
|
|
{
|
|
|
|
outgoingEdgeId,
|
|
|
|
options,
|
|
|
|
}: { outgoingEdgeId?: string; options: ChatCompletionOpenAIOptions }
|
|
|
|
): Promise<ExecuteIntegrationResponse> => {
|
2023-03-13 16:28:08 +01:00
|
|
|
let newSessionState = state
|
2023-04-27 11:21:32 +02:00
|
|
|
const noCredentialsError = {
|
|
|
|
status: 'error',
|
|
|
|
description: 'Make sure to select an OpenAI account',
|
|
|
|
}
|
2023-03-15 17:47:05 +01:00
|
|
|
if (!options.credentialsId) {
|
2023-04-27 11:21:32 +02:00
|
|
|
return {
|
|
|
|
outgoingEdgeId,
|
|
|
|
logs: [noCredentialsError],
|
|
|
|
}
|
2023-03-15 17:47:05 +01:00
|
|
|
}
|
2023-03-09 08:46:36 +01:00
|
|
|
const credentials = await prisma.credentials.findUnique({
|
|
|
|
where: {
|
|
|
|
id: options.credentialsId,
|
|
|
|
},
|
|
|
|
})
|
2023-03-15 17:47:05 +01:00
|
|
|
if (!credentials) {
|
|
|
|
console.error('Could not find credentials in database')
|
2023-04-27 11:21:32 +02:00
|
|
|
return { outgoingEdgeId, logs: [noCredentialsError] }
|
2023-03-15 17:47:05 +01:00
|
|
|
}
|
2023-05-25 10:32:35 +02:00
|
|
|
const { apiKey } = (await decrypt(
|
2023-03-09 08:46:36 +01:00
|
|
|
credentials.data,
|
|
|
|
credentials.iv
|
2023-05-25 10:32:35 +02:00
|
|
|
)) as OpenAICredentials['data']
|
2023-06-16 16:50:23 +02:00
|
|
|
const { variablesTransformedToList, messages } = parseChatCompletionMessages(
|
|
|
|
newSessionState.typebot.variables
|
2023-03-15 17:47:05 +01:00
|
|
|
)(options.messages)
|
2023-03-13 16:28:08 +01:00
|
|
|
if (variablesTransformedToList.length > 0)
|
2023-07-18 14:31:20 +02:00
|
|
|
newSessionState = updateVariables(state)(variablesTransformedToList)
|
2023-03-15 17:47:05 +01:00
|
|
|
|
2023-03-20 17:26:21 +01:00
|
|
|
const temperature = parseVariableNumber(newSessionState.typebot.variables)(
|
|
|
|
options.advancedSettings?.temperature
|
|
|
|
)
|
|
|
|
|
2023-06-16 16:50:23 +02:00
|
|
|
if (
|
|
|
|
isPlaneteScale() &&
|
|
|
|
isCredentialsV2(credentials) &&
|
|
|
|
newSessionState.isStreamEnabled
|
|
|
|
)
|
2023-03-13 16:28:08 +01:00
|
|
|
return {
|
2023-07-12 12:28:58 +02:00
|
|
|
clientSideActions: [
|
|
|
|
{
|
|
|
|
streamOpenAiChatCompletion: {
|
|
|
|
messages: messages as {
|
|
|
|
content?: string
|
|
|
|
role: (typeof chatCompletionMessageRoles)[number]
|
|
|
|
}[],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
2023-03-13 16:28:08 +01:00
|
|
|
outgoingEdgeId,
|
|
|
|
newSessionState,
|
|
|
|
}
|
2023-06-16 16:50:23 +02:00
|
|
|
const { response, logs } = await executeChatCompletionOpenAIRequest({
|
|
|
|
apiKey,
|
|
|
|
messages,
|
|
|
|
model: options.model,
|
|
|
|
temperature,
|
|
|
|
})
|
|
|
|
if (!response)
|
2023-03-13 16:28:08 +01:00
|
|
|
return {
|
2023-06-16 16:50:23 +02:00
|
|
|
outgoingEdgeId,
|
|
|
|
logs,
|
2023-03-13 16:28:08 +01:00
|
|
|
}
|
2023-06-16 16:50:23 +02:00
|
|
|
const messageContent = response.choices.at(0)?.message?.content
|
|
|
|
const totalTokens = response.usage?.total_tokens
|
|
|
|
if (isEmpty(messageContent)) {
|
|
|
|
console.error('OpenAI block returned empty message', response)
|
|
|
|
return { outgoingEdgeId, newSessionState }
|
2023-03-13 16:28:08 +01:00
|
|
|
}
|
2023-06-16 16:50:23 +02:00
|
|
|
return resumeChatCompletion(newSessionState, {
|
|
|
|
options,
|
|
|
|
outgoingEdgeId,
|
|
|
|
logs,
|
|
|
|
})(messageContent, totalTokens)
|
|
|
|
}
|