Deep Linking
To create the best user experience, we should have the ability for customers to deep link into the chatbot based on domain or URL path and display corresponding peak view buttons and prompts. In addition if the user “starts over” they chatbot should use the deep link logic to restart to the correct flow.
To enable deep linking, we need to make sure we have the following components setup.
Settings
Intents
Experience Designer Logic
We have the ability to have stepped approach of determining the correct flow.
Do we have match for the current pages path?
If Yes, use corresponding flow id and prompt
If No, do we have match on the current domain?
If Yes, use corresponding flow id and prompt
If No, use the default launch flow id
Settings
In the settings schema we will have properties available for the following.
"domainToFlow": {
"example.org": "64a563f99c5e1200815a303e",
"my.example.org/PRD": "64d306d9709d4f007e435c70",
"dev.example.org": "64a563f99c5e1200815a303e",
"tools.orbita-cs.com": "64d306d9709d4f007e435c70"
},
"pathToFlow": {
"example.org/digital-medicine/connected-health/home-test-page": "64a626ad9c5e1200815a4974",
"example.org/digitial_medicine/connected-health": "65a626ad9c5e1200815a4974",
"example.org/digitial_medicine": "65a626ad9c5e1200815a4974",
},
"flow": {
"launch": {
"id": "64a563f99c5e1200815a303e"
},
.
.
.
}
Intents
We will use the Amazon.StartOverIntent. This will correctly process if the user types “start over” or “startover”.
Experience Designer Logic
Launch
[
{
"id": "1c2dd752.655129",
"type": "function",
"z": "81b0fb3a.94e8d8",
"name": "Get project context",
"func": "const orbitaUtil = global.get(\"orbitaUtil\");\nconst projectId = orbitaUtil.getProjectId(node);\n\nconst establishDeferral = () => {\n let deferred = null;\n \n const promise = new Promise((resolve, reject) => {\n deferred = {\n resolve,\n reject\n };\n });\n \n promise.deferred = deferred;\n \n return promise;\n};\n\nlet projects = global.get(\"projects\");\n\nif (!projects) {\n projects = {};\n global.set(\"projects\", projects);\n}\n\nflow.set(\"project\", undefined);\n\nlet project = projects[projectId];\n\nif (!project || project.isStale) {\n project = establishDeferral();\n projects[projectId] = project;\n}\n\nPromise.resolve(project).then((resolvedProject) => {\n flow.set(\"project\", resolvedProject);\n \n node.send(msg);\n});",
"outputs": 1,
"noerr": 0,
"x": 290,
"y": 140,
"wires": [
[
"9292947b.0814e8"
]
]
},
{
"id": "9292947b.0814e8",
"type": "function",
"z": "81b0fb3a.94e8d8",
"name": "Dependencies",
"func": "const project = flow.get(\"project\");\n\nproject.awaitDependencies([\"baseIntents\", \"settings\", \"utilities\"]).then((resolvedDependencies) => {\n node.send(msg);\n}).catch((error) => {\n const moduleName = ORBI.utils.getFlowName(node);\n\n node.error(`${moduleName}: Dependency resolution failed: ${error}`);\n});",
"outputs": 1,
"noerr": 0,
"x": 480,
"y": 140,
"wires": [
[
"c5606e97.f9751"
]
]
},
{
"id": "c5606e97.f9751",
"type": "function",
"z": "81b0fb3a.94e8d8",
"name": "Custom afterLaunch handler",
"func": "const orbitaUtil = global.get(\"orbitaUtil\");\n\nconst project = flow.get(\"project\");\n\nconst { baseIntents, utilities } = project;\n\nconst CUSTOM_DATA_PATHS = {\n ENTRY_POINT: \"payload.originalDetectIntentRequest.payload.customData.windowLocation.href\"\n};\n\nconst SETTINGS_PATHS = {\n PATH_TO_FLOW: \"pathToFlow\",\n DOMAIN_TO_FLOW: \"domainToFlow\"\n};\n\nbaseIntents.registerHandler(\"afterLaunch\", async (msg) => {\n const { settings } = project;\n \n let entryPoint = utilities.object.get(msg, CUSTOM_DATA_PATHS.ENTRY_POINT, null);\n \n if (entryPoint) {\n entryPoint = entryPoint.replace(/^http[s]?:\\/\\//i, \"\");\n \n const domain = entryPoint.split(\"/\")[0];\n \n const pathToFlow = utilities.object.get(settings, SETTINGS_PATHS.PATH_TO_FLOW, {});\n const domainToFlow = utilities.object.get(settings, SETTINGS_PATHS.DOMAIN_TO_FLOW, {});\n \n let launchFlowIdOverride = null;\n \n for (const path in pathToFlow){\n if (entryPoint.includes(path)) {\n launchFlowIdOverride = pathToFlow[path];\n }\n }\n \n if(!launchFlowIdOverride && domainToFlow[domain]){\n launchFlowIdOverride = domainToFlow[domain];\n }\n \n if (launchFlowIdOverride) {\n msg.launchFlowId = launchFlowIdOverride;\n } else {\n const _ = global.get('lodash');\n msg.menu = _.get(msg, 'payload.originalDetectIntentRequest.payload.customData.menu',null);\n if(msg.menu === 'unauthenticated'){\n msg.launchFlowId = utilities.object.get(settings, \"flow.unauthenticated.id\", null);\n } else if(msg.menu === 'authenticated'){\n msg.launchFlowId = utilities.object.get(settings, \"flow.authenticated.id\", null);\n }\n }\n \n if(msg.payload.originalDetectIntentRequest.payload.language){\n msg.orbita.session.language = msg.payload.originalDetectIntentRequest.payload.language;\n\n msg.payload.session.language = msg.orbita.session.language;\n msg.language = msg.orbita.session.language;\n msg.analytics.attributes = {\n 'lang': msg.language\n };\n }\n msg.orbita.session.visitID = orbitaUtil.uuid();\n }\n return msg;\n});",
"outputs": 0,
"noerr": 0,
"x": 700,
"y": 140,
"wires": []
},
{
"id": "4437498f.067e98",
"type": "inject",
"z": "81b0fb3a.94e8d8",
"name": "",
"topic": "",
"payload": "",
"payloadType": "date",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"x": 110,
"y": 140,
"wires": [
[
"1c2dd752.655129"
]
]
},
{
"id": "slots",
"type": "slots",
"z": "",
"slots": []
}
]
Start Over
[
{
"id": "c8319289.799db",
"type": "alexa-http intent",
"z": "34006a85.ab8eb6",
"name": "",
"skillConfig": "a765b69a.298f68",
"url": "/alexa_test",
"intent": "AMAZON.StartOverIntent",
"lastIntent": "",
"x": 340,
"y": 1100,
"wires": [
[
"b579c77c.7ba308"
]
]
},
{
"id": "cf3bf50c.e93cb8",
"type": "alexa-http intent",
"z": "34006a85.ab8eb6",
"name": "",
"skillConfig": "a765b69a.298f68",
"url": "/alexa_test",
"intent": "AMAZON.StartOverIntent",
"lastIntent": "anystate",
"x": 300,
"y": 1140,
"wires": [
[
"b579c77c.7ba308"
]
]
},
{
"id": "b579c77c.7ba308",
"type": "function",
"z": "34006a85.ab8eb6",
"name": "Start Over Flow Picker",
"func": "const orbitaUtil = global.get(\"orbitaUtil\");\n\nconst project = flow.get(\"project\");\n\nconst { baseIntents, utilities, settings, flowManager } = project;\n\nconst CUSTOM_DATA_PATHS = {\n ENTRY_POINT: \"payload.originalDetectIntentRequest.payload.customData.windowLocation.href\"\n};\n\nconst SETTINGS_PATHS = {\n PATH_TO_FLOW: \"pathToFlow\",\n DOMAIN_TO_FLOW: \"domainToFlow\"\n};\n\nvar launchFlowId = utilities.object.get(settings, \"flow.launch.id\", null); \n\n\nlet entryPoint = utilities.object.get(msg, CUSTOM_DATA_PATHS.ENTRY_POINT, null);\n \nif (entryPoint) {\n entryPoint = entryPoint.replace(/^http[s]?:\\/\\//i, \"\");\n \n const domain = entryPoint.split(\"/\")[0];\n \n const pathToFlow = utilities.object.get(settings, SETTINGS_PATHS.PATH_TO_FLOW, {});\n const domainToFlow = utilities.object.get(settings, SETTINGS_PATHS.DOMAIN_TO_FLOW, {});\n \n let launchFlowIdOverride = null;\n \n for (const path in pathToFlow){\n if (entryPoint.includes(path)) {\n launchFlowIdOverride = pathToFlow[path];\n }\n }\n \n if(!launchFlowIdOverride && domainToFlow[domain]){\n launchFlowIdOverride = domainToFlow[domain];\n }\n \n if (launchFlowIdOverride) {\n launchFlowId = launchFlowIdOverride;\n } else {\n const _ = global.get('lodash');\n msg.menu = _.get(msg, 'payload.originalDetectIntentRequest.payload.customData.menu',null);\n if(msg.menu === 'unauthenticated'){\n launchFlowId = utilities.object.get(settings, \"flow.unauthenticated.id\", null);\n } else if(msg.menu === 'authenticated'){\n launchFlowId = utilities.object.get(settings, \"flow.authenticated.id\", null);\n }\n }\n \n if(msg.payload.originalDetectIntentRequest.payload.language){\n msg.orbita.session.language = msg.payload.originalDetectIntentRequest.payload.language;\n\n msg.payload.session.language = msg.orbita.session.language;\n msg.language = msg.orbita.session.language;\n msg.analytics.attributes = {\n 'lang': msg.language\n };\n }\n msg.orbita.session.visitID = orbitaUtil.uuid();\n node.warn('flowid: ' + launchFlowId)\n}\n \nflowManager.changeFlow(msg, launchFlowId);\n\nreturn msg;\n",
"outputs": 0,
"noerr": 0,
"x": 660,
"y": 1120,
"wires": []
},
{
"id": "a765b69a.298f68",
"type": "alexa-skill-config",
"skillname": "Patient Access and Acquisition",
"projectId": "647644399f8ae70079725b0e",
"intents": "[]",
"skillstate": "fromsession, flowManager, FPL, useSymptomChecker, escalation,flow, test,FlowStudio, testState, bill,escalation,confirm_escalation,help,emergency, Reminder, sanity, flow_stud,webWeight,fromSession,flowMngr,scheduleride,aMedication,Survey,whyhelpmessage,medication,callorcomeby,Januvia,survey2,glucose,faqquestion,DailySurveyInProgress,HeadacheSurveyInProgress,MonthlySurveyInProgress,FeedbackSurveyInProgress,AllReportsDone,AskedForChangeResponse,AskedForChangeTwice,MigraineTrackerQuestions1,MigraineTrackerQuestions2,MigraineTrackerQuestions3,StudyQuestions1,StudyQuestions2,StudyQuestions3,Help1,Help2,Help3,AskedForHeadacheStart,AskedForHeadacheStartYesterday,AskedForHeadacheStartTime,AskedForHeadacheEndTime,AskedForHeadacheTimeCorrectness,AskedForHeadacheChangeStartTime,AskedForHeadacheEndDate,InvalidHeadacheTime,AskedForContinuePartial,MaxRecognitionError,ServicePhoneNumber,ConfirmGoHome,ConfirmStop,ConfirmPause,ConfirmCancel,FORTESTING,testState,setup, startup, Survey,flowManager, survey, flowMngr,eventSurvey, whyhelpmessage, HeadacheSurveyInProgress, MonthlySurveyInProgress, FeedbackSurveyInProgress, AllReportsDone, AskedForChangeResponse, AskedForChangeTwice, MigraineTrackerQuestions1, MigraineTrackerQuestions2, MigraineTrackerQuestions3, StudyQuestions1, StudyQuestions2, StudyQuestions3, Help1, Help2, Help3, AskedForHeadacheStart, AskedForHeadacheStartYesterday, AskedForHeadacheStartTime, AskedForHeadacheEndTime, AskedForHeadacheTimeCorrectness, AskedForHeadacheChangeStartTime, AskedForHeadacheEndDate, InvalidHeadacheTime, AskedForContinuePartial, MaxRecognitionError, ServicePhoneNumber, ConfirmGoHome, ConfirmStop, ConfirmPause, ConfirmCancel,pain,dual,TreatmentSurgery,plateletsflow,password,changeappointmentList,MedicalHeart,chooseLocation,cancelAppointment,plateletsFlow, reminder, CheckUser, fromSession, plateletsFlow, cancelAppointment,PlateletsChangeOption,MedicalHemochromatosis, MedicalHeart,LifestyleSTD,setDateOrTimeIntent, FAQ,setTimelanding,setDatelanding,FAQ, fromsession, mayoKB, orbitaKB, askAnother, afterAssessment, phonePrompt, awaitingPhone, confirmPhone, finalPhonePrompt, inChunkedAnswer, appointmentPhonePrompt,reminder,CheckUser,Reminder,sanity,SymptomTriage,survey,LogHealthData,exampleCustomState,t0,t1,t2,t3, FAL, FAP,mayo,inFlow, mayo,flowStudio, resumePrompt,flow_stud",
"disableLogging": false
},
{
"id": "slots",
"type": "slots",
"z": "",
"slots": []
}
]