Add Complex Logic To A Twilio Whatsapp Bot - twilio

I am developing a Whatsapp Bot in Twilio to collect survey data Covid-19 related. However, i want to add complex logic in my program task. For example, i only want to display a question asking if the user is pregnant or not if the user has selected female as her gender. Plus i want to add a range of the questions asking weight and height.
Below is the sample code for my task
"actions": [
{
"say": "Thank you for making the time for this survey. Your answers help us improve the service!"
},
{
"collect": {
"name": "csat_answers",
"questions": [
{
"question": "Have you completed this survey before??",
"name": "first_time",
"type": "Twilio.YES_NO"
},
{
"question": "Please enter your username",
"name": "usernmae"
},
{
"question": "How old are you?",
"name": "age",
"type": "Twilio.NUMBER"
},
{
"question": "What Gender are you",
"name": "Gender"
},
{
"question": "Are you pregnant?",
"name": "pregnant",
"type": "Twilio.YES_NO"
},
{
"question": "What is your height (cm)?",
"name": "height",
"type": "Twilio.NUMBER"
},
{
"question": "What is your weight (kg)?",
"name": "weight",
"type": "Twilio.NUMBER"
}
],
"on_complete": {
"redirect": {
"method": "POST",
"uri": "task://complete_survey"
}
}
}
}
]
}```

You will need to introduce logic in your Autopilot assistant, static JSON will not provide this capability.
How to Use Twilio Functions with Twilio Autopilot
If you are not a developer but a builder, you will want to look at Twilio Studio, to graphically draw out your survey flow and handle survey state.
Conduct a Survey with Twilio Studio

Twilio developer evangelist here.
There's no way to do conditional Collect flows in Autopilot so that logic would need to be a part of your app code. You can implement that conditional logic with Autopilot using Twilio Functions, our serverless environment tool for Node.js applications.
This Node.js quickstart has some of what you're looking for.
You could have one Autopilot task which redirects to the Function which would check what the user said. That Redirect task could include this JSON:
{
"actions": [
{
"collect": {
"name": "pregnant_collect",
"questions": [
{
"question": "Are you pregnant?",
"name": "pregnant",
"type": "Twilio.YES_NO"
}
],
"on_complete": {
"redirect": {
"method": "POST",
"uri": "https://YOUR-TWILIO-FUNCTION.twil.io/Function_Name"
}
}
}
}
]
}
and then use a conditional in the Twilio Function that above Task redirects to (above, it's https://YOUR-TWILIO-FUNCTION.twil.io/Function_Name) to check what the user said. The Twilio Autopilot task could include this JSON:
exports.handler = function(context, event, callback) {
//Memory from the answered question
let memory = JSON.parse(event.Memory);
//array of "actions" objects
let actions = [];
//response item to return/add to responseObject in Actions
let responseItem;
//get answer from Memory
let pregnant_answer = Memory.twilio.collected_data.pregnant_collect.answers.pregnant.answer;
//Yes or No
if (pregnant_answer === "Yes") {
responseItem = {
"say": "WHATEVER YOU WANT TO SAY FOR YES"
};
actions.push(responseItem);
}
else {
responseItem = {
"say": "WHATEVER YOU WANT TO SAY FOR NO"
};
actions.push(responseItem);
}
responseItem = {
"redirect": {
"method": "POST",
"uri": "task://next_task"
}
};
actions.push(responseItem);
let responseObject = {
"actions": actions
};
callback(null, responseObject);
};
Let me know if this helps at all! <3

Related

Microsoft Teams: Messaging extension on query result select item is not invoked on iOS

I'm building a Microsoft Teams bot with Compose Extension (Search extension) functionality. As soon as the user opens the search extension it fetches results from the backend. I'm using thumbnail cards to show the result list. I have also added tap functionality into thumbnail cards. That means when a user selects a result a backend invoke call will be triggered with some specific data and with that data I build an adaptive card.
This feature works well in Teams mac, web, and android apps. But with the native iOS app, the invoke call is never triggered when a user selects a result. Instead, it sends a thumbnail card on the Teams compose area.
This is the response I'm building for the Search extension
{
"composeExtension": {
"type": "result",
"attachmentLayout": "list",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.thumbnail",
"content": {
"images": [
{
"url": "https://localhost:8080/Public/img3-a68ff7.jpeg"
}
],
"subtitle": "Thumbnail card subtitle",
"tap": {
"type": "invoke",
"value": {
"type": "IDEA_SELECT_CALLBACK",
"selectedItemId": 7082
}
},
"text": "Thumbnail card text",
"title": "Title"
}
}
]
}
}
image from ios where a thumbnail card is thrown in compose area
ideal result from PC/mac where invoke command triggered and the adaptive card is built
Mac/PC screenshots
Android screenshots
iOS screenshots
Code example from ms github
Well, I have made some changes to the response object. I've added the review property and instead of setting tap to the content, I'm setting it to the review. Doing so, invoke is triggered on selecting a search result but it also pastes the Hero Card on the compose area on my iOS device.
Here is the exact same response I'm building...
{
"composeExtension": {
"type": "result",
"attachmentLayout": "list",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.thumbnail",
"content": {
"images": [
{
"url": "https:/localhost/93/937083/Public/img3-a68ff7.jpeg"
}
],
"subtitle": "Subtitle",
"text": "Sample text",
"title": "Thumbnail card title"
},
"preview": {
"contentType": "application/vnd.microsoft.card.hero",
"content": {
"buttons": null,
"images": [
{
"url": "https:/localhost/93/937083/Public/img3-a68ff7.jpeg"
}
],
"subtitle": "Subtitle",
"tap": {
"type": "invoke",
"value": {
"type": "SELECT_CALLBACK",
"selectedItemId": 1001
}
},
"text": "Sample text",
"title": "Thumbnail card title"
}
}
}
]
}
}
hero card on the compose area and adaptive card on the background built by invoked value

Microsoft Graph API - send message in channel by using team tagging

This graph API send a message in the channel
POST https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}/messages
{
"body": {
"content": "Hello world"
}
}
Also, following the docs from https://learn.microsoft.com/en-us/graph/api/resources/chatmessagemention?view=graph-rest-1.0 I can mention user, channel or team
But I am looking for how I can mention Tags while sending message in a channel.
After doing some research, came up with a solution thought of posting here for others:
Graph API
POST https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}/messages
Body here is critical
{
"subject": "This is very urgent!",
"importance": "urgent",
"body": {
"contentType": "html",
"content": "Programatically mentioning of Tagged users <at id=\"0\">String_1234</at>"
},
"mentions": [
{
"id": 0,
"mentionText": "String_1234",
"mentioned": {
"tag": {
"#odata.type": "#microsoft.graph.teamworkTagIdentity",
"id": "", //tag id
"displayName": "" //tag name
}
}
}
]
}

How fetch "webParts" from site pages

I am trying to fetch Pages from Sharepoint sites using graph API.
But when we make GET request with
https://graph.microsoft.com/beta/sites/{site-id}/pages/{page-id}
the response consists of webParts which only have type and data.
Inside data we have an id(which same as type) and an instanceId that is unique for every webPart.
Sample webPart:
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"id": "d1d91016-032f-456d-98a4-721247c305e8",
"instanceId": "c54a74ef-86c1-44aa-9ba4-802e6841e3a7"
}
My goal is to fetch webPages with complete details and then backup them to a local drive in any format.
The documentation of graph API shows that the responce would consist of complete details for the webPart, but it is not so.
Documentation link: https://learn.microsoft.com/en-us/graph/api/sitepage-get?view=graph-rest-beta&tabs=http
Sample request URL:
https://graph.microsoft.com/beta/sites/m365x214355.sharepoint.com,c1e5444e-12d8-43d3-96b1-f2f66559ef58,b181bdf0-9680-4988-81f7-a24aee4afd6a/pages
Webpart repsonse:
"webParts": [
{
"type": "rte",
"data": {
"innerHTML": "<p>Take a look at the team behind delivering amazing fashion events for Contoso.</p><p>Find out how the team uses the latest technology to plan amazing fashion shows and gather customer feedback for future events.</p><p>Meet the people behind Contoso's events, learn how to plan your own event, and find the necessary resources to run highly successful fashion shows, premiers, and extravaganzas!</p>"
}
},
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"id": "d1d91016-032f-456d-98a4-721247c305e8",
"instanceId": "c54a74ef-86c1-44aa-9ba4-802e6841e3a7"
}
},
{
"type": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"data": {
"id": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"instanceId": "75ccfeba-ad6c-416d-a859-4a6b114e156e"
}
},
{
"type": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"data": {
"id": "b7dd04e1-19ce-4b24-9132-b60a1c2b910d",
"instanceId": "f04e02fb-45e6-4e74-9f46-0c8d90e7fb8d"
}
},
{
"type": "275c0095-a77e-4f6d-a2a0-6a7626911518",
"data": {
"id": "275c0095-a77e-4f6d-a2a0-6a7626911518",
"instanceId": "c1a222b0-624e-4e30-b544-d2a67e8e1112"
}
}
Expected Response format:
"webParts": [
{
"type": "rte",
"data": {
"innerHTML": "<p>Here are the team's upcoming events:</p>"
}
},
{
"type": "d1d91016-032f-456d-98a4-721247c305e8",
"data": {
"title": "Events",
"description": "Display upcoming events",
"serverProcessedContent": {
"htmlStrings": {},
"searchablePlainTexts": {
"title": ""
},
"imageSources": {},
"links": {
"baseUrl": "https://www.contoso.com/sites/Engineering"
},
"componentDependencies": {
"layoutComponentId": "8ac0c53c-e8d0-4e3e-87d0-7449eb0d4027"
}
},
"dataVersion": "1.0",
"properties": {
"selectedListId": "032e08ab-89b0-4d8f-bc10-73094233615c",
"selectedCategory": "",
"dateRangeOption": 0,
"startDate": "",
"endDate": "",
"isOnSeeAllPage": false,
"layoutId": "FilmStrip",
"dataProviderId": "Event",
"webId": "0764c419-1ecc-4126-ba32-0c25ae0fffe8",
"siteId": "6b4ffc7a-cfc2-4a76-903a-1cc3686dee23"
}
}
}
]
I want webParts in the format as per documentation.
If the instanceId is unique then there might be some reference table to match these instanceIds and fetch the detailed webParts structure.

new validation webhook feature inside Twilio Collect action

I saw that Twilio added a new feature when using the Collect action, which allows one to validate the user answer by means of a web hook. Here's the link: https://www.twilio.com/docs/autopilot/actions/collect
I'm wondering if this is already part of the framework or not. I've tried small examples, and also the long sample they have in the documentation (using my own webhooks of course), and the validation web hook is not being triggered, or called at all.
as an example I have the following:
{"actions": [
{
"collect": {
"name": "date_questions",
"questions": [
{
"question": "What date?",
"name": "date",
"type": "Twilio.DATE",
"validate": {
"on_failure": {
"messages": [
{
"say": "Sorry, that's not a valid date."
},
{
"say": "Hmm, I'm not understanding what you're saying"
}
],
"repeat_question": true
},
"webhook": {
"method": "POST",
"url": "https://my_validation_wh"
}
}
}
],
"on_complete": {
"redirect": "https://my_on_complete_wh"
}
}
}
]}

Creating sections in swagger

I'm writing a swagger spec and I have three separate endpoints. How do I separate them in my documentation? I want to have a clear distinction between example: Users, Posts & Other. So each one would have a CRUD description and displayed in swagger UI it would look like:
USERS
// user specs
POST
// post specs
OTHER
// other specs
You need to use tags to accomplish this.
So, on your "paths" object, you sort all your routes and on each one, you add a "tags": ["{resource}"] where it should be grouped.
For example:
"paths": {
"/users": {
"get": {
"tags": ["User"],
"description": "...",
},
"post": {
"tags": ["User"],
"description": "...",
}
},
"/posts": {
"get": {
"tags": ["Post"],
"description": "...",
},
"post": {
"tags": ["Post"],
"description": "...",
}
},
"/other": {
"get": {
"tags": ["Other"],
"description": "...",
},
"post": {
"tags": ["Other"],
"description": "...",
}
},
}
This is not obvious at all on the documentation. Actually the documentation is very complete but lacks an index and some organisation.

Resources