I'm trying to define a 'Payload' in Ruby for my Facebook Messenger bot. My use case is, when a user sees structured content (a story with a button) and they click the button, instead of sending them to a URL, I want to hit my webhook and return more structured content.
So, I've tried several iterations of this and not sure where I'm getting tripped up. I've started by adding a messaging event:
messaging_event["entry"].first["messaging"].each do |msg|
puts msg
sender = msg["sender"]["id"]
if msg["message"] && msg["message"]["text"]
payload = msg["message"][“payload”]
I did something very similar for adding text, which was:
post '/webhook/' do
messaging_event = JSON.parse(request.body.read)
puts messaging_event
messaging_event["entry"].first["messaging"].each do |msg|
puts msg
sender = msg["sender"]["id"]
if msg["message"] && msg["message"]["text"]
text = msg["message"]["text"]
puts "Sender ID: #{sender}, Text: #{text}"
So, at this point, I'm not sure if I need to further def the payload like:
def payload(sender, payload)
data = {
recipient: { id: sender },
message: payload
}
send_message(data)
end
Or, if I simply need to create a variable and call that variable within my Module object like:
module Messages
SIMPLE_ONE_BUTTON_PAYLOAD = {
"attachment":{
"type":"template",
"payload":{
"template_type":"button",
"text":"Here's a simple button message",
"buttons":[
"type":"postback",
"title":"Button One",
"payload":"[variable I need to call]",
]
}
}
}
end
So, there's really two things here -- Do I need the payload messaging event and to define the payload and what do I need to call within the object? Any thoughts or feedback here would be really helpful. Thanks in advance!
You need to handle postbacks in your code. When a user hits a button, facebook calls your webhook with a post back (unless it's a url).
From the docs:
Postbacks are back end calls to your webhook when buttons are tapped. These calls contain the payload that is set for the button. Buttons on Structured Messages support opening URLs and postbacks.
The structure of postback is different than a text message.
Text Message:
{"object":"page","entry":[{"id":654321,"time":1460624758100,"messaging":[{"sender":{"id":123456},"recipient":{"id":654321},"timestamp":1460624758089,"message":{"mid":"mid.987654","seq":12632,"text":"This is the message."}}]}]}
Postback:
{"object":"page","entry":[{"id":654321,"time":1460625294253,"messaging":[{"sender":{"id":123456},"recipient":{"id":654321},"timestamp":1460625294253,"postback":{"payload":"Payload defined in the button"}}]}]}
You're doing if msg["message"] && msg["message"]["text"] but a post back doesn't have the ["message"] element. You need to make another case for msg["postback"].
So, change this:
if msg["message"] && msg["message"]["text"]
payload = msg["message"]["payload"]
to this:
if msg["postback"] && msg["postback"]["payload"]
payload = msg["postback"]["payload"]
You can read further on handling postbacks here in the official documentation (Point 8 Handling Postbacks).
Related
In my web chat, I have my intent handling code responding with some text with embedded hyper-links so the user can click on these from the chat window. This works fine until I enabled speech and now those hyperlinks are being spoken. Is there a markup I can use in my text responses so that the speech services ignore certain text like the hyper-links?
Thanks
Larry
Is there a markup I can use in my text responses so that the speech services ignore certain text like the hyper-links?
You can detect hyperlink from text by using regular expression, and then explicitly specify text to be displayed and text to be spoken like below:
var mes = "For details, please check https://learn.microsoft.com/en-us/azure/cognitive-services/qnamaker/faqs";
var res = "";
if (Regex.Match(mes, #"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?").Success)
{
res = Regex.Replace(mes, #"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", "the link");
}
await context.SayAsync(text: $"{mes}", speak: $"{res}");
Test result:
I would make an IMessagActivityMapper that does checks like that for you. This way it will check every response you send back in one place rather than having to do it everywhere you send a url back.
public sealed class TextToSpeakActivityMapper : IMessageActivityMapper
{
public IMessageActivity Map(IMessageActivity message)
{
// only set the speak if it is not set by the developer.
var channelCapability = new ChannelCapability(Address.FromActivity(message));
if (channelCapability.SupportsSpeak() && string.IsNullOrEmpty(message.Speak))
{
message.Speak = Regex.Replace(message.Text, #"http(s)?://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?", "the link");
}
return message;
}
}
Then register it in your Global.asax.cs file:
builder.RegisterType<TextToSpeakActivityMapper>()
.AsImplementedInterfaces()
.SingleInstance();
I am trying to send a webhook out from Teams, which is apparently accomplished with a Custom Bot. I am able to get the bot created and then I can do #botname stuff and the endpoint receives a payload.
However, the bot immediately replies with "Sorry, there was a problem encountered with your request". I get this error if I point the "Callback URL" to a requestb.in url or if I point it to my endpoint. This leads me to suspect the bot is expecting some specific response from the endpoint, but this isn't documented. My endpoint responds with a 202 and some json. Requestb.in responds with a 200 and "ok".
So, is it true that the bot requires a specific response payload and if so what is this payload?
That link above mentions Your custom bot will need to reply asynchronously to the HTTP request from Microsoft Teams. It will have 5 seconds to reply to the message before the connection is terminated. But there is no indication of how to satisfy this request, unless the custom bot will need to reply synchronously.
You need to return a JSON response with the keys 'text' and 'type' as shown in the example here
{
"type": "message",
"text": "This is a reply!"
}
In case you are using NodeJS, you can try this sample code
I created an azure function in C# as the callback for the custom bot and was initially sending back a json string but that didnt work. Finally I had to set the response object's Content and ContentType to get it working (as shown here). Here is the code for a simple bot that echoes back what the user types in the channel, feel free to adapt it to your scenario.
Custom MS Teams bot example code using azure functions
#r "Newtonsoft.Json"
using System.Net;
using System.Net.Http.Headers;
using Newtonsoft.Json;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
log.Info("C# HTTP trigger function processed a request.");
// parse query parameter
string name = req.GetQueryNameValuePairs()
.FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0)
.Value;
// Get request body
dynamic data = await req.Content.ReadAsAsync<object>();
log.Info(JsonConvert.SerializeObject(data));
// Set name to query string or body data
name = name ?? data?.text;
Response res = new Response();
res.type = "Message";
res.text = $"You said:{name}";
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(JsonConvert.SerializeObject(res));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return response;
}
public class Response {
public string type;
public string text;
}
It seems like I can't set reply_to in vals hash when I'm using SparkPost::Client.new().send_message(param1,param2,etc...). Egs here: https://github.com/SparkPost/ruby-sparkpost
Meaning, when I send an email through the client - I want the end-user (that receives the email) to automatically have the reply_to attr (NOT the from attr) fill out the Reply To: field for a given ESP.
I've also seen this: https://github.com/SparkPost/ruby-sparkpost/blob/master/examples/transmission/with_template.rb. Which uses send_payload.
Does anyone know how to set the reply_toso it doesn't simply default to the from's email address?
Figured it out. Currently, you must use the SparkPost::Client.new().transmission.send_payload method and build the payload yourself.
Example:
payload = {
recipients: [{tags:[tag1,tag2],address:{email:foo#bar.com}}],
content: {
from: "Someone <no-reply#somewhere.io>",
subject: "Your awesome subject",
reply_to: "Someone Else <totally.hit.me.up#somewhere.else.io>",
html:"<h1>Hello World</h1>"
}
}
SparkPost::Client.new().transmission.send_payload(payload)
I'm building an application and one of the features is integrated with Twilio.
I have all the IVR flow done with Asp.Net Mvc 3 and everything is working correctly so far.
However, one of the features is to have the user input a phone number and have Twilio call that number and play something once the other user answers.
I'm using the Twilio REST API to make the call, but the call is not being done and I don't have any error on the application or on Twilio.
What I'm doing is this: I have an Action that receive the data from twilio
public ActionResult Dial(Call request, int opt)
{
var twilio = new TwilioRestClient(Configuration.TwilioAccKey, Configuration.TwilioAuthKey);
twilio.InitiateOutboundCall(Configuration.TwilioPhoneNumber,
"+" + request.Digits,
string.Format("{0}/Calls/Endorsement/Play?opt={1}", Configuration.BaseUrl, opt));
var response = new TwilioResponse();
response.Redirect("/Calls/Endorsement/Play?opt=" + opt, "GET");
return TwiML(response);
}
The response after the REST call is being executed and the outbound call doesn't throw any error.
What am I doing wrong?
Thanks!
Your code to initiate the outbound call looks correct.
Its possible that an exception is being returned from the REST API. I've changed your code to use the InitiateOutboundCall methods callback parameter to check if the RestException property is not null:
var twilio = new TwilioRestClient(Configuration.TwilioAccKey,
Configuration.TwilioAuthKey);
twilio.InitiateOutboundCall(Configuration.TwilioPhoneNumber,
"+" + request.Digits,
string.Format("{0}/Calls/Endorsement/Play?opt={1}", Configuration.BaseUrl, opt),
call =>
{
if (call.RestException != null)
{
//handle the rest error
}
}
);
If RestException is null and nothing is being logged in the Twilio debugger log, then your best option might be to break out Fiddler and see whats happening during the actual request to the API.
I had a similar problem and want to post here in case someone else finds this issue like I did. (At the time this is the only thing that shows up in a search for "InitiateOutboundCall".)
In my case no exceptions were thrown either by my app or by Twilio. The call to InitiateOutboundCall simply was not doing anything.
The docs make it clear that the URL must be absolute and I had left off the "http://". After adding this everything worked as expected.
I'm using Umbraco 4.6.2, and need to extend the default notifications it provides. For the sake of this question, let's say I am trying to add an "Unpublish" notification.
In \umbraco\presentation\umbraco\dialogs\notifications.aspx.cs it constructs the list of checkbx items shown to the user when opening the "Notifications" dialogue from the context menu.
I see that each Action has a ShowInNotifier property - how can I set this value to true for the UnPublish action?
Does this require modifying the core codebase, or is there a nice way I can gracefully extend Umbraco?
So after I have added this, users can subscribe to the UnPublish notification (am I missing any steps here?).
Will this automagically send notifications now?
I'm guessing not, so the next thing I have done is hooked the UnPublish event:
public class CustomEvents : ApplicationBase
{
public CustomEvents()
{
Document.AfterUnPublish += new Document.UnPublishEventHandler(Document_AfterUnPublish);
}
void Document_AfterUnPublish(Document sender, umbraco.cms.businesslogic.UnPublishEventArgs e)
{
var user = User.GetCurrent();
if (!string.IsNullOrEmpty(user.Email) && user.GetNotifications(sender.Path).Contains("UnPublish"))
{
//Send a notification here using default Umbraco settings, or, construct email and send manually:
string umbracoNotificationSenderAddress = ""; //How to get the address stored in umbracoSettings.config -> <notifications> -> <email>
//How to use the same subject/message formats used for other notifications? With the links back to the content?
string subject = "Notification of UnPublish performed on " + MyUtilities.GetFriendlyName(sender.Id);
string message = MyUtilities.GetFriendlyName(sender.Id) + " has just been unpublished.";
umbraco.library.SendMail(umbracoNotificationSenderAddress, user.Email, subject, message, true);
}
}
}
So the bits of that code that are not real/I need some pointers on:
Is that the correct way for checking if a user is subscribed to a particular notification?
How can I send a notification using the default umbraco settings? (e.g. generate an email just like the other notifications)
If that is not possible and I must construct my own email:
How do I get the from email address stored in umbracoSettings.config that
How can I copy the formatting used by the default Umbraco notifications? Should I manually copy it or is there a nicer way to do this (programmatically).
Any help (or even just links to relevant examples) are appreciated :>
My colleague got this working.
Create a class that overrides the action you wish to have notifications for.
You can see all the actions in /umbraco/cms/Actions
public class ActionUnPublishOverride : umbraco.BusinessLogic.Actions.ActionUnPublish, IAction
{
... see what the other actions look like to find out what to put in here!
In the overridden class, you will have a public char Letter. Set this to match the event to hook into. You can find the letters each event has in the database.
Set the public bool ShowInNotifier to true.
That's it!
I've got this working on Umbraco 4.7 by using the UmbracoSettings class:
http://www.java2s.com/Open-Source/CSharp/Content-Management-Systems-CMS/umbraco/umbraco/businesslogic/UmbracoSettings.cs.htm
umbraco.library.SendMail(umbraco.UmbracoSettings.NotificationEmailSender, newMember.Email, "email subject", "email body", false);