From 1a44bf4935a131010e912e9c7d0ba9127b55be83 Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Mon, 20 Nov 2023 10:32:38 +0100 Subject: [PATCH] :sparkles: (openai) Add create speech OpenAI action Closes #1025 --- apps/builder/package.json | 2 +- .../public/templates/audio-chat-gpt.json | 206 ++++++ .../public/templates/openai-conditions.json | 290 ++++++++ .../integrations/openai/api/listModels.ts | 4 +- .../ModelsDropdown.tsx | 3 + .../openai/components/OpenAINodeBody.tsx | 30 +- .../openai/components/OpenAISettings.tsx | 30 +- .../audio/OpenAICreateSpeechSettings.tsx | 98 +++ .../OpenAIChatCompletionSettings.tsx | 3 +- .../nodes/block/BlockNodeContent.tsx | 11 +- apps/builder/src/features/templates/data.ts | 16 + .../editor/blocks/integrations/openai.mdx | 31 +- apps/docs/openapi/builder/_spec_.json | 628 ++++++++++++++++++ apps/docs/openapi/chat/_spec_.json | 264 ++++++++ apps/viewer/package.json | 4 +- .../openai/audio/createSpeechOpenAI.ts | 121 ++++ .../integrations/openai/executeOpenAIBlock.ts | 6 + .../openai/parseChatCompletionMessages.ts | 5 +- packages/bot-engine/package.json | 4 +- packages/lib/s3/uploadFileToBucket.ts | 15 +- .../blocks/integrations/openai/constants.ts | 15 +- .../blocks/integrations/openai/schema.ts | 26 +- pnpm-lock.yaml | 34 +- 23 files changed, 1772 insertions(+), 74 deletions(-) create mode 100644 apps/builder/public/templates/audio-chat-gpt.json create mode 100644 apps/builder/public/templates/openai-conditions.json rename apps/builder/src/features/blocks/integrations/openai/components/{createChatCompletion => }/ModelsDropdown.tsx (96%) create mode 100644 apps/builder/src/features/blocks/integrations/openai/components/audio/OpenAICreateSpeechSettings.tsx create mode 100644 packages/bot-engine/blocks/integrations/openai/audio/createSpeechOpenAI.ts diff --git a/apps/builder/package.json b/apps/builder/package.json index 4bce6bff9..ec90f7db5 100644 --- a/apps/builder/package.json +++ b/apps/builder/package.json @@ -74,7 +74,7 @@ "nextjs-cors": "2.1.2", "nodemailer": "6.9.3", "nprogress": "0.2.0", - "openai": "4.11.1", + "openai": "4.19.0", "papaparse": "5.4.1", "posthog-js": "1.77.1", "posthog-node": "3.1.1", diff --git a/apps/builder/public/templates/audio-chat-gpt.json b/apps/builder/public/templates/audio-chat-gpt.json new file mode 100644 index 000000000..189b91a8e --- /dev/null +++ b/apps/builder/public/templates/audio-chat-gpt.json @@ -0,0 +1,206 @@ +{ + "version": "6", + "id": "clp6onbn200011ab379x5gnea", + "name": "Audio ChatGPT", + "icon": "🔈", + "events": [ + { + "id": "ewnfbo0exlu7ihfu2lu2lusm", + "outgoingEdgeId": "knz1ln1so0dfyth76qjkjn1p", + "graphCoordinates": { "x": -228.25, "y": -123.31 }, + "type": "start" + } + ], + "groups": [ + { + "id": "qfrz5nwm63g12dajsjxothb5", + "title": "User input", + "graphCoordinates": { "x": 105.17, "y": -56.29 }, + "blocks": [ + { + "id": "ovgk70u0kfxrbtz9dy4e040o", + "type": "text input", + "options": { "variableId": "vudksu3zyrat6s1bq6qne0rx3" } + }, + { + "id": "m4jadtknjb3za3gvxj1xdn1k", + "outgoingEdgeId": "fpj0xacppqd1s5slyljzhzc9", + "type": "Set variable", + "options": { + "variableId": "vabkycu0qqff5d6ar2ama16pf", + "type": "Append value(s)", + "item": "{{User Message}}" + } + } + ] + }, + { + "id": "a6ymhjwtkqwp8t127plz8qmk", + "title": "ChatGPT reply", + "graphCoordinates": { "x": 445.12, "y": -56.2 }, + "blocks": [ + { + "id": "xikptnw1lp1qxdqo10qhmwy1", + "type": "OpenAI", + "options": { + "task": "Create chat completion", + "model": "gpt-3.5-turbo", + "messages": [ + { + "id": "wsdxha9db58gk2v9n1j10m7c", + "role": "Dialogue", + "dialogueVariableId": "vabkycu0qqff5d6ar2ama16pf", + "startsBy": "user" + } + ], + "responseMapping": [ + { + "id": "p8ksqi2jhyzid2od3dikv299", + "valueToExtract": "Message content", + "variableId": "vni6kwbch8zlq92dclgcivzyr" + } + ], + "credentialsId": "clp6ooc3700031ab30yof27jm" + } + }, + { + "id": "yblc864bzipaqfja7b2o3oo0", + "type": "Set variable", + "options": { + "variableId": "vabkycu0qqff5d6ar2ama16pf", + "type": "Append value(s)", + "item": "{{Assistant Message}}" + } + }, + { + "id": "prsimdxdol42ty2parzgx8am", + "type": "OpenAI", + "options": { + "credentialsId": "clp6ooc3700031ab30yof27jm", + "task": "Create speech", + "model": "tts-1", + "input": "{{Assistant Message}}", + "voice": "alloy", + "saveUrlInVariableId": "vgr0iwg95npp7pztkmdyn89m1" + } + }, + { + "id": "f6onszqys2tx7pw3tshb2vcy", + "outgoingEdgeId": "dw9jclv60i040saiikj3a386", + "type": "audio", + "content": { "url": "{{Assistant audio message}}" } + } + ] + }, + { + "id": "c5f00f3oclwi1srcz10jjt9u", + "title": "Intro", + "graphCoordinates": { "x": -222.61, "y": -54.39 }, + "blocks": [ + { + "id": "dp5gx25j73fgmcj9582ydik9", + "type": "OpenAI", + "options": { + "credentialsId": "clp6ooc3700031ab30yof27jm", + "task": "Create speech", + "model": "tts-1", + "input": "Hi there! How can I help?", + "voice": "alloy", + "saveUrlInVariableId": "vxw4quja426402hvhtm33tsp3" + } + }, + { + "id": "dmab8kc35uh84vvw1a53xbjn", + "outgoingEdgeId": "xnao10ucc1hbynv3pmk1t4by", + "type": "audio", + "content": { "url": "{{Welcome audio}}" } + } + ] + }, + { + "id": "yswu9fml4zflxaqlujb94ir8", + "title": "", + "graphCoordinates": { "x": 19.51, "y": -338.93 }, + "blocks": [ + { + "id": "okm2zz32zn8b60u1vkfrv9ca", + "type": "text", + "content": { + "richText": [ + { + "type": "p", + "children": [ + { + "text": "You need to add your OpenAI credentials to make this bot work. 🪄" + } + ] + } + ] + } + }, + { + "id": "m5a1d0vhsrpyvvvyj89awxzc", + "type": "text", + "content": { + "richText": [ + { + "type": "p", + "children": [ + { + "text": "Once it's done, delete this group and connect the " + }, + { "text": "Start", "bold": true }, + { "text": " event with " }, + { "text": "Intro", "bold": true }, + { "text": " 🚀\n" } + ] + } + ] + } + } + ] + } + ], + "edges": [ + { + "id": "fpj0xacppqd1s5slyljzhzc9", + "from": { "blockId": "m4jadtknjb3za3gvxj1xdn1k" }, + "to": { "groupId": "a6ymhjwtkqwp8t127plz8qmk" } + }, + { + "id": "xnao10ucc1hbynv3pmk1t4by", + "from": { "blockId": "dmab8kc35uh84vvw1a53xbjn" }, + "to": { "groupId": "qfrz5nwm63g12dajsjxothb5" } + }, + { + "id": "dw9jclv60i040saiikj3a386", + "from": { "blockId": "f6onszqys2tx7pw3tshb2vcy" }, + "to": { "groupId": "qfrz5nwm63g12dajsjxothb5" } + }, + { + "from": { "eventId": "ewnfbo0exlu7ihfu2lu2lusm" }, + "to": { "groupId": "yswu9fml4zflxaqlujb94ir8" }, + "id": "knz1ln1so0dfyth76qjkjn1p" + } + ], + "variables": [ + { "id": "vni6kwbch8zlq92dclgcivzyr", "name": "Assistant Message" }, + { "id": "vudksu3zyrat6s1bq6qne0rx3", "name": "User Message" }, + { "id": "vabkycu0qqff5d6ar2ama16pf", "name": "Chat history" }, + { "id": "vxw4quja426402hvhtm33tsp3", "name": "Welcome audio" }, + { "id": "vgr0iwg95npp7pztkmdyn89m1", "name": "Assistant audio message" } + ], + "theme": {}, + "selectedThemeTemplateId": null, + "settings": {}, + "createdAt": "2023-11-20T09:06:40.430Z", + "updatedAt": "2023-11-20T09:20:01.662Z", + "folderId": null, + "publicId": null, + "customDomain": null, + "workspaceId": "freeWorkspace", + "resultsTablePreferences": null, + "isArchived": false, + "isClosed": false, + "whatsAppCredentialsId": null +} diff --git a/apps/builder/public/templates/openai-conditions.json b/apps/builder/public/templates/openai-conditions.json new file mode 100644 index 000000000..6fe7fc374 --- /dev/null +++ b/apps/builder/public/templates/openai-conditions.json @@ -0,0 +1,290 @@ +{ + "version": "6", + "id": "clp6pe8dy00051ab3n6coxt62", + "name": "ChatGPT condition", + "events": [ + { + "id": "ewnfbo0exlu7ihfu2lu2lusm", + "outgoingEdgeId": "gj1gs8hdembrsw84aafd1hbj", + "graphCoordinates": { "x": -228.25, "y": -123.31 }, + "type": "start" + } + ], + "groups": [ + { + "id": "qfrz5nwm63g12dajsjxothb5", + "title": "User input", + "graphCoordinates": { "x": -107.01, "y": -53.23 }, + "blocks": [ + { + "id": "emjcjxlvzm2xex10exq4wf5h", + "type": "text", + "content": { + "richText": [ + { "type": "p", "children": [{ "text": "How can we help?" }] } + ] + } + }, + { + "id": "ovgk70u0kfxrbtz9dy4e040o", + "outgoingEdgeId": "n396v90ad7quz0gwygr6n5fc", + "type": "text input", + "options": { "variableId": "vudksu3zyrat6s1bq6qne0rx3" } + } + ] + }, + { + "id": "bh3uva3254p0jgp46gj92way", + "title": "Condition 🧠", + "graphCoordinates": { "x": 228.67, "y": -50.67 }, + "blocks": [ + { + "id": "wdg7upk4oqp602jqjn06gjf6", + "type": "OpenAI", + "options": { + "task": "Create chat completion", + "model": "gpt-4-1106-preview", + "messages": [ + { + "id": "s7s7uaurqlmsn3r89c10mk98", + "role": "system", + "content": "You are helpful assistant doing customer support for a software called Typebot.\n\nIf the user is asking a question about his account, please say \"ACCOUNT\".\n\nIf the user wants to talk to a human, please say \"HUMAN\".\n\nOtherwise, say \"OK\"" + }, + { + "id": "zrgypmt1wlogakfl06gfxpgk", + "role": "user", + "content": "Can I talk to a human?" + }, + { + "id": "i6ldg74yr9n185oumozb3r6b", + "role": "assistant", + "content": "HUMAN" + }, + { + "id": "eoxa3dxtw8wjdyv9efnxryxk", + "role": "user", + "content": "I need to check my account" + }, + { + "id": "nb7sy9x7g07w5s1sxb83v295", + "role": "assistant", + "content": "ACCOUNT" + }, + { + "id": "zazen7p0cyawtix7der2e923", + "role": "user", + "content": "{{User Message}}" + } + ], + "responseMapping": [ + { + "id": "s7s7uaurqlmsn3r89c10mk98", + "valueToExtract": "Message content", + "variableId": "vni6kwbch8zlq92dclgcivzyr" + } + ] + } + }, + { + "id": "b63f0et5y70mragfcrmezifh", + "outgoingEdgeId": "wkecv7zg757mbsnbfdej6uph", + "type": "Condition", + "items": [ + { + "id": "d0bax1yf18x2bj5zt38vr6xs", + "outgoingEdgeId": "optu30rn5vjiwueijh0utvoi", + "content": { + "comparisons": [ + { + "id": "iiv6h6ssgusrfza4vped0iqe", + "variableId": "vni6kwbch8zlq92dclgcivzyr", + "comparisonOperator": "Contains", + "value": "ACCOUNT" + } + ] + } + }, + { + "id": "ulf15sjzk9b7df95rzaqe40j", + "outgoingEdgeId": "ft02qowy1n8uy2k5dzdo0j22", + "content": { + "comparisons": [ + { + "id": "qekpq2av325h7rkmnrvtumxn", + "variableId": "vni6kwbch8zlq92dclgcivzyr", + "comparisonOperator": "Contains", + "value": "HUMAN" + } + ] + } + } + ] + } + ] + }, + { + "id": "flt2vtb4pb6mvlvyrrxonzwf", + "title": "Account", + "graphCoordinates": { "x": 585.48, "y": -214.13 }, + "blocks": [ + { + "id": "h45t9e5yxc2fpfiv49gvmwjj", + "type": "text", + "content": { + "richText": [ + { + "type": "p", + "children": [ + { "text": "Ok feel free to check your account here" } + ] + } + ] + } + }, + { + "id": "fn0s0ezabail96c5n0xs24aq", + "type": "choice input", + "items": [{ "id": "tslv59v8oqbfpnd21la8qnz4", "content": "Account" }] + }, + { + "id": "r16g3avw7mwzi12srqisuex0", + "type": "Redirect", + "options": { "url": "https://google.com" } + } + ] + }, + { + "id": "jn9w80afa6a66czzjfto8tmt", + "title": "Human", + "graphCoordinates": { "x": 586.68, "y": 153.73 }, + "blocks": [ + { + "id": "nvkp4zm7f24b0g3b25u3rb59", + "type": "text", + "content": { + "richText": [ + { "type": "p", "children": [{ "text": "I'm a human" }] } + ] + } + } + ] + }, + { + "id": "el01d0j1db9kp6v8wlrk9dob", + "title": "Else", + "graphCoordinates": { "x": 581.46, "y": 315.66 }, + "blocks": [ + { + "id": "tpy9wjrwmhw16xjgs8htao04", + "type": "text", + "content": { + "richText": [{ "type": "p", "children": [{ "text": "Else" }] }] + } + } + ] + }, + { + "id": "vafybpsjqcbrbbhi8pwl0gic", + "title": "", + "graphCoordinates": { "x": 6.52, "y": -346.17 }, + "blocks": [ + { + "id": "q1tc6z6xfl4jtrxdvv8phgil", + "type": "text", + "content": { + "richText": [ + { + "type": "p", + "children": [ + { + "text": "You need to add your OpenAI credentials to make this bot work. 🪄\n" + } + ] + } + ] + } + }, + { + "id": "b3ahk7pzsh4abp3bkdlijc0v", + "type": "text", + "content": { + "richText": [ + { + "type": "p", + "children": [ + { + "text": "Once it's done, delete this group and connect the " + }, + { "text": "Start", "bold": true }, + { "text": " event with " }, + { "text": "Intro", "bold": true }, + { "text": " 🚀\n" } + ] + } + ] + } + } + ] + } + ], + "edges": [ + { + "id": "h5sk58j0ryrxmfv4gmw7r4dw", + "from": { "blockId": "gphm5wy1md9cunwkdtbzg6nq" }, + "to": { "groupId": "qfrz5nwm63g12dajsjxothb5" } + }, + { + "id": "y8ml9ljnsydol9b42fd9zdve", + "from": { "blockId": "myldn1l1nfdwwm8qvza71rwv" }, + "to": { "groupId": "qfrz5nwm63g12dajsjxothb5" } + }, + { + "id": "optu30rn5vjiwueijh0utvoi", + "from": { + "blockId": "b63f0et5y70mragfcrmezifh", + "itemId": "d0bax1yf18x2bj5zt38vr6xs" + }, + "to": { "groupId": "flt2vtb4pb6mvlvyrrxonzwf" } + }, + { + "id": "ft02qowy1n8uy2k5dzdo0j22", + "from": { + "blockId": "b63f0et5y70mragfcrmezifh", + "itemId": "ulf15sjzk9b7df95rzaqe40j" + }, + "to": { "groupId": "jn9w80afa6a66czzjfto8tmt" } + }, + { + "id": "wkecv7zg757mbsnbfdej6uph", + "from": { "blockId": "b63f0et5y70mragfcrmezifh" }, + "to": { "groupId": "el01d0j1db9kp6v8wlrk9dob" } + }, + { + "id": "n396v90ad7quz0gwygr6n5fc", + "from": { "blockId": "ovgk70u0kfxrbtz9dy4e040o" }, + "to": { "groupId": "bh3uva3254p0jgp46gj92way" } + }, + { + "from": { "eventId": "ewnfbo0exlu7ihfu2lu2lusm" }, + "to": { "groupId": "vafybpsjqcbrbbhi8pwl0gic" }, + "id": "gj1gs8hdembrsw84aafd1hbj" + } + ], + "variables": [ + { "id": "vni6kwbch8zlq92dclgcivzyr", "name": "Assistant Message" }, + { "id": "vudksu3zyrat6s1bq6qne0rx3", "name": "User Message" } + ], + "theme": {}, + "selectedThemeTemplateId": null, + "settings": {}, + "createdAt": "2023-11-20T09:27:35.926Z", + "updatedAt": "2023-11-20T09:27:59.586Z", + "icon": "🧠", + "folderId": null, + "publicId": null, + "customDomain": null, + "resultsTablePreferences": null, + "isArchived": false, + "isClosed": false, + "whatsAppCredentialsId": null +} diff --git a/apps/builder/src/features/blocks/integrations/openai/api/listModels.ts b/apps/builder/src/features/blocks/integrations/openai/api/listModels.ts index a8181ae84..792d28633 100644 --- a/apps/builder/src/features/blocks/integrations/openai/api/listModels.ts +++ b/apps/builder/src/features/blocks/integrations/openai/api/listModels.ts @@ -25,6 +25,7 @@ export const listModels = authenticatedProcedure workspaceId: z.string(), baseUrl: z.string(), apiVersion: z.string().optional(), + type: z.enum(['gpt', 'tts']), }) ) .output( @@ -34,7 +35,7 @@ export const listModels = authenticatedProcedure ) .query( async ({ - input: { credentialsId, workspaceId, baseUrl, apiVersion }, + input: { credentialsId, workspaceId, baseUrl, apiVersion, type }, ctx: { user }, }) => { const workspace = await prisma.workspace.findFirst({ @@ -97,6 +98,7 @@ export const listModels = authenticatedProcedure return { models: models.data + .filter((model) => model.id.includes(type)) .sort((a, b) => b.created - a.created) .map((model) => model.id) ?? [], } diff --git a/apps/builder/src/features/blocks/integrations/openai/components/createChatCompletion/ModelsDropdown.tsx b/apps/builder/src/features/blocks/integrations/openai/components/ModelsDropdown.tsx similarity index 96% rename from apps/builder/src/features/blocks/integrations/openai/components/createChatCompletion/ModelsDropdown.tsx rename to apps/builder/src/features/blocks/integrations/openai/components/ModelsDropdown.tsx index e6810436f..95277f611 100644 --- a/apps/builder/src/features/blocks/integrations/openai/components/createChatCompletion/ModelsDropdown.tsx +++ b/apps/builder/src/features/blocks/integrations/openai/components/ModelsDropdown.tsx @@ -9,6 +9,7 @@ type Props = { apiVersion?: string credentialsId: string defaultValue?: string + type: 'gpt' | 'tts' onChange: (model: string | undefined) => void } @@ -18,6 +19,7 @@ export const ModelsDropdown = ({ defaultValue, onChange, credentialsId, + type, }: Props) => { const { workspace } = useWorkspace() const { showToast } = useToast() @@ -28,6 +30,7 @@ export const ModelsDropdown = ({ baseUrl: baseUrl ?? defaultOpenAIOptions.baseUrl, workspaceId: workspace?.id as string, apiVersion, + type, }, { enabled: !!workspace, diff --git a/apps/builder/src/features/blocks/integrations/openai/components/OpenAINodeBody.tsx b/apps/builder/src/features/blocks/integrations/openai/components/OpenAINodeBody.tsx index 2825a213f..f66cd81ac 100644 --- a/apps/builder/src/features/blocks/integrations/openai/components/OpenAINodeBody.tsx +++ b/apps/builder/src/features/blocks/integrations/openai/components/OpenAINodeBody.tsx @@ -1,29 +1,24 @@ import { SetVariableLabel } from '@/components/SetVariableLabel' import { useTypebot } from '@/features/editor/providers/TypebotProvider' import { Stack, Text } from '@chakra-ui/react' -import { - ChatCompletionOpenAIOptions, - CreateImageOpenAIOptions, - OpenAIBlock, -} from '@typebot.io/schemas/features/blocks/integrations/openai' +import { OpenAIBlock } from '@typebot.io/schemas/features/blocks/integrations/openai' type Props = { - task: NonNullable['task'] - responseMapping: - | ChatCompletionOpenAIOptions['responseMapping'] - | CreateImageOpenAIOptions['responseMapping'] + options: OpenAIBlock['options'] } -export const OpenAINodeBody = ({ task, responseMapping }: Props) => { +export const OpenAINodeBody = ({ options }: Props) => { const { typebot } = useTypebot() return ( - - {task ?? 'Configure...'} + + {options?.task ?? 'Configure...'} {typebot && - responseMapping + options && + 'responseMapping' in options && + options.responseMapping ?.map((mapping) => mapping.variableId) .map((variableId, idx) => variableId ? ( @@ -34,6 +29,15 @@ export const OpenAINodeBody = ({ task, responseMapping }: Props) => { /> ) : null )} + {typebot && + options && + 'saveUrlInVariableId' in options && + options.saveUrlInVariableId && ( + + )} ) } diff --git a/apps/builder/src/features/blocks/integrations/openai/components/OpenAISettings.tsx b/apps/builder/src/features/blocks/integrations/openai/components/OpenAISettings.tsx index 39f562da7..f1e28e37b 100644 --- a/apps/builder/src/features/blocks/integrations/openai/components/OpenAISettings.tsx +++ b/apps/builder/src/features/blocks/integrations/openai/components/OpenAISettings.tsx @@ -13,6 +13,7 @@ import { CredentialsDropdown } from '@/features/credentials/components/Credentia import { ChatCompletionOpenAIOptions, CreateImageOpenAIOptions, + CreateSpeechOpenAIOptions, OpenAIBlock, } from '@typebot.io/schemas/features/blocks/integrations/openai' import { OpenAICredentialsModal } from './OpenAICredentialsModal' @@ -24,6 +25,7 @@ import { defaultOpenAIOptions, openAITasks, } from '@typebot.io/schemas/features/blocks/integrations/openai/constants' +import { OpenAICreateSpeechSettings } from './audio/OpenAICreateSpeechSettings' type OpenAITask = (typeof openAITasks)[number] @@ -47,15 +49,10 @@ export const OpenAISettings = ({ } const updateTask = (task: OpenAITask) => { - switch (task) { - case 'Create chat completion': { - onOptionsChange({ - credentialsId: options?.credentialsId, - task, - }) - break - } - } + onOptionsChange({ + credentialsId: options?.credentialsId, + task, + } as OpenAIBlock['options']) } const updateBaseUrl = (baseUrl: string) => { @@ -142,9 +139,12 @@ const OpenAITaskSettings = ({ options, onOptionsChange, }: { - options: ChatCompletionOpenAIOptions | CreateImageOpenAIOptions + options: + | ChatCompletionOpenAIOptions + | CreateImageOpenAIOptions + | CreateSpeechOpenAIOptions onOptionsChange: (options: OpenAIBlock['options']) => void -}) => { +}): JSX.Element | null => { switch (options.task) { case 'Create chat completion': { return ( @@ -154,6 +154,14 @@ const OpenAITaskSettings = ({ /> ) } + case 'Create speech': { + return ( + + ) + } case 'Create image': { return null } diff --git a/apps/builder/src/features/blocks/integrations/openai/components/audio/OpenAICreateSpeechSettings.tsx b/apps/builder/src/features/blocks/integrations/openai/components/audio/OpenAICreateSpeechSettings.tsx new file mode 100644 index 000000000..9a6efaad1 --- /dev/null +++ b/apps/builder/src/features/blocks/integrations/openai/components/audio/OpenAICreateSpeechSettings.tsx @@ -0,0 +1,98 @@ +import { CreateSpeechOpenAIOptions } from '@typebot.io/schemas/features/blocks/integrations/openai' +import { FormControl, FormLabel, Stack, Text } from '@chakra-ui/react' +import { TextLink } from '@/components/TextLink' +import { ModelsDropdown } from '../ModelsDropdown' +import { Textarea } from '@/components/inputs' +import { DropdownList } from '@/components/DropdownList' +import { openAIVoices } from '@typebot.io/schemas/features/blocks/integrations/openai/constants' +import { VariableSearchInput } from '@/components/inputs/VariableSearchInput' +import { Variable } from '@typebot.io/schemas' + +const apiReferenceUrl = + 'https://platform.openai.com/docs/api-reference/audio/createSpeech' + +type Props = { + options: CreateSpeechOpenAIOptions + onOptionsChange: (options: CreateSpeechOpenAIOptions) => void +} + +export const OpenAICreateSpeechSettings = ({ + options, + onOptionsChange, +}: Props) => { + const updateModel = (model: string | undefined) => { + onOptionsChange({ + ...options, + model, + }) + } + + const updateInput = (input: string | undefined) => { + onOptionsChange({ + ...options, + input, + }) + } + + const updateVoice = (voice: (typeof openAIVoices)[number]) => { + onOptionsChange({ + ...options, + voice, + }) + } + + const updateSaveUrlInVariableId = ( + variable: Pick | undefined + ) => { + onOptionsChange({ + ...options, + saveUrlInVariableId: variable?.id, + }) + } + + return ( + + + Read the{' '} + + API reference + {' '} + to better understand the available options. + + {options.credentialsId && ( + <> + +