diff --git a/apps/builder/components/editor/StepsSideBar/LearnAutomatedTasks.tsx b/apps/builder/components/editor/StepsSideBar/LearnAutomatedTasks.tsx index 7c63310ac6..d98064098c 100644 --- a/apps/builder/components/editor/StepsSideBar/LearnAutomatedTasks.tsx +++ b/apps/builder/components/editor/StepsSideBar/LearnAutomatedTasks.tsx @@ -107,6 +107,7 @@ const LearnAutomatedTasks = () => { justifyContent="flex-start" onMouseEnter={() => setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} + gap={0} > { const { draggedStepType } = useStepDnd() const [isMouseDown, setIsMouseDown] = useState(false) + const { typebot } = useTypebot() useEffect(() => { setIsMouseDown(draggedStepType === type) @@ -35,10 +37,10 @@ export const StepCard = ({ const handleMouseDown = (e: React.MouseEvent) => onMouseDown(e, type) - const shouldAddGradientBorder = [ - WOZStepType.MESSAGE, - WOZStepType.INTERPRET_DATA_WITH_AI, - ].includes(type as WOZStepType) + const shouldAddGradientBorder = + [WOZStepType.MESSAGE, WOZStepType.INTERPRET_DATA_WITH_AI].includes( + type as WOZStepType + ) && typebot?.availableFor?.includes('automated-tasks') return ( { ) } - const EVENT_AVAILABLE_STEPS: StepType[] = [IntegrationStepType.WEBHOOK] + const EVENT_AVAILABLE_STEPS: StepType[] = [ + IntegrationStepType.WEBHOOK, + WOZStepType.INTERPRET_DATA_WITH_AI, + ] const AUTOMATED_TASKS_AVAILABLE_STEPS: StepType[] = [ WOZStepType.MESSAGE, WOZStepType.INTERPRET_DATA_WITH_AI, diff --git a/apps/builder/components/octaComponents/OctaSelect/OctaSelect.type.ts b/apps/builder/components/octaComponents/OctaSelect/OctaSelect.type.ts index 1bade7cf9c..004547fca2 100644 --- a/apps/builder/components/octaComponents/OctaSelect/OctaSelect.type.ts +++ b/apps/builder/components/octaComponents/OctaSelect/OctaSelect.type.ts @@ -1,35 +1,35 @@ import React, { DetailedHTMLProps, InputHTMLAttributes } from 'react' -import { SELECT_ACTION, SELECT_ACTIONS } from './OctaSelect'; +import { SELECT_ACTION } from './OctaSelect' -export type OctaSelectProps = { - onChange: (value: any, itemFull?: any) => void +export type OctaSelectProps = { + onChange: (value: T, itemFull?: T) => void defaultSelected?: any - label?: string; - findable?: boolean; - options?: Array; - showEdit?: boolean; - showDelete?: boolean; + label?: string + findable?: boolean + options?: Array + showEdit?: boolean + showDelete?: boolean onIconClicked?: (value: any, action: SELECT_ACTION) => {} } & DetailedHTMLProps, HTMLSelectElement> export type OptionProps = { - value: any; - children?: string; - optionKey?: string | number; - isTitle?: boolean; - disabled?: boolean; - selected: any; - showEdit?: boolean; - showDelete?: boolean; + value: any + children?: string + optionKey?: string | number + isTitle?: boolean + disabled?: boolean + selected: any + showEdit?: boolean + showDelete?: boolean onIconClicked?: (value: any, action: SELECT_ACTION) => {} } & DetailedHTMLProps, HTMLLIElement> export type OptionType = { - value: any; - label: string; - isTitle?: boolean; - disabled?: boolean; - key: string | number; - optionKey?: string | number; - subType?: string; + value: any + label: string + isTitle?: boolean + disabled?: boolean + key: string | number + optionKey?: string | number + subType?: string } diff --git a/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/InterpretDataWithAI/InterpretDataWithAI.tsx b/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/InterpretDataWithAI/InterpretDataWithAI.tsx index 7191561ef7..f01bb9cda2 100644 --- a/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/InterpretDataWithAI/InterpretDataWithAI.tsx +++ b/apps/builder/components/shared/Graph/Nodes/StepNode/SettingsPopoverContent/bodies/InterpretDataWithAI/InterpretDataWithAI.tsx @@ -12,13 +12,19 @@ import { Spinner, HStack, } from '@chakra-ui/react' -import { IntegrationStepType, WOZInterpretDataWithAIOptions } from 'models' -import { useMemo, useState, useRef, useEffect } from 'react' +import { + IntegrationStepType, + WOZInterpretDataWithAIOptions, + WOZInterpretDataWithAIResponseFormat, +} from 'models' +import { useMemo, useState, useRef } from 'react' import { useInterpretDataWithAI } from 'hooks/InterpretDataWithAI/useInterpretDataWithAI' import { VariablesMenu } from './VariablesMenu' import { MdInfoOutline } from 'react-icons/md' import { WOZInterpretDataWithAI } from 'models' import { getDeepKeys } from 'services/integrations' +import { useTypebot } from 'contexts/TypebotContext' +import OctaSelect from 'components/octaComponents/OctaSelect/OctaSelect' type Props = { step: WOZInterpretDataWithAI @@ -34,6 +40,9 @@ export const InterpretDataWithAI = ({ step, onContentChange }: Props) => { testReturn, refetch, } = useInterpretDataWithAI({ step }) + + const { typebot } = useTypebot() + const isAutomatedTasksBot = typebot?.availableFor.includes('automated-tasks') const [isTesting, setIsTesting] = useState(false) const [resultOfInterpretWithAi, setResultOfInterpretWithAi] = @@ -78,6 +87,13 @@ export const InterpretDataWithAI = ({ step, onContentChange }: Props) => { }, 0) } + const stepDescription = useMemo(() => { + if (isAutomatedTasksBot) { + return 'Defina como a IA deve apresentar os dados coletados na conversa.' + } + return 'Defina como a IA deve apresentar os dados coletados para o próximo passo do fluxo.' + }, []) + const placeholderInstructions = useMemo(() => { return `Ex: Retorne ao cliente a lista dos tickets encontrados. \b\b @@ -85,6 +101,16 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }}, {{ criado-em }}` }, []) + const placeholderInstructionsEvents = useMemo(() => { + if ( + step?.content?.responseFormat === + WOZInterpretDataWithAIResponseFormat.JSON + ) { + return `Ex: Crie um JSON com os dados do ticket. Use as variáveis: {ticked_id}, {assunto}, {responsavel}, {data_de_criacao}` + } + return `Ex: Gere um resumo das informações coletadas, listando o motivo do contato, o status atual e a data de abertura.` + }, [step?.content?.responseFormat]) + const tooltipInstructions = useMemo(() => { return `Como instruir a IA?
    @@ -94,6 +120,27 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }},
` }, []) + const tooltipInstructionsEvents = useMemo(() => { + return `Como instruir a IA? +
    +
  1. Defina a estrutura de dados (ex: um JSON) que o próximo passo do fluxo deve receber.
  2. +
  3. Escreva manualmente o nome das variáveis capturadas nos passos anteriores usando chaves, como {nome_da_variavel}.
  4. +
  5. Este campo é técnico: a IA usará suas instruções para organizar as informações antes de enviá-las ao sistema, sem que o cliente veja este texto.
  6. +
` + }, []) + + const tooltipInstructionsResponseFormat = useMemo(() => { + return `Mensagem natural (texto): +
+ Quando a informação for usada como um texto simples ou resumo em etapas posteriores do fluxo. +
+
+ JSON (estrutura): +
+ Quando o próximo passo é uma integração/sistema externo e é preciso transformar informação em código para enviar para outro sistema. + ` + }, []) + const responseKeys = useMemo( () => getDeepKeys(data?.response || {}), [data?.response] @@ -122,6 +169,30 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }}, } } + const handleSelectResponseFormat = ( + value: WOZInterpretDataWithAIResponseFormat + ) => { + onContentChange({ + ...step.content, + responseFormat: value, + }) + } + + const responseFormatOptions = useMemo(() => { + return [ + { + key: 'json', + label: 'JSON', + value: WOZInterpretDataWithAIResponseFormat.JSON, + }, + { + key: 'text', + label: 'Mensagem natural', + value: WOZInterpretDataWithAIResponseFormat.TEXT, + }, + ] + }, []) + const componentToRender = useMemo(() => { if (whoIsConnectedOnMyBlock?.length <= 0) { return ( @@ -133,7 +204,10 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }}, if (whoIsConnectedOnMyBlock?.length === 1) { const block = whoIsConnectedOnMyBlock[0] - if (block.steps[0].type !== IntegrationStepType.WEBHOOK) + if ( + block.steps[0].type !== IntegrationStepType.WEBHOOK && + isAutomatedTasksBot + ) return ( @@ -148,8 +222,11 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }}, return ( - Este bloco deve receber apenas uma conexão, sendo esta conexão um - componente chamado "Conecte a outro sistema" + Este bloco deve receber apenas uma conexão{' '} + {isAutomatedTasksBot + ? `, sendo esta conexão um + componente chamado "Conecte a outro sistema"` + : ''} ) @@ -164,7 +241,7 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }}, ) } - if (!success) { + if (!success && isAutomatedTasksBot) { return ( @@ -179,18 +256,52 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }}, } return ( - - - Defina como a IA deve apresentar os dados coletados na conversa. - - + + {stepDescription} + {!isAutomatedTasksBot && ( + + + Formato de saída + + } + hasArrow + > + + + + + + + )} + {!isAutomatedTasksBot && ( + + )} Instruções de retorno } hasArrow @@ -208,7 +319,11 @@ Use as variáveis: {{ numero-ticket }}, {{ status-ticket }},