2
0

Remove ZemanticAI block

Closes #1656, closes #1652
This commit is contained in:
Baptiste Arnaud
2024-07-22 17:24:02 +02:00
parent 71d09cdf7c
commit ec2a53fac1
50 changed files with 5 additions and 1821 deletions

View File

@ -1,47 +0,0 @@
import { Select } from '@/components/inputs/Select'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { useWorkspace } from '@/features/workspace/WorkspaceProvider'
import { useToast } from '@/hooks/useToast'
import { trpc } from '@/lib/trpc'
type Props = {
credentialsId: string
blockId: string
defaultValue: string
onChange: (projectId: string | undefined) => void
}
export const ProjectsDropdown = ({
defaultValue,
onChange,
credentialsId,
}: Props) => {
const { typebot } = useTypebot()
const { workspace } = useWorkspace()
const { showToast } = useToast()
const { data } = trpc.zemanticAI.listProjects.useQuery(
{
credentialsId,
workspaceId: workspace?.id as string,
},
{
enabled: !!typebot && !!workspace,
onError: (error) => {
showToast({
description: error.message,
status: 'error',
})
},
}
)
return (
<Select
items={data?.projects as { label: string; value: string }[]}
selectedItem={defaultValue}
onSelect={onChange}
placeholder="Select a project"
/>
)
}

View File

@ -1,44 +0,0 @@
import { DropdownList } from '@/components/DropdownList'
import { VariableSearchInput } from '@/components/inputs/VariableSearchInput'
import { TableListItemProps } from '@/components/TableList'
import { Stack } from '@chakra-ui/react'
import { Variable, ZemanticAiBlock } from '@typebot.io/schemas'
import {
defaultZemanticAiResponseMappingItem,
searchResponseValues,
} from '@typebot.io/schemas/features/blocks/integrations/zemanticAi/constants'
type Props = TableListItemProps<
NonNullable<
NonNullable<ZemanticAiBlock['options']>['responseMapping']
>[number]
>
export const SearchResponseItem = ({ item, onItemChange }: Props) => {
const changeValueToExtract = (
valueToExtract: (typeof searchResponseValues)[number]
) => {
onItemChange({ ...item, valueToExtract })
}
const changeVariableId = (variable: Pick<Variable, 'id'> | undefined) => {
onItemChange({ ...item, variableId: variable ? variable.id : undefined })
}
return (
<Stack p="4" rounded="md" flex="1" borderWidth="1px">
<DropdownList
currentItem={
item.valueToExtract ??
defaultZemanticAiResponseMappingItem.valueToExtract
}
items={searchResponseValues}
onItemSelect={changeValueToExtract}
/>
<VariableSearchInput
onSelectVariable={changeVariableId}
initialVariableId={item.variableId}
/>
</Stack>
)
}

View File

@ -1,21 +0,0 @@
import { Icon, IconProps } from '@chakra-ui/react'
export const ZemanticAiLogo = (props: IconProps) => (
<Icon viewBox="0 0 24 24" {...props}>
<g transform="matrix(.049281 0 0 .064343 -.27105 -3.4424)">
<path
d="m99.5 205.5v221h-94v-373h94v152z"
fill="#8771b1"
opacity=".991"
/>
<path
d="m284.5 426.5v-221-152h94v373h-94z"
fill="#f05b4e"
opacity=".99"
/>
<path d="m99.5 205.5h93v221h-93v-221z" fill="#ec9896" />
<path d="m192.5 205.5h92v221h-92v-221z" fill="#efe894" />
<path d="m398.5 298.5h94v128h-94v-128z" fill="#46bb91" opacity=".989" />
</g>
</Icon>
)

View File

@ -1,37 +0,0 @@
import React from 'react'
import { Stack, Text } from '@chakra-ui/react'
import { useTypebot } from '@/features/editor/providers/TypebotProvider'
import { SetVariableLabel } from '@/components/SetVariableLabel'
import { ZemanticAiBlock } from '@typebot.io/schemas'
type Props = {
options: ZemanticAiBlock['options']
}
export const ZemanticAiNodeBody = ({
options: { query, projectId, responseMapping } = {},
}: Props) => {
const { typebot } = useTypebot()
return (
<Stack>
<Text
color={query && projectId ? 'currentcolor' : 'gray.500'}
noOfLines={1}
>
{query && projectId ? `Ask: ${query}` : 'Configure...'}
</Text>
{typebot &&
responseMapping
?.map((mapping) => mapping.variableId)
.map((variableId, idx) =>
variableId ? (
<SetVariableLabel
key={variableId + idx}
variables={typebot.variables}
variableId={variableId}
/>
) : null
)}
</Stack>
)
}

View File

@ -1,148 +0,0 @@
import { TextInput, Textarea, NumberInput } from '@/components/inputs'
import {
Accordion,
AccordionButton,
AccordionIcon,
AccordionItem,
AccordionPanel,
Stack,
Text,
} from '@chakra-ui/react'
import { isEmpty } from '@typebot.io/lib'
import { ZemanticAiBlock } from '@typebot.io/schemas'
import { ProjectsDropdown } from './ProjectsDropdown'
import { SearchResponseItem } from './SearchResponseItem'
import { TableList } from '@/components/TableList'
type Props = {
block: ZemanticAiBlock
onOptionsChange: (options: ZemanticAiBlock['options']) => void
}
export const ZemanticAiSettings = ({
block: { id: blockId, options },
onOptionsChange,
}: Props) => {
const updateProjectId = (projectId: string | undefined) => {
onOptionsChange({
...options,
projectId: isEmpty(projectId) ? undefined : projectId,
})
}
const updateQuery = (query: string) => {
onOptionsChange({
...options,
query: isEmpty(query) ? undefined : query,
})
}
const updateMaxResults = (
maxResults: number | `{{${string}}}` | undefined
) => {
onOptionsChange({
...options,
maxResults: maxResults as number,
})
}
const updateSystemPrompt = (systemPrompt: string) => {
onOptionsChange({
...options,
systemPrompt: isEmpty(systemPrompt) ? undefined : systemPrompt,
})
}
const updatePrompt = (prompt: string) => {
onOptionsChange({
...options,
prompt: isEmpty(prompt) ? undefined : prompt,
})
}
const updateResponseMapping = (
responseMapping: NonNullable<ZemanticAiBlock['options']>['responseMapping']
) => {
onOptionsChange({
...options,
responseMapping,
})
}
return (
<Stack spacing={4}>
{options?.credentialsId && (
<>
<ProjectsDropdown
credentialsId={options?.credentialsId as string}
defaultValue={(options?.projectId as string) ?? ''}
onChange={updateProjectId}
blockId={blockId as string}
/>
<TextInput
label="Query:"
moreInfoTooltip="The question you want to ask or search against the documents in the project."
defaultValue={options?.query ?? ''}
onChange={updateQuery}
withVariableButton={true}
placeholder="Content"
/>
<NumberInput
label="Max Results:"
moreInfoTooltip="The maximum number of document chunk results to return from your search."
direction="column"
defaultValue={options?.maxResults}
onValueChange={updateMaxResults}
placeholder="i.e. 3"
w="full"
/>
<Accordion allowMultiple={true}>
<AccordionItem>
<AccordionButton>
<Text w="full" textAlign="left">
Advanced settings
</Text>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pb={4} as={Stack} spacing={6}>
<Textarea
label="System Prompt:"
moreInfoTooltip="System prompt to send to the summarization LLM. This is prepended to the prompt and helps guide system behavior."
defaultValue={options?.systemPrompt ?? ''}
onChange={updateSystemPrompt}
placeholder="System Prompt"
withVariableButton={true}
/>
<Textarea
label="Prompt:"
moreInfoTooltip="Prompt to send to the summarization LLM."
defaultValue={options?.prompt ?? ''}
onChange={updatePrompt}
placeholder="Prompt"
withVariableButton={true}
/>
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<AccordionButton>
<Text w="full" textAlign="left">
Save answer
</Text>
<AccordionIcon />
</AccordionButton>
<AccordionPanel pt="4">
<TableList
initialItems={options.responseMapping ?? []}
onItemsChange={updateResponseMapping}
newItemDefaultProps={{ valueToExtract: 'Summary' }}
>
{(props) => <SearchResponseItem {...props} />}
</TableList>
</AccordionPanel>
</AccordionItem>
</Accordion>
</>
)}
</Stack>
)
}

View File

@ -1,87 +0,0 @@
import prisma from '@typebot.io/lib/prisma'
import { authenticatedProcedure } from '@/helpers/server/trpc'
import { TRPCError } from '@trpc/server'
import { z } from 'zod'
import { isReadWorkspaceFobidden } from '@/features/workspace/helpers/isReadWorkspaceFobidden'
import { decrypt } from '@typebot.io/lib/api/encryption/decrypt'
import { ZemanticAiCredentials } from '@typebot.io/schemas/features/blocks/integrations/zemanticAi'
import ky from 'ky'
export const listProjects = authenticatedProcedure
.input(
z.object({
credentialsId: z.string(),
workspaceId: z.string(),
})
)
.query(async ({ input: { credentialsId, workspaceId }, ctx: { user } }) => {
const workspace = await prisma.workspace.findFirst({
where: { id: workspaceId },
select: {
members: {
select: {
userId: true,
},
},
credentials: {
where: {
id: credentialsId,
},
select: {
id: true,
data: true,
iv: true,
},
},
},
})
if (!workspace || isReadWorkspaceFobidden(workspace, user))
throw new TRPCError({
code: 'NOT_FOUND',
message: 'No workspace found',
})
const credentials = workspace.credentials.at(0)
if (!credentials)
throw new TRPCError({
code: 'NOT_FOUND',
message: 'No credentials found',
})
const data = (await decrypt(
credentials.data,
credentials.iv
)) as ZemanticAiCredentials['data']
const url = 'https://api.zemantic.ai/v1/projects'
try {
const response = await ky
.get(url, {
headers: {
Authorization: `Bearer ${data.apiKey}`,
},
})
.json()
const projectsData = response as {
id: string
name: string
}[]
return {
projects: projectsData.map((project) => ({
label: project.name,
value: project.id,
})),
}
} catch (e) {
throw new TRPCError({
code: 'INTERNAL_SERVER_ERROR',
message: 'Could not list projects',
cause: e,
})
}
})

View File

@ -1,6 +0,0 @@
import { router } from '@/helpers/server/trpc'
import { listProjects } from './listProjects'
export const zemanticAiRouter = router({
listProjects,
})

View File

@ -62,8 +62,6 @@ const CredentialsCreateModalContent = ({
onClose={onClose}
/>
)
case 'zemanticAi':
return null
default:
return (
<CreateForgedCredentialsModalContent

View File

@ -211,8 +211,6 @@ const CredentialsIcon = ({
return <StripeLogo rounded="sm" {...props} />
case 'whatsApp':
return <WhatsAppLogo {...props} />
case 'zemanticAi':
return null
default:
return <BlockIcon type={type} {...props} />
}
@ -247,8 +245,6 @@ const CredentialsLabel = ({
WhatsApp
</Text>
)
case 'zemanticAi':
return null
default:
return <BlockLabel type={type} {...props} />
}

View File

@ -57,7 +57,6 @@ const CredentialsUpdateModalContent = ({
onUpdate={onSubmit}
/>
)
case 'zemanticAi':
case 'whatsApp':
return null
default:

View File

@ -31,7 +31,6 @@ import { TypebotLinkIcon } from '@/features/blocks/logic/typebotLink/components/
import { AbTestIcon } from '@/features/blocks/logic/abTest/components/AbTestIcon'
import { PictureChoiceIcon } from '@/features/blocks/inputs/pictureChoice/components/PictureChoiceIcon'
import { PixelLogo } from '@/features/blocks/integrations/pixel/components/PixelLogo'
import { ZemanticAiLogo } from '@/features/blocks/integrations/zemanticAi/ZemanticAiLogo'
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integrations/constants'
@ -117,8 +116,6 @@ export const BlockIcon = ({ type, ...props }: BlockIconProps): JSX.Element => {
return <ChatwootLogo {...props} />
case IntegrationBlockType.PIXEL:
return <PixelLogo {...props} />
case IntegrationBlockType.ZEMANTIC_AI:
return <ZemanticAiLogo {...props} />
case 'start':
return <FlagIcon {...props} />
case IntegrationBlockType.OPEN_AI:

View File

@ -219,12 +219,6 @@ export const BlockLabel = ({ type, ...props }: Props): JSX.Element => {
{t('editor.sidebarBlock.pixel.label')}
</Text>
)
case IntegrationBlockType.ZEMANTIC_AI:
return (
<Text fontSize="sm" {...props}>
{t('editor.sidebarBlock.zemanticAi.label')}
</Text>
)
default:
return <ForgedBlockLabel type={type} {...props} />
}

View File

@ -27,10 +27,7 @@ import { useDebouncedCallback } from 'use-debounce'
import { forgedBlockIds } from '@typebot.io/forge-repository/constants'
// Integration blocks migrated to forged blocks
const legacyIntegrationBlocks = [
IntegrationBlockType.OPEN_AI,
IntegrationBlockType.ZEMANTIC_AI,
]
const legacyIntegrationBlocks = [IntegrationBlockType.OPEN_AI]
export const BlocksSideBar = () => {
const { t } = useTranslate()

View File

@ -16,7 +16,7 @@ import {
import React, { useState } from 'react'
import { ZodObjectLayout } from '../zodLayouts/ZodObjectLayout'
import { ForgedBlockDefinition } from '@typebot.io/forge-repository/types'
import { CredentialsWithoutLegacy } from '@typebot.io/schemas'
import { Credentials } from '@typebot.io/schemas'
type Props = {
blockDef: ForgedBlockDefinition
@ -91,7 +91,7 @@ export const CreateForgedCredentialsModalContent = ({
workspaceId: workspace.id,
name,
data,
} as CredentialsWithoutLegacy,
} as Credentials,
})
}

View File

@ -14,7 +14,7 @@ import {
import React, { useEffect, useState } from 'react'
import { ZodObjectLayout } from '../zodLayouts/ZodObjectLayout'
import { ForgedBlockDefinition } from '@typebot.io/forge-repository/types'
import { CredentialsWithoutLegacy } from '@typebot.io/schemas'
import { Credentials } from '@typebot.io/schemas'
type Props = {
credentialsId: string
@ -76,7 +76,7 @@ export const UpdateForgedCredentialsModalContent = ({
workspaceId: workspace.id,
name,
data,
} as CredentialsWithoutLegacy,
} as Credentials,
})
}

View File

@ -32,7 +32,6 @@ import { ChatwootNodeBody } from '@/features/blocks/integrations/chatwoot/compon
import { AbTestNodeBody } from '@/features/blocks/logic/abTest/components/AbTestNodeBody'
import { PictureChoiceNode } from '@/features/blocks/inputs/pictureChoice/components/PictureChoiceNode'
import { PixelNodeBody } from '@/features/blocks/integrations/pixel/components/PixelNodeBody'
import { ZemanticAiNodeBody } from '@/features/blocks/integrations/zemanticAi/ZemanticAiNodeBody'
import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/constants'
@ -151,9 +150,6 @@ export const BlockNodeContent = ({
case IntegrationBlockType.PIXEL: {
return <PixelNodeBody options={block.options} />
}
case IntegrationBlockType.ZEMANTIC_AI: {
return <ZemanticAiNodeBody options={block.options} />
}
default: {
return <ForgedBlockNodeContent block={block} indices={indices} />
}

View File

@ -39,7 +39,6 @@ import { AbTestSettings } from '@/features/blocks/logic/abTest/components/AbTest
import { PictureChoiceSettings } from '@/features/blocks/inputs/pictureChoice/components/PictureChoiceSettings'
import { SettingsHoverBar } from './SettingsHoverBar'
import { PixelSettings } from '@/features/blocks/integrations/pixel/components/PixelSettings'
import { ZemanticAiSettings } from '@/features/blocks/integrations/zemanticAi/ZemanticAiSettings'
import { InputBlockType } from '@typebot.io/schemas/features/blocks/inputs/constants'
import { IntegrationBlockType } from '@typebot.io/schemas/features/blocks/integrations/constants'
import { LogicBlockType } from '@typebot.io/schemas/features/blocks/logic/constants'
@ -338,11 +337,6 @@ export const BlockSettings = ({
/>
)
}
case IntegrationBlockType.ZEMANTIC_AI: {
return (
<ZemanticAiSettings block={block} onOptionsChange={updateOptions} />
)
}
case LogicBlockType.CONDITION:
return null
default: {

View File

@ -65,8 +65,6 @@ export const getHelpDocUrl = (
return 'https://docs.typebot.io/editor/blocks/logic/jump'
case IntegrationBlockType.PIXEL:
return 'https://docs.typebot.io/editor/blocks/integrations/pixel'
case IntegrationBlockType.ZEMANTIC_AI:
return 'https://docs.typebot.io/editor/blocks/integrations/zemantic-ai'
case LogicBlockType.CONDITION:
return 'https://docs.typebot.io/editor/blocks/logic/condition'
default:

View File

@ -3,7 +3,6 @@ import { router } from '../trpc'
import { generateUploadUrl } from '@/features/upload/api/generateUploadUrl'
import { openAIRouter } from '@/features/blocks/integrations/openai/api/router'
import { internalWhatsAppRouter } from '@/features/whatsapp/router'
import { zemanticAiRouter } from '@/features/blocks/integrations/zemanticAi/api/router'
import { forgeRouter } from '@/features/forge/api/router'
import { googleSheetsRouter } from '@/features/blocks/integrations/googleSheets/api/router'
import { telemetryRouter } from '@/features/telemetry/api/router'
@ -13,7 +12,6 @@ export const internalRouter = router({
generateUploadUrl,
whatsAppInternal: internalWhatsAppRouter,
openAI: openAIRouter,
zemanticAI: zemanticAiRouter,
forge: forgeRouter,
sheets: googleSheetsRouter,
telemetry: telemetryRouter,