Send a Whatsapp/SMS message with info obtained from a user with Autopilot - twilio

I've made a simple bot that gives information and collects some data from the users that use it. For example a user can ask for an appoinment and give his cellphone. What I'm trying to do is send a WA or a SMS message to a third number with the information that the bot collected. This is a sample of the Task code for the collect part
"collect": {
"name": "schedule_appt",
"questions": [
{
{
"question": "Let us your phone number and an expert will get in touch with you",
"name": "appt_phone_number",
"type": "Twilio.PHONE_NUMBER"
}
]
Now, I want to send a WA or SMS message with the value of "Twilio.PHONE_NUMBER" to another number. Is it possible to do with the options that twilio give in the bot creator or should I create some custom code for this situation? If so, which would be the best way to do it? A PHP app, or something Web developed?
I'm kinda lost so any advice would be appreciated.
Thanks!

You can do something like this:
{
"actions": [
{
"collect": {
"name": "schedule_appt",
"questions": [
{
"question": "Let us your phone number and an expert will get in touch with you",
"name": "appt_phone_number",
"type": "Twilio.PHONE_NUMBER"
}
],
"on_complete": {
"redirect": {
"method": "POST",
"uri": "https://xyz.twil.io/sostub"
}
}
}
}
]
}
Twilio Function (destination for URL:https://xyz.twil.io/sostub match to your unique Twilio Function domain)
exports.handler = async function(context, event, callback) {
let twilioClient = context.getTwilioClient();
let memory = JSON.parse(event.Memory);
console.log("User Identifier: "+ event.UserIdentifier);
console.log("Task: "+ event.CurrentTask);
console.log(event.CurrentInput);
let message = "Your Message Has been Sent!";
let responseObject = {
"actions": [
{
"say": message
}]
};
let sendSMS = () => {
try {
let result = twilioClient.messages
.create({
body: `Appointment Scheduled, Mobile Phone ${event.CurrentInput}`,
to: '+14075551212',
from: '+15095551212',
});
return result;
} catch(e) {
console.log(e);
callback(e);
}
};
let result = await sendSMS();
callback(null, responseObject);
};

Related

Twilio autopilot redirect not working properly

Im having a problem in getting Autopilot redirect to work
After redirecting to my POST url it stops saying anything.
Below is my code:
{
"actions": [
{
"collect": {
"name": "password_reset_collect",
"questions": [
{
"question": "I will perform password reset to your account. Do you wish to continue?",
"name": "continue",
"type": "Twilio.YES_NO"
}
],
"on_complete": {
"redirect": "https://88fb4b1a.ngrok.io/Voice/Post"
}
}
},
{
"remember": {
"action_query": "password_reset"
}
}
]
}
and in my POST url it returns JSON result using return Content() as follows
var response = "{\"actions\": [{\"say\": {\"speech\": \"Thank you! Have a good day\" }},{\"listen\": true }]}";
return Content(response, "application/json");
result:
{
"actions": [
{
"say": {
"speech": "Thank you! Have a good day"
}
},
{
"listen": true
}
]
}
It never say what I specified in the on JSON and the call end
What am I doing wrong?
Twilio developer evangelist here.
I'd try putting Remember before Collect, as mentioned on the Actions docs page.

Autopilot redirect to new task not working correctly

So, I've been working with Autopilot tasks for a little here since the patch when you no longer need to build, and I've seen that when I get to the second redirect to another task and when that task listens, it just fails to listen and it goes back to its fallback task.
I've tried to not use a function between the redirect and such, I've used a direct post to my Twilio function, and none of that works. I do have a questionnaire of two questions, and the complete label is a redirect, and that is where my tasks start to fail.
"actions": [
{
"say": {
"speech": "I just have a few questions"
}
},
{
"collect": {
"name": "questions",
"questions": [
{
"question": "Is the weather nice today",
"name": "q_1",
"type": "Twilio.YES_NO",
},
{
"question": "Do you like ice cream?",
"name": "q_2",
"type": "Twilio.YES_NO",
}
],
"on_complete": {
"redirect": "MY FUNCTION LINK"
}
}
}
]
}
Then the function will return this as a JSON:
responseObject = {
"actions": [
{
"redirect": "task://MY TASK"
}
]
};
Then the tasks goes like this:
{
"actions": [
{
"say": "Would you like to be transfered over, or be called later?"
},
{
"listen": {
"tasks": [
"transfer",
"calllater"
]
}
}
]
}
But the tasks that as being listened to never completes, and my logs seem like the task that called it does not exist.
The task should go to the correct tasks that are being listed to, but it just crashes and goes back to the fallback task. I have to idea why this does not work, please let me know.
Twilio developer evangelist here. 👋
I just took the code you posted and adjusted it and it works fine. Let me tell you what I did.
I created a welcome task
// welcome task
{
"actions": [
{
"say": {
"speech": "I just have a few questions"
}
},
{
"collect": {
"name": "questions",
"questions": [
{
"question": "Do you like ice cream?",
"name": "q_2",
"type": "Twilio.YES_NO"
}
],
"on_complete": {
"redirect": "https://picayune-snout.glitch.me/api/collect"
}
}
}
]
}
This tasks defines similar to your example an on_complete endpoint which I hosted on Glitch. The endpoints responds with JSON which looks like this.
module.exports = (req, res) => {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(
{
"actions": [
{
"say": {
"speech": "Thanks for you information"
}
},
{
"redirect": "task://continue"
}
]
}
));
}
Then, I defined the continue task similar to yours:
{
"actions": [
{
"say": "Would you like to be transfered over, or be called later?"
},
{
"listen": {
"tasks": [
"transfer",
"calllater"
]
}
}
]
}
calllater and transfer only use say and it works fine. Important piece is that you define samples for these two tasks so that the system can recognize them. Also you have to rebuild the model for the Natural Language Router.
Hard to tell what you did wrong. :/

actions on google, Oauth account Linking

I have been trying to connect an assistant action to my backend server
I am using my own Oauth server and followed the instructions on
https://developers.google.com/actions/identity/oauth2?oauth=code
I am using actions_intent_Sign_in for my dialogflow event intent (like https://actions-on-google.github.io/actions-on-google-nodejs/classes/conversation_helper.signin.html)
when i use my action to sign in, i get the login window to my server, i do the account linking and i can see that i generated the tokens on my server but i cant find the token in (conv.user.access.token)
and this is the code for my intent using "actions on google sdk "
'use strict';
var _ = require('lodash');
var path = require('path')
var express = require('express')
var http = require('http')
const bodyParser = require('body-parser');
var expressApp = express().use(bodyParser.json());
var server = http.createServer(expressApp).listen(3000)
const {
dialogflow,
SignIn
} = require('actions-on-google');
const app = dialogflow({
debug: true,
clientId: '7b4a6dfc-4b35-11e9-8646-d663bd873d93'
});
app.intent('Start Sign-in', conv => {
conv.ask(new SignIn());
});
app.intent('Get Sign-in', (conv, params, signin) => {
console.log("get sign in ");
console.log(JSON.stringify(signin));
if (signin.status === 'OK') {
const access = conv.user.access.token
console.log("the access token is " + access);
conv.ask('Great, thanks for signing in! What do you want to do next?');
} else {
conv.ask('I wont be able to save your data, but what do you want to do next?.');
}
});
and the response comes back as
{"#type":"type.googleapis.com/google.actions.v2.SignInValue","status":"OK"}
the access token is undefined
Response {
"status": 200,
"headers": {
"content-type": "application/json;charset=utf-8"
},
"body": {
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
{
"simpleResponse": {
"textToSpeech": "Great, thanks for signing in! What do you want to do next?"
}
}
]
}
}
}
}
}
the user object of conv has only this data
"user": {
"raw": {
"lastSeen": "2019-03-20T12:46:23Z",
"locale": "en-US",
"userId": "okdhyeGSk5tofgLjEepIUrA6mmewCESY8MjklZRPvQJgv6-uybfPobwdfgtrGZJ3bE2sM9ninhst"
},
"storage": {},
"_id": "okdhyeGSk5tofgLjEepIUrA6mmewCESY8MjklZRPvQJgv6-uybfPobwdfgtrGZJ3bE2sM9ninhst",
"locale": "en-US",
"permissions": [],
"last": {
"seen": "2019-03-20T12:46:23.000Z"
},
"name": {},
"entitlements": [],
"access": {},
"profile": {}
}
i dont know where the access/refresh token can be found or if there is any requirement for the post to send from my oauth server that i missed
so finally i managed to get it working with the help of Actions on Google Support Team
the problem was me having another google account logged-in in another tab, even though i had the AoG and dialogflow agent connected with the same account
tried all using incognito window and it works

Twilio Autopilot: How to pull data from Airtable and return results to user?

I'm using Collect in the first Autopilot task to get the date from the user (i.e. Jan 31, 2019). Then I am trying to use that variable (date) to search an Airtable database for that specific row. I want to return the results of that row to the user ("on Jan 31 the Main Theater is playing this movie, the Other Theater is playing...).
My Airtable Get code is below, but I am unsure how to assign the returned data to variables that I can read back to the user.
exports.handler = function(context, event, callback) {
var Airtable = require('airtable');
var base = new Airtable({apiKey:
'apikey'}).base('basekey');
base('Blockouts').find('recbGHAQopLQdCOHK', function(err, record) {
if (err) { console.error(err); return; }
console.log(record);
});
}
and here's the output that Airtable will send back:
{
"id": "recbGHAQopLQdCOHK",
"fields": {
"Date": "2019-02-02",
"Main Theater": "Star Wars",
"Other Theater": "Avengers"
},
"createdTime": "2019-02-02T21:21:48.000Z"
}
Twilio evangelist here.
If your Airtable Get code is not there already, it should go in a Twilio function (which supports Node.js)! that is pointed at an Autopilot task whose actions code has something like this:
{
"actions": [
{
"redirect": {
"uri": "https://your-twilio-function-path.twil.io/airtable-or-whatever-if-this-is-your-path"
}
}
]
}
Then in your Twilio function/Airtable Get code, you should modify your Twilio Response object to accept all requesting origins and have that look something like this:
exports.handler = function(context, event, callback) {
let response = new Twilio.Response();
let headers = {
"Access-Control-Allow-Origin": "*",
"Content-Type": "application/json"
};
var responseObject = {"actions":[
{ "say": "Try again" }
]};
response.setHeaders(headers);
var Airtable = require('airtable');
var base = new Airtable({apiKey: 'apikey'}).base('basekey');
base('Blockouts').find('recbGHAQopLQdCOHK', function(err, record) {
if (err) { console.error(err); return; }
console.log(record);
}).then(res => {
var date = res.data[0].fields.date;
responseObject = {"actions":[
{ "say": date }
]};
callback(null, responseObject);
});
};
I have not tested this code with your Airtable output (famous last words of a programmer), but used almost exactly the same code when making an Axios request to an API where I saved some of the data returned from that call in a variable, so it should be similar.
Hope this helps.

Telegram (simplest) inline bot send photo 2 times on iOS

I have an inline bot similar to #pic and it works ok, when I type query word I can see pictures appear so I can choose one and send to a chat. The problem is when I do - 2 copies of same result are sent. This happens only on iOS client. On Android, PC and other platforms only one picture is being sent. I have checked all logs (the bot is done in Node.js) and for every request I have a single response. It seems to be a iOS client bug, although #pic bot works fine. Has someone encountered this bug or have an idea of what can cause it?
Example of answerInlineQuery response object
{
"inline_query_id": "817150058382989968",
"results": [
{
"type": "photo",
"id": "se090",
"photo_url": "http://www.shadowera.com/secardbot361/se090.jpg",
"thumb_url": "http://www.shadowera.com/secardbot361/se090.jpg",
"photo_width": 344,
"photo_height": 480,
"title": "Tracking Gear",
"description": "You can view the hands of opposing players.",
"caption": "king"
},
{...
UPDATE:
So I have created a simplest possible inline bot in node.js #iosinlinebot (you can try it) AND you have the same exact behaviour: only on iOS devices you will send 2 images to the chat once tapped on the result.
Here is the code:
exports.handler = function(event, context) {
console.log(event);
const https = require("https");
let answer = {
inline_query_id: event.inline_query.id,
results: [{
type: "photo",
id: "abcd",
photo_url: "https://lh3.googleusercontent.com/jVXglyWWL5J2y1vRN-7Jy3_ozvvZc4w5486IAkbAIrWcNN_vn7YuIvhc1JDtGq43BqGl=s180",
thumb_url: "https://lh3.googleusercontent.com/jVXglyWWL5J2y1vRN-7Jy3_ozvvZc4w5486IAkbAIrWcNN_vn7YuIvhc1JDtGq43BqGl=s180",
photo_width: 180,
photo_height: 180,
title: "title",
description: "description",
caption: "test"
}],
cache_time:1
};
let postBody = JSON.stringify(answer);
let options = {
hostname: "api.telegram.org",
port: 443,
path: "/bot" + process.env.TOKEN + "/answerInlineQuery",
method: "POST",
headers: {
'Content-Type': 'application/json',
'Content-Length': postBody.length
}
};
let postreq = https.request(options, (res) => {
res.setEncoding('utf8');
const body = [];
res.on('data', (chunk) => body.push(chunk));
res.on('end', () => {
let j = body.join('');
console.log(j);
//context.done(JSON.parse(j));
});
});
postreq.write(postBody);
postreq.end();
};
this is an event object (coming from telegram):
{
"update_id": 12345678,
"inline_query": {
"id": "123456789123456789",
"from": {
"id": 123456789,
"is_bot": false,
"first_name": "Firstname",
"username": "username",
"language_code": "it-IT"
},
"query": "test",
"offset": ""
}
}
UPDATE:
Thanks to Sedric Heidarizarei we were able to find the problem. It is a telegram iOS client bug. If InlineQueryResultPhoto object contains caption field, you user will post 2 images to the chat.
It is very important to close the Begin and the End of your regex with ^ and $.
For example a user with this regex /^[/]start/ can use start and start a and start b as Bot command And will allow Them to receive your photo, But with /^[/]start$/, The user must enter the exact /start Command.
1: Use This Module: node-telegram-bot-api
2: And Send Your Photo:
bot.onText(/^[/]start$/, (msg) => {
const opts = {
parse_mode: 'Markdown',
reply_markup: {
inline_keyboard: [[{
text: '🔙',
callback_data: 'back'
}]]
}
};
bot.sendPhoto(msg.chat.id, 'AgADBAADn64xBoABCx8L8trMV9eMqgDAAEC', opts); // Your Photo id
});
Notice:
Open an empty project and just use and check your InlineQueryResultPhoto.
update:
That is a Telegram bug for For temporary use, remove caption from your let answer ={}

Categories

Resources