@@ -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) ?? [],
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -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<OpenAIBlock['options']>['task']
|
||||
responseMapping:
|
||||
| ChatCompletionOpenAIOptions['responseMapping']
|
||||
| CreateImageOpenAIOptions['responseMapping']
|
||||
options: OpenAIBlock['options']
|
||||
}
|
||||
|
||||
export const OpenAINodeBody = ({ task, responseMapping }: Props) => {
|
||||
export const OpenAINodeBody = ({ options }: Props) => {
|
||||
const { typebot } = useTypebot()
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
<Text color={task ? 'currentcolor' : 'gray.500'} noOfLines={1}>
|
||||
{task ?? 'Configure...'}
|
||||
<Text color={options?.task ? 'currentcolor' : 'gray.500'} noOfLines={1}>
|
||||
{options?.task ?? 'Configure...'}
|
||||
</Text>
|
||||
{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 && (
|
||||
<SetVariableLabel
|
||||
variables={typebot.variables}
|
||||
variableId={options.saveUrlInVariableId}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<OpenAICreateSpeechSettings
|
||||
options={options}
|
||||
onOptionsChange={onOptionsChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case 'Create image': {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -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<Variable, 'id' | 'name'> | undefined
|
||||
) => {
|
||||
onOptionsChange({
|
||||
...options,
|
||||
saveUrlInVariableId: variable?.id,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack spacing={4} pt="2">
|
||||
<Text fontSize="sm" color="gray.500">
|
||||
Read the{' '}
|
||||
<TextLink href={apiReferenceUrl} isExternal>
|
||||
API reference
|
||||
</TextLink>{' '}
|
||||
to better understand the available options.
|
||||
</Text>
|
||||
{options.credentialsId && (
|
||||
<>
|
||||
<ModelsDropdown
|
||||
credentialsId={options.credentialsId}
|
||||
defaultValue={options.model}
|
||||
baseUrl={options.baseUrl}
|
||||
apiVersion={options.apiVersion}
|
||||
type="tts"
|
||||
onChange={updateModel}
|
||||
/>
|
||||
<Textarea
|
||||
defaultValue={options.input}
|
||||
onChange={updateInput}
|
||||
label="Input:"
|
||||
/>
|
||||
<FormControl>
|
||||
<FormLabel>Voice:</FormLabel>
|
||||
<DropdownList
|
||||
currentItem={options.voice}
|
||||
onItemSelect={updateVoice}
|
||||
items={openAIVoices}
|
||||
placeholder="Select a voice"
|
||||
w="full"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormControl>
|
||||
<FormLabel>Save URL:</FormLabel>
|
||||
<VariableSearchInput
|
||||
initialVariableId={options.saveUrlInVariableId}
|
||||
onSelectVariable={updateSaveUrlInVariableId}
|
||||
/>
|
||||
</FormControl>
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { TextLink } from '@/components/TextLink'
|
||||
import { ChatCompletionResponseItem } from './ChatCompletionResponseItem'
|
||||
import { NumberInput } from '@/components/inputs'
|
||||
import { ModelsDropdown } from './ModelsDropdown'
|
||||
import { ModelsDropdown } from '../ModelsDropdown'
|
||||
|
||||
const apiReferenceUrl =
|
||||
'https://platform.openai.com/docs/api-reference/chat/create'
|
||||
@@ -79,6 +79,7 @@ export const OpenAIChatCompletionSettings = ({
|
||||
defaultValue={options.model}
|
||||
baseUrl={options.baseUrl}
|
||||
apiVersion={options.apiVersion}
|
||||
type="gpt"
|
||||
onChange={updateModel}
|
||||
/>
|
||||
<Accordion allowMultiple>
|
||||
|
||||
@@ -145,16 +145,7 @@ export const BlockNodeContent = ({
|
||||
return <ChatwootNodeBody block={block} />
|
||||
}
|
||||
case IntegrationBlockType.OPEN_AI: {
|
||||
return (
|
||||
<OpenAINodeBody
|
||||
task={block.options?.task}
|
||||
responseMapping={
|
||||
block.options && 'responseMapping' in block.options
|
||||
? block.options.responseMapping
|
||||
: []
|
||||
}
|
||||
/>
|
||||
)
|
||||
return <OpenAINodeBody options={block.options} />
|
||||
}
|
||||
case IntegrationBlockType.PIXEL: {
|
||||
return <PixelNodeBody options={block.options} />
|
||||
|
||||
@@ -94,6 +94,14 @@ export const templates: TemplateProps[] = [
|
||||
description:
|
||||
'A bot that uses the ChatGPT model to generate responses based on the user input',
|
||||
},
|
||||
{
|
||||
name: 'Audio ChatGPT',
|
||||
emoji: '🤖',
|
||||
fileName: 'audio-chat-gpt.json',
|
||||
description:
|
||||
'An audio AI bot that uses the OpenAI block to generate responses based on the user input',
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
name: 'ChatGPT personas',
|
||||
emoji: '🎭',
|
||||
@@ -117,4 +125,12 @@ export const templates: TemplateProps[] = [
|
||||
description:
|
||||
'You are a dog insurance company. This bot allows you to collect information about the dog and provide a quote.',
|
||||
},
|
||||
{
|
||||
name: 'OpenAI conditions',
|
||||
emoji: '🧠',
|
||||
fileName: 'openai-conditions.json',
|
||||
isNew: true,
|
||||
description:
|
||||
'This is an example of how you can use the OpenAI block to take smart decisions based on the user input and redirect the conversation to the right path.',
|
||||
},
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user