skip to Main Content

I’m designing a bot using Microsoft botframework in C# which will be deployed on messenger.

On of the features I’m trying to include is displaying attractions around the users location. I’ve 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 the users location as well as a way to store the location so i can use it to do the nearby search.

If anyone could point me in the correct direction I’d be greatly appreciative.

Here’s a nice example of something i’m trying to replicate.
Messenger Requests User Location

User Location is picked up
Location is sent to the bot a relative information is displayed

This is an example of what I’m 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);
        }
    }

The “context.Wait(Stores);” in the ResumeAfter Task is throwing a “The type arguments for method IDialogStack.Wait cannot be inferred from the usage”.

2

Answers


  1. How to get Location from Facebook Messenger

    Have a look to BotBuilder-Location project on GitHub: https://github.com/Microsoft/BotBuilder-Location

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

    sample

    You may be interested in particular in the 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 that was also on the EchoBot sample provided in the 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));
            }
        }
    }
    

    Image of the demo:
    demo

    Login or Signup to reply.
  2. A location which is sent as a message can be accessed from the message’s Entities 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
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search