@@ -26,6 +26,7 @@
|
||||
"next": "13.1.6",
|
||||
"nextjs-cors": "^2.1.2",
|
||||
"nodemailer": "6.9.1",
|
||||
"openai": "^3.2.1",
|
||||
"phone": "^3.1.34",
|
||||
"qs": "6.11.0",
|
||||
"react": "18.2.0",
|
||||
@@ -34,9 +35,9 @@
|
||||
"trpc-openapi": "1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@paralleldrive/cuid2": "2.2.0",
|
||||
"@babel/preset-env": "7.20.2",
|
||||
"@faire/mjml-react": "3.1.1",
|
||||
"@paralleldrive/cuid2": "2.2.0",
|
||||
"@playwright/test": "1.31.1",
|
||||
"@types/cors": "2.8.13",
|
||||
"@types/google-spreadsheet": "3.3.1",
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
PaymentInputOptions,
|
||||
PaymentInputRuntimeOptions,
|
||||
SessionState,
|
||||
StripeCredentialsData,
|
||||
StripeCredentials,
|
||||
} from 'models'
|
||||
import Stripe from 'stripe'
|
||||
import { decrypt } from 'utils/api/encryption'
|
||||
@@ -82,12 +82,12 @@ const createStripePaymentIntent =
|
||||
|
||||
const getStripeInfo = async (
|
||||
credentialsId: string
|
||||
): Promise<StripeCredentialsData | undefined> => {
|
||||
): Promise<StripeCredentials['data'] | undefined> => {
|
||||
const credentials = await prisma.credentials.findUnique({
|
||||
where: { id: credentialsId },
|
||||
})
|
||||
if (!credentials) return
|
||||
return decrypt(credentials.data, credentials.iv) as StripeCredentialsData
|
||||
return decrypt(credentials.data, credentials.iv) as StripeCredentials['data']
|
||||
}
|
||||
|
||||
// https://stripe.com/docs/currencies#zero-decimal
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { parseVariables, updateVariables } from '@/features/variables/utils'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { SessionState, VariableWithUnknowValue } from 'models'
|
||||
import {
|
||||
ChatCompletionOpenAIOptions,
|
||||
OpenAICredentials,
|
||||
} from 'models/features/blocks/integrations/openai'
|
||||
import { OpenAIApi, Configuration, ChatCompletionRequestMessage } from 'openai'
|
||||
import { isDefined, byId, isNotEmpty } from 'utils'
|
||||
import { decrypt } from 'utils/api/encryption'
|
||||
|
||||
export const createChatCompletionOpenAI = async (
|
||||
state: SessionState,
|
||||
{
|
||||
outgoingEdgeId,
|
||||
options,
|
||||
}: { outgoingEdgeId?: string; options: ChatCompletionOpenAIOptions }
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
const {
|
||||
typebot: { variables },
|
||||
} = state
|
||||
if (!options.credentialsId) return { outgoingEdgeId }
|
||||
const credentials = await prisma.credentials.findUnique({
|
||||
where: {
|
||||
id: options.credentialsId,
|
||||
},
|
||||
})
|
||||
if (!credentials) return { outgoingEdgeId }
|
||||
const { apiKey } = decrypt(
|
||||
credentials.data,
|
||||
credentials.iv
|
||||
) as OpenAICredentials['data']
|
||||
const configuration = new Configuration({
|
||||
apiKey,
|
||||
})
|
||||
const openai = new OpenAIApi(configuration)
|
||||
const {
|
||||
data: { choices, usage },
|
||||
} = await openai.createChatCompletion({
|
||||
model: options.model,
|
||||
messages: options.messages
|
||||
.map((message) => ({
|
||||
role: message.role,
|
||||
content: parseVariables(variables)(message.content),
|
||||
}))
|
||||
.filter(
|
||||
(message) => isNotEmpty(message.role) && isNotEmpty(message.content)
|
||||
) as ChatCompletionRequestMessage[],
|
||||
})
|
||||
const messageContent = choices[0].message?.content
|
||||
const totalTokens = usage?.total_tokens
|
||||
if (!messageContent) {
|
||||
return { outgoingEdgeId }
|
||||
}
|
||||
const newVariables = options.responseMapping.reduce<
|
||||
VariableWithUnknowValue[]
|
||||
>((newVariables, mapping) => {
|
||||
const existingVariable = variables.find(byId(mapping.variableId))
|
||||
if (!existingVariable) return newVariables
|
||||
if (mapping.valueToExtract === 'Message content') {
|
||||
newVariables.push({
|
||||
...existingVariable,
|
||||
value: messageContent,
|
||||
})
|
||||
}
|
||||
if (mapping.valueToExtract === 'Total tokens' && isDefined(totalTokens)) {
|
||||
newVariables.push({
|
||||
...existingVariable,
|
||||
value: totalTokens,
|
||||
})
|
||||
}
|
||||
return newVariables
|
||||
}, [])
|
||||
if (newVariables.length > 0) {
|
||||
const newSessionState = await updateVariables(state)(newVariables)
|
||||
return {
|
||||
outgoingEdgeId,
|
||||
newSessionState,
|
||||
}
|
||||
}
|
||||
return {
|
||||
outgoingEdgeId,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { ExecuteIntegrationResponse } from '@/features/chat/types'
|
||||
import { SessionState } from 'models'
|
||||
import { OpenAIBlock } from 'models/features/blocks/integrations/openai'
|
||||
import { createChatCompletionOpenAI } from './createChatCompletionOpenAI'
|
||||
|
||||
export const executeOpenAIBlock = async (
|
||||
state: SessionState,
|
||||
block: OpenAIBlock
|
||||
): Promise<ExecuteIntegrationResponse> => {
|
||||
switch (block.options.task) {
|
||||
case 'Create chat completion':
|
||||
return createChatCompletionOpenAI(state, {
|
||||
options: block.options,
|
||||
outgoingEdgeId: block.outgoingEdgeId,
|
||||
})
|
||||
case 'Create image':
|
||||
case undefined:
|
||||
return { outgoingEdgeId: block.outgoingEdgeId }
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
SendEmailBlock,
|
||||
SendEmailOptions,
|
||||
SessionState,
|
||||
SmtpCredentialsData,
|
||||
SmtpCredentials,
|
||||
} from 'models'
|
||||
import { createTransport } from 'nodemailer'
|
||||
import Mail from 'nodemailer/lib/mailer'
|
||||
@@ -161,7 +161,7 @@ const sendEmail = async ({
|
||||
|
||||
const getEmailInfo = async (
|
||||
credentialsId: string
|
||||
): Promise<SmtpCredentialsData | undefined> => {
|
||||
): Promise<SmtpCredentials['data'] | undefined> => {
|
||||
if (credentialsId === 'default')
|
||||
return {
|
||||
host: defaultTransportOptions.host,
|
||||
@@ -175,7 +175,7 @@ const getEmailInfo = async (
|
||||
where: { id: credentialsId },
|
||||
})
|
||||
if (!credentials) return
|
||||
return decrypt(credentials.data, credentials.iv) as SmtpCredentialsData
|
||||
return decrypt(credentials.data, credentials.iv) as SmtpCredentials['data']
|
||||
}
|
||||
|
||||
const getEmailBody = async ({
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import test, { expect } from '@playwright/test'
|
||||
import { createSmtpCredentials } from '../../../../test/utils/databaseActions'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import { SmtpCredentialsData } from 'models'
|
||||
import { importTypebotInDatabase } from 'utils/playwright/databaseActions'
|
||||
import { getTestAsset } from '@/test/utils/playwright'
|
||||
import { SmtpCredentials } from 'models'
|
||||
|
||||
export const mockSmtpCredentials: SmtpCredentialsData = {
|
||||
export const mockSmtpCredentials: SmtpCredentials['data'] = {
|
||||
from: {
|
||||
email: 'sunny.cremin66@ethereal.email',
|
||||
name: 'Sunny Cremin',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { executeChatwootBlock } from '@/features/blocks/integrations/chatwoot/api'
|
||||
import { executeGoogleAnalyticsBlock } from '@/features/blocks/integrations/googleAnalytics/api'
|
||||
import { executeGoogleSheetBlock } from '@/features/blocks/integrations/googleSheets/api'
|
||||
import { executeOpenAIBlock } from '@/features/blocks/integrations/openai/executeOpenAIBlock'
|
||||
import { executeSendEmailBlock } from '@/features/blocks/integrations/sendEmail/api'
|
||||
import { executeWebhookBlock } from '@/features/blocks/integrations/webhook/api'
|
||||
import { IntegrationBlock, IntegrationBlockType, SessionState } from 'models'
|
||||
@@ -23,5 +24,7 @@ export const executeIntegration =
|
||||
case IntegrationBlockType.MAKE_COM:
|
||||
case IntegrationBlockType.PABBLY_CONNECT:
|
||||
return executeWebhookBlock(state, block)
|
||||
case IntegrationBlockType.OPEN_AI:
|
||||
return executeOpenAIBlock(state, block)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Credentials as CredentialsFromDb } from 'db'
|
||||
import { OAuth2Client, Credentials } from 'google-auth-library'
|
||||
import { GoogleSheetsCredentialsData } from 'models'
|
||||
import { GoogleSheetsCredentials } from 'models'
|
||||
import { isDefined } from 'utils'
|
||||
import { decrypt, encrypt } from 'utils/api'
|
||||
import prisma from './prisma'
|
||||
@@ -15,7 +15,7 @@ export const getAuthenticatedGoogleClient = async (
|
||||
const data = decrypt(
|
||||
credentials.data,
|
||||
credentials.iv
|
||||
) as GoogleSheetsCredentialsData
|
||||
) as GoogleSheetsCredentials['data']
|
||||
|
||||
const oauth2Client = new OAuth2Client(
|
||||
process.env.GOOGLE_CLIENT_ID,
|
||||
@@ -28,14 +28,17 @@ export const getAuthenticatedGoogleClient = async (
|
||||
}
|
||||
|
||||
const updateTokens =
|
||||
(credentialsId: string, existingCredentials: GoogleSheetsCredentialsData) =>
|
||||
(
|
||||
credentialsId: string,
|
||||
existingCredentials: GoogleSheetsCredentials['data']
|
||||
) =>
|
||||
async (credentials: Credentials) => {
|
||||
if (
|
||||
isDefined(existingCredentials.id_token) &&
|
||||
credentials.id_token !== existingCredentials.id_token
|
||||
)
|
||||
return
|
||||
const newCredentials: GoogleSheetsCredentialsData = {
|
||||
const newCredentials: GoogleSheetsCredentials['data'] = {
|
||||
...existingCredentials,
|
||||
expiry_date: credentials.expiry_date,
|
||||
access_token: credentials.access_token,
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
import Stripe from 'stripe'
|
||||
|
||||
import Cors from 'cors'
|
||||
import { PaymentInputOptions, StripeCredentialsData, Variable } from 'models'
|
||||
import { PaymentInputOptions, StripeCredentials, Variable } from 'models'
|
||||
import prisma from '@/lib/prisma'
|
||||
import { parseVariables } from '@/features/variables'
|
||||
|
||||
@@ -103,12 +103,12 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
|
||||
const getStripeInfo = async (
|
||||
credentialsId: string
|
||||
): Promise<StripeCredentialsData | undefined> => {
|
||||
): Promise<StripeCredentials['data'] | undefined> => {
|
||||
const credentials = await prisma.credentials.findUnique({
|
||||
where: { id: credentialsId },
|
||||
})
|
||||
if (!credentials) return
|
||||
return decrypt(credentials.data, credentials.iv) as StripeCredentialsData
|
||||
return decrypt(credentials.data, credentials.iv) as StripeCredentials['data']
|
||||
}
|
||||
|
||||
// https://stripe.com/docs/currencies#zero-decimal
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
PublicTypebot,
|
||||
ResultValues,
|
||||
SendEmailOptions,
|
||||
SmtpCredentialsData,
|
||||
SmtpCredentials,
|
||||
} from 'models'
|
||||
import { NextApiRequest, NextApiResponse } from 'next'
|
||||
import { createTransport, getTestMessageUrl } from 'nodemailer'
|
||||
@@ -155,7 +155,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
|
||||
const getEmailInfo = async (
|
||||
credentialsId: string
|
||||
): Promise<SmtpCredentialsData | undefined> => {
|
||||
): Promise<SmtpCredentials['data'] | undefined> => {
|
||||
if (credentialsId === 'default')
|
||||
return {
|
||||
host: defaultTransportOptions.host,
|
||||
@@ -169,7 +169,7 @@ const getEmailInfo = async (
|
||||
where: { id: credentialsId },
|
||||
})
|
||||
if (!credentials) return
|
||||
return decrypt(credentials.data, credentials.iv) as SmtpCredentialsData
|
||||
return decrypt(credentials.data, credentials.iv) as SmtpCredentials['data']
|
||||
}
|
||||
|
||||
const getEmailBody = async ({
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CredentialsType, SmtpCredentialsData } from 'models'
|
||||
import { PrismaClient } from 'db'
|
||||
import { SmtpCredentials } from 'models'
|
||||
import { encrypt } from 'utils/api'
|
||||
import { proWorkspaceId } from 'utils/playwright/databaseSetup'
|
||||
|
||||
@@ -7,7 +7,7 @@ const prisma = new PrismaClient()
|
||||
|
||||
export const createSmtpCredentials = (
|
||||
id: string,
|
||||
smtpData: SmtpCredentialsData
|
||||
smtpData: SmtpCredentials['data']
|
||||
) => {
|
||||
const { encryptedData, iv } = encrypt(smtpData)
|
||||
return prisma.credentials.create({
|
||||
@@ -16,7 +16,7 @@ export const createSmtpCredentials = (
|
||||
data: encryptedData,
|
||||
iv,
|
||||
name: smtpData.from.email as string,
|
||||
type: CredentialsType.SMTP,
|
||||
type: 'smtp',
|
||||
workspaceId: proWorkspaceId,
|
||||
},
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user