Skip to content

Commit ac17794

Browse files
committed
feat(typebot): numbered choice input with numeric reply support
- Replace ▶️ emoji with numbered list (1. Option, 2. Option...) - Store choice map in session parameters for number-based selection - Resolve numeric replies to choice text before sending to Typebot - Users can now type '1' instead of the full option text - Clear choiceMap after use to avoid stale mappings
1 parent 3b95b03 commit ac17794

1 file changed

Lines changed: 36 additions & 4 deletions

File tree

src/api/integrations/chatbot/typebot/services/typebot.service.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,11 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
408408

409409
const items = input.items;
410410

411-
for (const item of items) {
412-
formattedText += `▶️ ${item.content}\n`;
411+
// Format choices with numbers for easier selection
412+
const choiceMap: Record<string, string> = {};
413+
for (let i = 0; i < items.length; i++) {
414+
formattedText += `*${i + 1}.* ${items[i].content}\n`;
415+
choiceMap[String(i + 1)] = items[i].content;
413416
}
414417

415418
formattedText = formattedText.replace(/\n$/, '');
@@ -425,12 +428,21 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
425428
sendTelemetry('/message/sendText');
426429
}
427430

431+
// Store choice map in session for number-based selection
432+
const currentParams = (session.parameters as Record<string, any>) || {};
433+
const updatedParams: any = {
434+
...currentParams,
435+
lastChoiceMap: input.type === 'choice input' ? Object.fromEntries(
436+
input.items.map((item: any, idx: number) => [String(idx + 1), item.content])
437+
) : undefined,
438+
};
428439
await prismaRepository.integrationSession.update({
429440
where: {
430441
id: session.id,
431442
},
432443
data: {
433444
awaitUser: true,
445+
parameters: updatedParams,
434446
},
435447
});
436448
} else {
@@ -1097,18 +1109,38 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
10971109
}
10981110

10991111
// Continue existing chat
1112+
// Resolve numeric replies to choice text using stored choiceMap
1113+
// Refresh session from DB to get the latest parameters (lastChoiceMap may have been set in previous turn)
1114+
let resolvedContent = content;
1115+
const freshSession = await this.prismaRepository.integrationSession.findUnique({
1116+
where: { id: session.id },
1117+
});
1118+
const sessionParams = (freshSession?.parameters as Record<string, any>) || {};
1119+
if (sessionParams.lastChoiceMap && sessionParams.lastChoiceMap[content.trim()]) {
1120+
resolvedContent = sessionParams.lastChoiceMap[content.trim()];
1121+
this.logger.verbose(`[TypeBot] Resolved numeric choice "${content.trim()}" → "${resolvedContent}"`);
1122+
// Clear the choiceMap after use
1123+
const clearedParams: any = { ...sessionParams, lastChoiceMap: undefined };
1124+
await this.prismaRepository.integrationSession.update({
1125+
where: { id: session.id },
1126+
data: {
1127+
parameters: clearedParams,
1128+
},
1129+
});
1130+
}
1131+
11001132
const version = this.configService.get<Typebot>('TYPEBOT').API_VERSION;
11011133
let urlTypebot: string;
11021134
let reqData: { message: string; sessionId?: string };
11031135
if (version === 'latest') {
11041136
urlTypebot = `${url}/api/v1/sessions/${session.sessionId.split('-')[1]}/continueChat`;
11051137
reqData = {
1106-
message: content,
1138+
message: resolvedContent,
11071139
};
11081140
} else {
11091141
urlTypebot = `${url}/api/v1/sendMessage`;
11101142
reqData = {
1111-
message: content,
1143+
message: resolvedContent,
11121144
sessionId: session.sessionId.split('-')[1],
11131145
};
11141146
}

0 commit comments

Comments
 (0)