How to handle user location on facebook? C # Botframework

I am developing a bot using Microsoft botframe in C #, which will be deployed to messenger.

Enabling the features I'm trying to enable displays points of interest around the users location. I found this curl request on facebooks development site.

curl -X POST -H "Content-Type: application/json" -d '{
  "recipient":{
    "id":"USER_ID"
  },
  "message":{
    "text":"Please share your location:",
    "quick_replies":[
      {
        "content_type":"location",
      }
    ]
  }
}' "https://graph.facebook.com/v2.6/me/messages?access_token=PAGE_ACCESS_TOKEN"

      

Appart from this I haven't found a way to specify when to send a request for users' location, nor a way to store the location so that I can use it to search nearby.

If anyone could point me in the right direction, I would be very grateful.

Here is a good example of what I am trying to replicate. Messenger asks for the user's location

User selected location Location has been sent to the bot, relative information is displayed

This is an example of what I am trying to replicate.

[LuisIntent("Stores")]
        public async Task Stores(IDialogContext context, LuisResult result)
        {
            var msg = "location";
            if (msg == "location")
            {
                Lresult = result;
                await context.Forward(new FacebookLocationDialog(), ResumeAfter, msg, CancellationToken.None);
            }
            else
            {
                await Stores(context, result);
            }
        }

        public async Task ResumeAfter(IDialogContext context, IAwaitable<Place> result)
        {
            var place = await result;

            if (place != default(Place))
            {
                var geo = (place.Geo as JObject)?.ToObject<GeoCoordinates>();
                if (geo != null)
                {
                    var reply = context.MakeMessage();
                    reply.Attachments.Add(new HeroCard
                    {
                        Title = "Open your location in bing maps!",
                        Buttons = new List<CardAction> {
                            new CardAction
                            {
                                Title = "Your location",
                                Type = ActionTypes.OpenUrl,
                                Value = $"https://www.bing.com/maps/?v=2&cp={geo.Latitude}~{geo.Longitude}&lvl=16&dir=0&sty=c&sp=point.{geo.Latitude}_{geo.Longitude}_You%20are%20here&ignoreoptin=1"
                            }
                        }

                    }.ToAttachment());

                    await context.PostAsync(reply);
                }
                else
                {
                    await context.PostAsync("No GeoCoordinates!");
                }
            }
            else
            {
                await context.PostAsync("No location extracted!");
            }

            context.Wait(Stores);
        }

    }
    [Serializable]
    public class FacebookLocationDialog : IDialog<Place>
    {
        public async Task StartAsync(IDialogContext context)
        {
            context.Wait(MessageReceivedAsync);
        }

        public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
        {
            var msg = await argument;
            if (msg.ChannelId == "facebook")
            {
                var reply = context.MakeMessage();
                reply.ChannelData = new FacebookMessage
                (
                    text: "Please share your location with me.",
                    quickReplies: new List<FacebookQuickReply>
                    {
                        // If content_type is location, title and payload are not used
                        // see https://developers.facebook.com/docs/messenger-platform/send-api-reference/quick-replies#fields
                        // for more information.
                        new FacebookQuickReply(
                            contentType: FacebookQuickReply.ContentTypes.Location,
                            title: default(string),
                            payload: default(string)
                        )
                    }
                );
                await context.PostAsync(reply);
                context.Wait(LocationReceivedAsync);
            }
            else
            {
                context.Done(default(Place));
            }
        }

        public virtual async Task LocationReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
        {
            var msg = await argument;
            var location = msg.Entities?.Where(t => t.Type == "Place").Select(t => t.GetAs<Place>()).FirstOrDefault();
            context.Done(location);
        }
    }

      

"context.Wait (Shops)"; in the ResumeAfter task, specifies "The type arguments for the IDialogStack.Wait method cannot be decommissioned."

+3


source to share


2 answers


How to get location from Facebook Messenger

Have a look at the project BotBuilder-Location

on GitHub: https://github.com/Microsoft/BotBuilder-Location

It seems like it can be used in your example (based on the example provided: https://github.com/Microsoft/BotBuilder-Location#address-selection-using-fb-messengers-location-picker-gui-dialog )

sample

You may be interested to learn in FacebookNativeLocationRetrieverDialog.cs

:

private async Task StartAsync(IDialogContext context, string message)
{
    var reply = context.MakeMessage();
    reply.ChannelData = new FacebookMessage
    (
        text: message,
        quickReplies: new List<FacebookQuickReply>
        {
                new FacebookQuickReply(
                    contentType: FacebookQuickReply.ContentTypes.Location,
                    title: default(string),
                    payload: default(string)
                )
        }
    );

    await context.PostAsync(reply);
    context.Wait(this.MessageReceivedAsync);
}

      



By the way, this was also in the example EchoBot

provided at BotBuilder

( https://github.com/Microsoft/BotBuilder/blob/master/CSharp/Samples/EchoBot/EchoLocationDialog.cs )


Implementation

[Serializable]
public class MyFacebookLocationDialog : IDialog<Place>
{
    public async Task StartAsync(IDialogContext context)
    {
        context.Wait(MessageReceivedAsync);
    }

    public async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
    {
        var msg = await argument;

        // Here we prepare the message on Facebook that will ask for Location
        if (msg.ChannelId == "facebook")
        {
            var reply = context.MakeMessage();
            reply.ChannelData = new FacebookMessage
            (
                text: "Please share your location with me.",
                quickReplies: new List<FacebookQuickReply>
                {
                    // If content_type is location, title and payload are not used
                    // see https://developers.facebook.com/docs/messenger-platform/send-api-reference/quick-replies#fields
                    // for more information.
                    new FacebookQuickReply(
                        contentType: FacebookQuickReply.ContentTypes.Location,
                        title: default(string),
                        payload: default(string)
                    )
                }
            );
            await context.PostAsync(reply);

            // LocationReceivedAsync will be the place where we handle the result
            context.Wait(LocationReceivedAsync);
        }
        else
        {
            context.Done(default(Place));
        }
    }

    public async Task LocationReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> argument)
    {
        var msg = await argument;
        var location = msg.Entities?.Where(t => t.Type == "Place").Select(t => t.GetAs<Place>()).FirstOrDefault();

        // Printing message main content about location
        await context.PostAsync($"Location received: { Newtonsoft.Json.JsonConvert.SerializeObject(msg.Entities) }");

        // The result can be used then to do what you want, here in this sample it outputs a message with a link to Bing Maps centered on the position
        var geo = (location.Geo as JObject)?.ToObject<GeoCoordinates>();
        if (geo != null)
        {
            var reply = context.MakeMessage();
            reply.Attachments.Add(new HeroCard
            {
                Title = "Open your location in bing maps!",
                Buttons = new List<CardAction> {
                            new CardAction
                            {
                                Title = "Your location",
                                Type = ActionTypes.OpenUrl,
                                Value = $"https://www.bing.com/maps/?v=2&cp={geo.Latitude}~{geo.Longitude}&lvl=16&dir=0&sty=c&sp=point.{geo.Latitude}_{geo.Longitude}_You%20are%20here&ignoreoptin=1"
                            }
                        }

            }.ToAttachment());

            await context.PostAsync(reply);
            context.Done(location);
        }
        else
        {
            await context.PostAsync("No GeoCoordinates!");
            context.Done(default(Place));
        }
    }
}

      

Demo image: demo

+4


source


The address that is sent as a message can be accessed from the Message Objects list:

"type": "message",
"id": "mid.$cAAUW791mzPBhksN19999990ORr",
"timestamp": "2017-04-12T09:28:30.812Z",
"serviceUrl": "https://facebook.botframework.com",
"channelId": "facebook",
"from": {
    "id": "999999999999",
    "name": "StuartD"
},
"conversation": {
    "isGroup": false,
    "id": "999999999999-999999999999"
},
"recipient": {
    "id": "88888888888",
    "name": "Shhhh"
},
"attachments": [],
"entities": [{
    "type": "Place",
    "geo": {
        "elevation": 0.0,
        "latitude": 50.8249626159668,
        "longitude": -0.14287842810153961,
        "type": "GeoCoordinates"
    }
}

      



And in the controller:

var location = message.Entities?.FirstOrDefault(e => e.Type == "Place");
if (location != null) 
{
     var latitude = location.Properties["geo"]?["latitude"]?.ToString();
     var longitude = location.Properties["geo"]?["longitude"]?.ToString();
// etc

      

+2


source







All Articles