UNPKG

cctsa-wxccdemobot-commons

Version:

Common routines for building demo/reference bots with Webex Contact Center and Google Dialogflow ES using the codingforconvos NPM library.

748 lines (692 loc) 27.6 kB
/** * Copyright 2022 Justin Randall, Cisco Systems Inc. All Rights Reserved. * * This program is free software: you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with this program. If not, * see <https://www.gnu.org/licenses/>. */ const { Intent, Sequence, fmtLog } = require("codingforconvos"); const { RedmineConnector } = require("../connectors/redmine"); const { injectJdsEvent } = require("../common"); const { DialogContext } = require("codingforconvos/src/contexts"); // Define Sequence Name Constants. const SEQ_COVIDSCREEN_NAME = 'covidscreen'; /** * Inject a JDS tape event representing a covid-19 screening success. * * @param {DialogContext} dialogContext The dialog context. */ async function injectCovidScreenSuccessEvent(dialogContext) { injectJdsEvent(dialogContext, 'Covid Screen Accepted', { caseUrl: 'http://cctsa-redmine.outofservice.org/issues/'+dialogContext.ctxparams.triageNumber, caseReason: 'Record of accepted screening results' }); } /** * Inject a JDS tape event representing a covid-19 screening failure. * * @param {DialogContext} dialogContext The dialog context. */ async function injectCovidScreenFailureEvent(dialogContext) { injectJdsEvent(dialogContext, 'Covid Screen Rejected', { caseUrl: 'http://cctsa-redmine.outofservice.org/issues/'+dialogContext.ctxparams.triageNumber, caseReason: 'Record of rejected screening results', interceptEvent: 'RfcConfirmAppointmentRebook' }); } /** * Registers the sequences and intents for the covid screen module. * * @param {ConvoClient} convoClient The convo client. */ function registerModuleCovidScreen(convoClient) { // Register Sequence. convoClient.registerSequence(new Sequence({ name: SEQ_COVIDSCREEN_NAME, // Sequence name, also used for Dialogflow context name. activity: 'completing your Covid-19 in-person admittance questionnaire', // Activity description, used in course correction. identityRequired: false, authRequired: false, params: { accepted: '0', declined: '0', q1acomplete: '0', q1aresult: '', q1brequired: '0', q1bcomplete: '0', q1bresult: '', q2complete: '0', q2result: '', q3complete: '0', q3result: '', q4acomplete: '0', q4aresult: '', q4brequired: '0', q4bcomplete: '0', q4bresult: '', q5acomplete: '0', q5aresult: '', q5brequired: '0', q5bcomplete: '0', q5bresult: '', q6acomplete: '0', q6aresult: '', q6brequired: '0', q6bcomplete: '0', q6bresult: '', triagePassOrFail: '', triageNumber: '', rebookOffered: '0', rebookAccepted: '0', rebookDeclined: '0' }, navigate: (dialogContext) => { // Navigate the sequence forward. let context = dialogContext.getOrCreateCtx(SEQ_COVIDSCREEN_NAME); if (context.parameters.triagePassOrFail !== '') { if (context.parameters.triagePassOrFail === 'pass') { let event = dialogContext.respondWithEvent('CovidScreenTriageNumber'); return; } else { if (context.parameters.rebookOffered === '0') { let event = dialogContext.respondWithEvent('CovidScreenRebookAppt'); return; } if (context.parameters.rebookAccepted === '1') { let event = dialogContext.respondWithEvent('EscalateToAgent', dialogContext.params.lastFulfillmentText); return; } else { dialogContext.resetOfferedAgentFlags(); console.log('Calling popSequenceAndNavigate'); dialogContext.popSequenceAndNavigate(SEQ_COVIDSCREEN_NAME); return; } } } if (context.parameters.accepted === '0' && context.parameters.declined === '0') { let event = dialogContext.respondWithEvent('CovidScreenRequired'); return; } if (context.parameters.declined === '1') { let event = dialogContext.respondWithEvent('CovidScreenDeclined'); return; } if (context.parameters.accepted === '1') { if (context.parameters.q1acomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ1A'); return; } if (context.parameters.q1brequired === '1' && context.parameters.q1bcomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ1B'); return; } if (context.parameters.q2complete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ2'); return; } if (context.parameters.q3complete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ3'); return; } if (context.parameters.q4acomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ4A'); return; } if (context.parameters.q4brequired === '1' && context.parameters.q4bcomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ4B'); return; } if (context.parameters.q5acomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ5A'); return; } if (context.parameters.q5brequired === '1' && context.parameters.q5bcomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ5B'); return; } if (context.parameters.q6acomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ6A'); return; } if (context.parameters.q6brequired === '1' && context.parameters.q6bcomplete === '0') { let event = dialogContext.respondWithEvent('CovidScreenQ6B'); return; } let event = dialogContext.respondWithEvent('CovidScreenComplete'); return; } console.log(fmtLog('authentication.navigate', 'action: '+dialogContext.currentAction+', lastFulfillmentText: '+dialogContext.params.lastFulfillmentText, dialogContext)); dialogContext.respondWithText(); return; } })); /** * Return a summarized representation of the Covid-19 screening conversation outcome. * * @param {DialogContext} dialogContext The dialog context. * @returns a summarized representation of the Covid-19 screening conversation outcome. */ function summarizeTriage (dialogContext) { let context = dialogContext.getOrCreateCtx(SEQ_COVIDSCREEN_NAME); let triage = {}; let symptoms = []; let passOrFail = 'pass'; triage.diagnosedWithCovid = context.parameters.q1aresult; if (triage.diagnosedWithCovid === 'true') { passOrFail = 'fail'; triage.diagnosedWithCovidDate = context.parameters.q1bresult; } triage.livesWithCovid = context.parameters.q2result; if (context.parameters.q3result === 'true') { passOrFail = 'fail'; symptoms.push('fever'); } if (context.parameters.q4aresult === 'true') { passOrFail = 'fail'; symptoms = symptoms.concat(context.parameters.q4bresult); } if (context.parameters.q5aresult === 'true') { passOrFail = 'fail'; symptoms = symptoms.concat(context.parameters.q5bresult); } if (context.parameters.q6aresult === 'true') { passOrFail = 'fail'; triage.countryName = context.parameters.q6bresult; } triage.symptoms = symptoms; triage.passOrFail = passOrFail; return triage; } // Register Intent Handlers. convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.required', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: true, handler: (dialogContext) => { dialogContext.appendFulfillmentText(); return; } })); convoClient.registerIntents({ actions: [ 'skill.covidscreen.required.confirmation.yes', 'skill.covidscreen.required.confirmation.able' ], sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'accepted': '1', 'declined': '0' }); dialogContext.deleteCtx('skillcovidscreenrequired-followup'); return; } }); convoClient.registerIntents({ actions: [ 'skill.covidscreen.required.confirmation.no', 'skill.covidscreen.required.confirmation.notable' ], sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'declined': '1' }); dialogContext.deleteCtx('skillcovidscreenrequired-followup'); return; } }); convoClient.registerIntents({ actions: [ 'skill.covidscreen.q1a', 'skill.covidscreen.q1b', 'skill.covidscreen.q2', 'skill.covidscreen.q3', 'skill.covidscreen.q4a', 'skill.covidscreen.q4b', 'skill.covidscreen.q5a', 'skill.covidscreen.q5b', 'skill.covidscreen.q6a', 'skill.covidscreen.q6b' ], sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: true, handler: (dialogContext) => { dialogContext.appendFulfillmentText(); return; } }); // Question #1 Intents convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q1a.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q1acomplete': '1', 'q1aresult': 'true', 'q1brequired': '1' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q1a.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q1acomplete': '1', 'q1aresult': 'false', 'q1brequired': '0' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q1b.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q1bcomplete': '1', 'q1bresult': 'true' // FIXME: this should be an input parameter. }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q1b.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q1bcomplete': '1', 'q1bresult': 'false' // FIXME: this should be an input parameter. }); return; } })); /** * Utility function for registering common format questions. * * @param {string} questionId The question label. */ function registerCommonCovidQuestion(questionId) { convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.'+questionId+'.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ [questionId+'complete']: '1', [questionId+'result']: 'true' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.'+questionId+'.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ [questionId+'complete']: '1', [questionId+'result']: 'false' }); return; } })); } const commonQuestions = ['q2', 'q3']; commonQuestions.forEach(questionId => registerCommonCovidQuestion(questionId)); // Question #4 Intents convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q4a.healthcare.symptoms', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q4acomplete': '1', 'q4aresult': 'true', 'q4bcomplete': '1', 'q4bresult': dialogContext.inparams.symptoms }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q4a.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q4acomplete': '1', 'q4aresult': 'true', 'q4brequired': '1' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q4a.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q4acomplete': '1', 'q4aresult': 'false', 'q4brequired': '0' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q4b.healthcare.symptoms', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q4bcomplete': '1', 'q4bresult': dialogContext.inparams.symptoms }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q4b.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q4bcomplete': '1', 'q4bresult': 'true' // FIXME: this should be an input parameter. }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q4b.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q4bcomplete': '1', 'q4bresult': 'false' // FIXME: this should be an input parameter. }); return; } })); // Question #5 Intents convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q5a.healthcare.symptoms', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q5acomplete': '1', 'q5aresult': 'true', 'q5bcomplete': '1', 'q5bresult': dialogContext.inparams.symptoms }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q5a.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q5acomplete': '1', 'q5aresult': 'true', 'q5brequired': '1' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q5a.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q5acomplete': '1', 'q5aresult': 'false', 'q5brequired': '0' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q5b.healthcare.symptoms', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q5bcomplete': '1', 'q5bresult': dialogContext.inparams.symptoms }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q5b.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q5bcomplete': '1', 'q5bresult': 'true' // FIXME: this should be an input parameter. }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q5b.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q5bcomplete': '1', 'q5bresult': 'false' // FIXME: this should be an input parameter. }); return; } })); // Question #6 Intents convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q6a.common.countries', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q6acomplete': '1', 'q6aresult': 'true', 'q6bcomplete': '1', 'q6bresult': dialogContext.inparams.countryName }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q6a.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q6acomplete': '1', 'q6aresult': 'true', 'q6brequired': '1' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q6a.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q6acomplete': '1', 'q6aresult': 'false', 'q6brequired': '0' }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q6b.common.countries', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q6bcomplete': '1', 'q6bresult': dialogContext.inparams.countryName }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q6b.confirmation.yes', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q6bcomplete': '1', 'q6bresult': 'true' // FIXME: this should be an input parameter. }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.q6b.confirmation.no', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'q6bcomplete': '1', 'q6bresult': 'false' // FIXME: this should be an input parameter. }); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.complete', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: async (dialogContext) => { dialogContext.appendFulfillmentText(); const triage = summarizeTriage(dialogContext); const newCase = {}; newCase.subject = 'Covid-19 In-person Admittance Triage Complete'; newCase.description = dialogContext.params.customerFirstName+' has completed the Covid-19 admittance screening required before arriving for in-person appointments.'; if (triage.passOrFail === 'pass') { dialogContext.setCurrentParam('triagePassOrFail', 'pass'); newCase.statusId = 12; } else { dialogContext.setCurrentParam('triagePassOrFail', 'fail'); newCase.statusId = 6; } const redmineApi = dialogContext.connectorManager.get(RedmineConnector.name()); const redmineNewTriage = await redmineApi.createRedmineTriage(newCase, dialogContext, triage); console.log('redmineNewTriage.id: '+redmineNewTriage.id); dialogContext.setSessionParam('redmineOpenCaseId', redmineNewTriage.id); dialogContext.setCurrentParam('triageNumber', redmineNewTriage.id); if (triage.passOrFail === 'pass') { injectCovidScreenSuccessEvent(dialogContext); } else { injectCovidScreenFailureEvent(dialogContext); } //console.log('Calling popSequenceAndNavigate '+SEQ_COVIDSCREEN_NAME); //dialogContext.popSequenceAndNavigate(SEQ_COVIDSCREEN_NAME); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.complete.triagenumber', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: true, handler: async (dialogContext) => { dialogContext.appendFulfillmentText(); return; } })); convoClient.registerIntent(new Intent({ action: 'skill.covidscreen.complete.rebookappt', sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: true, handler: async (dialogContext) => { dialogContext.appendFulfillmentText(); return; } })); convoClient.registerIntents({ actions: [ 'skill.covidscreen.complete.rebookappt.confirmation.yes', 'skill.covidscreen.complete.rebookappt.confirmation.able' ], sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'rebookOffered': '1', 'rebookAccepted': '1', 'rebookDeclined': '0' }); return; } }); convoClient.registerIntents({ actions: [ 'skill.covidscreen.complete.rebookappt.confirmation.no', 'skill.covidscreen.complete.rebookappt.confirmation.notable' ], sequenceName: SEQ_COVIDSCREEN_NAME, waitForReply: false, handler: (dialogContext) => { dialogContext.setFulfillmentText(); dialogContext.setCurrentParams({ 'rebookOffered': '1', 'rebookAccepted': '0', 'rebookDeclined': '1' }); return; } }); } module.exports = {registerModuleCovidScreen};