From 4f02648d24e38b0df49487b41a6c0f71ad859b2c Mon Sep 17 00:00:00 2001 From: yahyha benzha Date: Fri, 6 Oct 2023 11:45:14 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20optimize=20crisp=20human?= =?UTF-8?q?=20assistance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/integrations/crisp/config-update.ts | 3 +- .../pages/api/integrations/crisp/hooks.ts | 191 +++++++++++++----- 2 files changed, 138 insertions(+), 56 deletions(-) diff --git a/apps/dashboard/pages/api/integrations/crisp/config-update.ts b/apps/dashboard/pages/api/integrations/crisp/config-update.ts index 0565cdcd3..2cb694b59 100644 --- a/apps/dashboard/pages/api/integrations/crisp/config-update.ts +++ b/apps/dashboard/pages/api/integrations/crisp/config-update.ts @@ -22,8 +22,7 @@ export const updateCrispConfig = async ( req: AppNextApiRequest, res: NextApiResponse ) => { - const data = req.body as z.infer; - + const data = schema.parse(req.body) // const websites = await getConnectedWebsites(); let metadata = {} as any; diff --git a/apps/dashboard/pages/api/integrations/crisp/hooks.ts b/apps/dashboard/pages/api/integrations/crisp/hooks.ts index 563e9b7b2..860d883d2 100644 --- a/apps/dashboard/pages/api/integrations/crisp/hooks.ts +++ b/apps/dashboard/pages/api/integrations/crisp/hooks.ts @@ -312,6 +312,69 @@ export const hook = async (req: AppNextApiRequest, res: NextApiResponse) => { metadata?.choice === 'request_human' && newChoice?.value !== 'enable_ai' ) { + const agent = await getAgent(body.data.website_id); + const conversation = await prisma.conversation.findFirst({ + where: { + AND: [{ visitorId: body.data.session_id }], + }, + include: { + messages: { + orderBy: { + createdAt: 'desc', + }, + }, + }, + }); + + // save the new message + const conversationManager = new ConversationManager({ + organizationId: agent?.organizationId!, + channel: ConversationChannel.crisp, + agentId: agent?.id!, + visitorId: body.data.session_id, + conversationId:conversation?.id, + }); + conversationManager.push({ + from: MessageFrom.human, + text: body.data.content, + }); + conversationManager.save() + + const mostRecentMessage = conversation?.messages[0] + if(mostRecentMessage?.from == 'human') { + const oneHourAgo = new Date().getTime() - (60 * 60 * 1000); + + if (new Date(mostRecentMessage.createdAt).getTime() < oneHourAgo) { + CrispClient.website.composeMessageInConversation( + body.website_id, + body.data.session_id, + { + type: 'start', + from: 'operator', + } + ); + await CrispClient.website.updateConversationMetas( + body.website_id, + body.data.session_id, + { + data: { + choice: 'enable_ai', + }, + } + ); + + try { + return handleQuery( + body.website_id, + body.data.session_id, + body.data.content + ); + + } catch (err) { + req.logger.error(err); + } + } + } return 'User has requested a human operator, do not handle.'; } @@ -369,62 +432,82 @@ export const hook = async (req: AppNextApiRequest, res: NextApiResponse) => { switch (selected?.value) { case 'request_human': - await CrispClient.website.updateConversationMetas( - body.website_id, - body.data.session_id, - { - data: { - choice: 'request_human', - }, + const availibility = await CrispClient.website.getWebsiteAvailabilityStatus(body.data.website_id); + const status = availibility?.status + + if(status === "online"){ + const active_operators: {user_id:string,avatar:string|null, timestamp:number}[] = await CrispClient.website.listLastActiveWebsiteOperators(body.data.website_id) + const highly_active_operator = active_operators.filter(op => op.timestamp == Math.min(...active_operators.map(o => o.timestamp)))[0]; + await CrispClient.website.updateConversationMetas( + body.website_id, + body.data.session_id, + { + data: { + choice: 'request_human', + }, + } + ); + + await CrispClient.website.sendMessageInConversation( + body.website_id, + body.data.session_id, + { + type: 'picker', + from: 'operator', + origin: 'chat', + content: { + id: 'chaindesk-enable', + text: 'An operator will get back to you shortly.', + choices: [ + { + value: 'enable_ai', + icon: '▶️', + label: 'Re-enable AI', + selected: false, + }, + ] + }, + mentions: [highly_active_operator.user_id], + user:{ + type:'website', + nickname:'chaindesk' + } + } + ); } - ); - - // const data = - // await CrispClient.website.listLastActiveWebsiteOperators( - // body.website_id - // ); - - // await CrispClient.website.sendMessageInConversation( - // body.website_id, - // body.data.session_id, - // { - // type: 'text', - // from: 'operator', - // origin: 'chat', - - // content: 'An operator will get back to you shortly.', - // user: { - // type: 'participant', - // // nickname: agent?.name || 'Chaindesk', - // avatar: 'https://chaindesk.ai/app-rounded-bg-white.png', - // }, - // // mentions: [data?.[0]?.user_id], - // } - // ); - - await CrispClient.website.sendMessageInConversation( - body.website_id, - body.data.session_id, - { - type: 'picker', - from: 'operator', - origin: 'chat', - - content: { - id: 'chaindesk-enable', - text: 'An operator will get back to you shortly.', - choices: [ - { - value: 'enable_ai', - icon: '▶️', - label: 'Re-enable AI', - selected: false, - }, - ], - }, + else { + // website offline + await CrispClient.website.updateConversationMetas( + body.website_id, + body.data.session_id, + { + data: { + choice: 'enable_ai', + }, + } + ); + await CrispClient.website.sendMessageInConversation( + body.website_id, + body.data.session_id, + { + type: 'picker', + from: 'operator', + origin: 'chat', + content: { + id: 'chaindesk-enable', + text: 'Unfortunetly, all the operators are not available at the moment.', + choices: [ + { + value: 'resolved', + icon: '✅', + label: 'Mark as resolved', + selected: false, + } + ], + }, + } + ); } - ); - break; case 'resolved': await CrispClient.website.changeConversationState(