Stephan Goosen
Stephan Goosen

Reputation: 11

Bot Framework: Tagging messages

So, when a bot sends a message through Bot Connecter, it sends it as a JSON object, that lookks something like:

{
  "type": "message",
  "timestamp": "2017-07-20T06:35:09.196Z",
  "serviceUrl": "http://127.0.0.1:53484",
  "channelId": "emulator",
  "from": {
  "id": "ijfi3f969c6fij756",
  "name": "Bot"
},
"conversation": {
"id": "g671h707amhch9326"
},
"recipient": {
"id": "default-user"
},
"membersAdded": [],
"membersRemoved": [],
"text": "Hey there!",
"attachments": [],
"entities": [],
"replyToId": "efincfmnc40la0g7c",
"id": "hi959g2a8ji1fn86",
"localTimestamp": "2017-07-20T08:35:09+02:00"
}

We would like to add a few additional tags, to carry a bit more data about the message being sent. For example, we might want to add a tag that shows we are expecting the user to reply with an email address. Perhaps something like:

{
"type": "message",
"expecting": "email"
"timestamp": "2017-07-20T06:35:09.196Z", "serviceUrl": "http://127.0.0.1:53484", "channelId": "emulator", "from": {
"id": "ijfi3f969c6fij756", "name": "Bot" },

The idea is, that we'd like to use our custom tags to run additional code. Something we might want to do, for example, is:

if(reply.Expecting.Equals("email")
{
  //Do something awesome here.
}

But, we haven't been able to find any information on how to customize these JSON messages. Is it possible? And if so, how would we go about it?

Upvotes: 1

Views: 313

Answers (2)

Mohan Kumar DB
Mohan Kumar DB

Reputation: 128

Assuming that you are using .net Framework.

below is one option i can think of. Introducing custom properties to the Activity

Implement Activity class on your CustomActivity class

 public class CustomActivity : Activity
    {
        [JsonProperty(PropertyName = "cutomprop")]
        public string MyCustomProp { get; set; } = "Custom Prop";
    }

Then while posting back replies consider creating Activity of type CustomActivity and do copy all props of original Activity to it (use tool Automapper for this purpose)

private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<object> result)
    {
        var activity = await result as Activity;

        ConnectorClient client = new ConnectorClient(new Uri(activity.ServiceUrl));

      var reply = new CustomActivity
        {

            ChannelData = activity.ChannelData,
            ChannelId = activity.ChannelId,
            ServiceUrl = activity.ServiceUrl,
            Name = activity.Name,
            Action = activity.Action,
            Type = activity.Type,
            Conversation = activity.Conversation,
            Code = activity.Code,
            From = activity.From,
            Value = activity.Value,
            Text = activity.Text,
            InputHint = activity.InputHint,
            Attachments = activity.Attachments,
            Entities = activity.Entities,
            ReplyToId = activity.ReplyToId,
            AttachmentLayout = activity.AttachmentLayout,
            HistoryDisclosed = activity.HistoryDisclosed,
            Id = activity.Id,
            LocalTimestamp = activity.LocalTimestamp,
            Locale = activity.Locale,
            MembersAdded = activity.MembersAdded,
            MembersRemoved = activity.MembersRemoved,
            Properties = activity.Properties,
            Recipient = activity.Recipient,
            RelatesTo = activity.RelatesTo,
            Speak = activity.Speak,
            SuggestedActions = activity.SuggestedActions,
            Summary = activity.Summary,
            TextFormat = activity.TextFormat,
            Timestamp = activity.Timestamp,
            TopicName = activity.TopicName

        };

        reply.Text = "I have colors in mind, but need your help to choose the best one.";
        reply.Type = ActivityTypes.Message;
        reply.TextFormat = TextFormatTypes.Plain;
       //set any other prop you want as per your needs
        await client.Conversations.SendToConversationAsync(reply);
        context.Wait(MessageReceivedAsync);
    }

Below is the output i got

{
  "cutomprop": "Custom Prop",
  "type": "message",
  "id": null,
  "timestamp": "2017-07-20T12:44:41.504Z",
  "localTimestamp": "2017-07-20T18:14:41+05:30",
  "serviceUrl": "http://127.0.0.1:56931",
  "channelId": "emulator",
  "from": {
    "id": "default-user",
    "name": "default-user"
  },
  "conversation": {
    "id": "h0j9hn8bicfm8e509"
  },
  "recipient": {
    "id": "mcfimjke5aebemhf",
    "name": "Bot"
  },
  "textFormat": "plain",

Hope that helps... consider validating it for your scenario and look out for any other side effects . **not tested it on all channels, it works on emulator

Upvotes: 1

user8086575
user8086575

Reputation:

You can accomplish this with middleware. Here's the C# docs, and the NodeJS docs.

Basically, you set up your middleware off of the bot object:

bot.use({
    botbuilder: (sess, next) => {
        inbound(sess, next);
    }
    ,send: (evt, next) => {
        outbound(evt, next);
    }
});

...where botbuilder captures what the user sends and send captures what the bot sends.

Then you can define functions to deal with the messages, and alter them if you find that to be appropriate:

function inbound(sess: builder.Session, next: Function): void {
     console.log(sess.message);
    next();
}

function outbound(evt: builder.IEvent, next: Function): void {
    console.log(evt);
    next();
}

My recommendation is to not alter the message data structure itself, but to instead do your custom behaviors using the middleware, since altering these messages could have side effects. You can easily capture what you need to in the middleware, and then pass arguments to the next() function to allow the subsequent dialog to handle expectations.

Also, if all you're doing is trying to capture expected user input, regular expression matches with intent dialogs or trigger actions works quite well.

Upvotes: 1

Related Questions