Skip to content

Commit

Permalink
🚸 (bot) Update reply if we get new format from backend
Browse files Browse the repository at this point in the history
  • Loading branch information
baptisteArno committed Aug 7, 2023
1 parent ec0a5be commit af1bee8
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 18 deletions.
4 changes: 4 additions & 0 deletions apps/docs/openapi/builder/_spec_.json
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,9 @@
"properties": {
"url": {
"type": "string"
},
"isAutoplayEnabled": {
"type": "boolean"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -1986,6 +1989,7 @@
"Custom",
"Empty",
"User ID",
"Now",
"Today",
"Yesterday",
"Tomorrow",
Expand Down
11 changes: 11 additions & 0 deletions apps/docs/openapi/chat/_spec_.json
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@
"properties": {
"url": {
"type": "string"
},
"isAutoplayEnabled": {
"type": "boolean"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -1554,6 +1557,7 @@
"Custom",
"Empty",
"User ID",
"Now",
"Today",
"Yesterday",
"Tomorrow",
Expand Down Expand Up @@ -4031,6 +4035,9 @@
"properties": {
"url": {
"type": "string"
},
"isAutoplayEnabled": {
"type": "boolean"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -6021,6 +6028,10 @@
],
"additionalProperties": false
}
},
"lastMessageNewFormat": {
"type": "string",
"description": "The sent message is validated and formatted on the backend. This is set only if the message differs from the formatted version."
}
},
"required": [
Expand Down
11 changes: 9 additions & 2 deletions apps/viewer/src/features/chat/api/sendMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,14 @@ export const sendMessage = publicProcedure
clientSideActions,
}
} else {
const { messages, input, clientSideActions, newSessionState, logs } =
await continueBotFlow(session.state)(message)
const {
messages,
input,
clientSideActions,
newSessionState,
logs,
lastMessageNewFormat,
} = await continueBotFlow(session.state)(message)

const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs

Expand All @@ -101,6 +107,7 @@ export const sendMessage = publicProcedure
clientSideActions,
dynamicTheme: parseDynamicThemeReply(newSessionState),
logs,
lastMessageNewFormat,
}
}
}
Expand Down
39 changes: 30 additions & 9 deletions apps/viewer/src/features/chat/helpers/continueBotFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export const continueBotFlow =
message: 'Current block is not an input block',
})

let formattedReply = null
let formattedReply: string | undefined

if (isInputBlock(block)) {
if (reply && !isReplyValid(reply, block))
Expand Down Expand Up @@ -116,25 +116,46 @@ export const continueBotFlow =
const nextEdgeId = getOutgoingEdgeId(newSessionState)(block, formattedReply)

if (groupHasMoreBlocks && !nextEdgeId) {
return executeGroup(newSessionState)({
const chatReply = await executeGroup(newSessionState)({
...group,
blocks: group.blocks.slice(blockIndex + 1),
})
return {
...chatReply,
lastMessageNewFormat:
formattedReply !== reply ? formattedReply : undefined,
}
}

if (!nextEdgeId && state.linkedTypebots.queue.length === 0)
return { messages: [], newSessionState }
return {
messages: [],
newSessionState,
lastMessageNewFormat:
formattedReply !== reply ? formattedReply : undefined,
}

const nextGroup = getNextGroup(newSessionState)(nextEdgeId)

if (!nextGroup) return { messages: [], newSessionState }
if (!nextGroup)
return {
messages: [],
newSessionState,
lastMessageNewFormat:
formattedReply !== reply ? formattedReply : undefined,
}

return executeGroup(newSessionState)(nextGroup.group)
const chatReply = executeGroup(newSessionState)(nextGroup.group)
return {
...chatReply,
lastMessageNewFormat:
formattedReply !== reply ? formattedReply : undefined,
}
}

const processAndSaveAnswer =
(state: SessionState, block: InputBlock, itemId?: string) =>
async (reply: string | null): Promise<SessionState> => {
async (reply: string | undefined): Promise<SessionState> => {
if (!reply) return state
let newState = await saveAnswer(state, block, itemId)(reply)
newState = saveVariableValueIfAny(newState, block)(reply)
Expand Down Expand Up @@ -236,7 +257,7 @@ const getOutgoingEdgeId =
({ typebot: { variables } }: Pick<SessionState, 'typebot'>) =>
(
block: InputBlock | SetVariableBlock | OpenAIBlock | WebhookBlock,
reply: string | null
reply: string | undefined
) => {
if (
block.type === InputBlockType.CHOICE &&
Expand Down Expand Up @@ -264,8 +285,8 @@ const getOutgoingEdgeId =
export const formatReply = (
inputValue: string | undefined,
blockType: BlockType
): string | null => {
if (!inputValue) return null
): string | undefined => {
if (!inputValue) return
switch (blockType) {
case InputBlockType.PHONE:
return formatPhoneNumber(inputValue)
Expand Down
2 changes: 1 addition & 1 deletion packages/embeds/js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@typebot.io/js",
"version": "0.1.15",
"version": "0.1.16",
"description": "Javascript library to display typebots on your website",
"type": "module",
"main": "dist/index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ export const ChatChunk = (props: Props) => {
ref={inputRef}
block={props.input}
inputIndex={props.inputIndex}
onSubmit={props.onSubmit}
onSkip={props.onSkip}
hasHostAvatar={props.theme.chat.hostAvatar?.isEnabled ?? false}
guestAvatar={props.theme.chat.guestAvatar}
context={props.context}
isInputPrefillEnabled={
props.settings.general.isInputPrefillEnabled ?? true
}
hasError={props.hasError}
onSubmit={props.onSubmit}
onSkip={props.onSkip}
/>
)}
<Show when={props.streamingMessageId} keyed>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ import { executeClientSideAction } from '@/utils/executeClientSideActions'
import { LoadingChunk } from './LoadingChunk'
import { PopupBlockedToast } from './PopupBlockedToast'
import { setStreamingMessage } from '@/utils/streamingMessageSignal'
import {
formattedMessages,
setFormattedMessages,
} from '@/utils/formattedMessagesSignal'

const parseDynamicTheme = (
initialTheme: Theme,
Expand Down Expand Up @@ -164,6 +168,15 @@ export const ConversationContainer = (props: Props) => {
])
}
if (!data) return
if (data.lastMessageNewFormat) {
setFormattedMessages([
...formattedMessages(),
{
inputId: [...chatChunks()].pop()?.input?.id ?? '',
formattedMessage: data.lastMessageNewFormat as string,
},
])
}
if (data.logs) props.onNewLogs?.(data.logs)
if (data.dynamicTheme) setDynamicTheme(data.dynamicTheme)
if (data.input?.id && props.onNewInputBlock) {
Expand Down
13 changes: 11 additions & 2 deletions packages/embeds/js/src/components/InputChatBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ import { PhoneInput } from '@/features/blocks/inputs/phone'
import { DateForm } from '@/features/blocks/inputs/date'
import { RatingForm } from '@/features/blocks/inputs/rating'
import { FileUploadForm } from '@/features/blocks/inputs/fileUpload'
import { createSignal, Switch, Match } from 'solid-js'
import { createSignal, Switch, Match, createEffect } from 'solid-js'
import { isNotDefined } from '@typebot.io/lib'
import { isMobile } from '@/utils/isMobileSignal'
import { PaymentForm } from '@/features/blocks/inputs/payment'
import { MultipleChoicesForm } from '@/features/blocks/inputs/buttons/components/MultipleChoicesForm'
import { Buttons } from '@/features/blocks/inputs/buttons/components/Buttons'
import { SinglePictureChoice } from '@/features/blocks/inputs/pictureChoice/SinglePictureChoice'
import { MultiplePictureChoice } from '@/features/blocks/inputs/pictureChoice/MultiplePictureChoice'
import { formattedMessages } from '@/utils/formattedMessagesSignal'

type Props = {
ref: HTMLDivElement | undefined
Expand All @@ -49,6 +50,7 @@ type Props = {

export const InputChatBlock = (props: Props) => {
const [answer, setAnswer] = createSignal<string>()
const [formattedMessage, setFormattedMessage] = createSignal<string>()

const handleSubmit = async ({ label, value }: InputSubmitContent) => {
setAnswer(label ?? value)
Expand All @@ -60,11 +62,18 @@ export const InputChatBlock = (props: Props) => {
props.onSkip()
}

createEffect(() => {
const formattedMessage = formattedMessages().find(
(message) => message.inputId === props.block.id
)?.formattedMessage
if (formattedMessage) setFormattedMessage(formattedMessage)
})

return (
<Switch>
<Match when={answer() && !props.hasError}>
<GuestBubble
message={answer() as string}
message={formattedMessage() ?? (answer() as string)}
showAvatar={props.guestAvatar?.isEnabled ?? false}
avatarSrc={props.guestAvatar?.url && props.guestAvatar.url}
/>
Expand Down
5 changes: 5 additions & 0 deletions packages/embeds/js/src/utils/formattedMessagesSignal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createSignal } from 'solid-js'

export const [formattedMessages, setFormattedMessages] = createSignal<
{ inputId: string; formattedMessage: string }[]
>([])
2 changes: 1 addition & 1 deletion packages/embeds/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@typebot.io/nextjs",
"version": "0.1.15",
"version": "0.1.16",
"description": "Convenient library to display typebots on your Next.js website",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/embeds/react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@typebot.io/react",
"version": "0.1.15",
"version": "0.1.16",
"description": "Convenient library to display typebots on your Next.js website",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
6 changes: 6 additions & 0 deletions packages/schemas/features/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,12 @@ export const chatReplySchema = z.object({
resultId: z.string().optional(),
dynamicTheme: dynamicThemeSchema.optional(),
logs: z.array(replyLogSchema).optional(),
lastMessageNewFormat: z
.string()
.optional()
.describe(
'The sent message is validated and formatted on the backend. This is set only if the message differs from the formatted version.'
),
})

export type ChatSession = z.infer<typeof chatSessionSchema>
Expand Down

4 comments on commit af1bee8

@vercel
Copy link

@vercel vercel bot commented on af1bee8 Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on af1bee8 Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

builder-v2 – ./apps/builder

builder-v2-git-main-typebot-io.vercel.app
builder-v2-typebot-io.vercel.app
app.typebot.io

@vercel
Copy link

@vercel vercel bot commented on af1bee8 Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

viewer-v2 – ./apps/viewer

bot.synapsegameia.com
bot.truongnguyen.live
bots.baptistearno.com
botz.cloudsiteapp.com
cdd.searchcube.com.sg
chat.missarkansas.org
chatbot.ownacademy.co
chats.maisefetivo.com
claudio-barros.online
criar.somaperuzzo.com
gotasafrodisiacas.com
homerun.wpwakanda.com
mdb.assessoria.ademir
mestredaalmagemea.com
portaldasanalises.com
prenota.aldoemaria.it
revistasaudeemdia.com
sbutton.wpwakanda.com
talk.convobuilder.com
test.leadbooster.help
whats.laracardoso.com
www.acesso-app.online
www.hemertonsilva.com
zillabot.saaszilla.co
815639944.21000000.one
83720273.bouclidom.com
aplicacao.bmind.com.br
apply.ansuraniphone.my
bbutton.wpwwakanda.com
bolsamaisbrasil.app.br
bot.chat-debora.online
bot.clubedotrader.club
bot.louismarcondes.com
bot.perfaceacademy.com
bot.pratikmandalia.com
bot.sucessodigital.xyz
bot.t20worldcup.com.au
bot.whatsappweb.adm.br
bot2.mycompany.reviews
bot3.mycompany.reviews
bot4.mycompany.reviews
c23111azqw.nigerias.io
chat.footballmeetup.ie
conto.barrettamario.it
dieta.barrettamario.it
felipewelington.com.br
form.bridesquadapp.com
form.searchcube.com.sg
go.orodrigoribeiro.com
help.giversforgood.com
info.clickasuransi.com
kodawariab736.skeep.it
mdb.diego.progenbr.com
michaeljackson.riku.ai
premium.kandabrand.com
psicologiacognitiva.co
report.gratirabbit.com
resume.gratirabbit.com
teambuilding.hidden.sg
viewer-v2-typebot-io.vercel.app
mdb.assessoria.rodrigo.progenbr.com
register.thailandmicespecialist.com
mdb.assessoria.desideri.progenbr.com
mdb.assessoria.fernanda.progenbr.com
mdb.assessoria.jbatista.progenbr.com
mdb.assessoria.mauricio.progenbr.com
form.shopmercedesbenzsouthorlando.com
mdb.evento.equipeinterna.progenbr.com
bot.studiotecnicoimmobiliaremerelli.it
mdb.assessoria.boaventura.progenbr.com
mdb.assessoria.jtrebesqui.progenbr.com
pesquisa.escolamodacomproposito.com.br
anamnese.clinicaramosodontologia.com.br
gabinete.baleia.formulario.progenbr.com
mdb.assessoria.carreirinha.progenbr.com
chrome-os-inquiry-system.itschromeos.com
mdb.assessoria.paulomarques.progenbr.com
viewer-v2-git-main-typebot-io.vercel.app
main-menu-for-itschromeos.itschromeos.com
mdb.assessoria.qrcode.ademir.progenbr.com
mdb.assessoria.qrcode.arthur.progenbr.com
mdb.assessoria.qrcode.danilo.progenbr.com
mdb.assessoria.qrcode.marcao.progenbr.com
mdb.assessoria.qrcode.marcio.progenbr.com
mdb.assessoria.qrcode.aloisio.progenbr.com
mdb.assessoria.qrcode.girotto.progenbr.com
mdb.assessoria.qrcode.marinho.progenbr.com
mdb.assessoria.qrcode.rodrigo.progenbr.com
mdb.assessoria.carlosalexandre.progenbr.com
mdb.assessoria.qrcode.desideri.progenbr.com
mdb.assessoria.qrcode.fernanda.progenbr.com
mdb.assessoria.qrcode.jbatista.progenbr.com
mdb.assessoria.qrcode.mauricio.progenbr.com
mdb.assessoria.fernanda.regional.progenbr.com
mdb.assessoria.qrcode.boaventura.progenbr.com
mdb.assessoria.qrcode.jtrebesqui.progenbr.com
mdb.assessoria.qrcode.carreirinha.progenbr.com
mdb.assessoria.qrcode.paulomarques.progenbr.com
mdb.assessoria.qrcode.carlosalexandre.progenbr.com
mdb.assessoria.qrcode.fernanda.regional.progenbr.com

@vercel
Copy link

@vercel vercel bot commented on af1bee8 Aug 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./apps/docs

docs.typebot.io
docs-git-main-typebot-io.vercel.app
docs-typebot-io.vercel.app

Please sign in to comment.