aichaos / rivescript-js

A RiveScript interpreter for JavaScript. RiveScript is a scripting language for chatterbots.
https://www.rivescript.com/
MIT License
377 stars 144 forks source link

slack buttons / rich UI components / metadata #238

Open dcsan opened 7 years ago

dcsan commented 7 years ago

Message Buttons

Using Rivescript for Slack/FBM etc authoring, do you have any thoughts how to support the richer UI elements and markup? For example Slack Buttons https://api.slack.com/docs/message-buttons

so we would have to extend Rivescript somehow to support this simple way is to add a type like:

inline commands

+ choose one!
- /button red | I like red!
- /button blue | pick blue

so its like /button $msg | $label where msg is what would get sent back to us as a chat message. This would be simple to author, but a bit of hassle to author.

json blocks

Another way is to add support for JSON metadata, perhaps with a { ... } type:

+ choose one!
{ 
// json goes here
    "text": "Would you like to play a game?",
    "attachments": [
        {
            "text": "Choose a game to play",
...
}

this is the direct JSON format from slack. I can see writers messing that JSON up very easily tho we could try a simpler format, but I think slack has probably tried to make it as simple as possible so any reduction would limit what can be done.

functions / parameters

Another way is to have button templates somewhere and use parameters:

+ choose one!
- /choice_dialog prompt="choose a color", b1label="pick red", b2label="choose blue"

but it's getting quite complex for authors, esp if we start having var="string" quotes that have to be in the right place etc.

so the params could be in a JSON block. If you want to have more complex dialogs, you would create another template. We could also use a YAML format or something simpler than JSON to remove quotes and other sources of errors.

+ choose one!
{ 
   template: yesno_dialog
   button1:
      label: Choose Red!
      message: picked_red
   button2:
...
}
kirsle commented 7 years ago

For some of your idea examples, a question I have is: would the buttons be attached to a specific -Reply or would they globally apply to the entire trigger? If it's to the entire trigger that's easier on the back-end to work with, because it can deal with conditions and random replies like it currently does, and then just attach the buttons to whatever the bot picked. If they're reply-specific, it will need to keep track of which reply has which buttons (and it might also be tedious to author because you might have to copy/paste the buttons for each reply on a trigger...)

I have an idea of my own for syntax: use HTML-style buttons.

I don't know if RiveScript bot authors are currently embedding a lot of HTML in their responses, but with tags like <div> taking up valuable HTML real estate, I would hope that's not the case. :smile: I might want to add something like a {raw}...{/raw} tag that blocks all tag processing from inside it and leaves everything verbatim, so if the user did want a literal HTML button (not a magic one that helps with Slackbots) they'd wrap it in a {raw} tag.

// This example assumes buttons are attached to each `-Reply` which, again,
// would be tedious to author... maybe we need a new command to attach
// out-of-band data for this, which is what some of your examples suggested
+ choose one
- What color do you want?
^ <button value="red">I like red!</button>
^ <button value="blue">I like blue!</button>

An idea for an "out-of-band data" could be better generalized as "reply suffix", so we might use a command character like & ("and") or $ ("suffix"), and be like...

+ choose one
- What color do you want?
- Which color do you like?
- Which of these colors is your favorite?
& <button value="red">I like red!</button>
& <button value="blue">I like blue!</button>

// As another example not having anything to do with buttons,
// but to show how the & command normally would behave...
//    User: how are you?
//    Bot: I'm great! How are you?
//    -or- Bot: Good! How are you?
+ how are you
- I'm great!
- Good!
- I'm doing fine.
& How are you?

The & commands would all concatenate a common suffix to the end of any reply the bot would've chosen otherwise. Multiple & commands concatenate onto the end of the last one, like ^Continue does for most other commands.

It could concat by inserting a space character by default because this is what I'd think most people would expect, so it won't require you to do ! local concat = space in all your source files.

kirsle commented 7 years ago

To elaborate more:

The <button> tag would become a proper RiveScript tag that it would parse and make a data structure out of. It would support all the usual attributes (name, value, etc.) -- actually, it might just leave the attributes arbitrary and collect them all. Then if you want to support e.g. confirmation pop-ups in your Slack bot, you could be like

<button value="red" confirm="Are you sure?" confirm-ok="OK" confirm-cancel="Cancel">I like red!</button>

...and your bot's back-end would look up those attributes and turn them into Slack params.

And then after the reply returns, you could call like rs.getButtons(username) or rs.lastButtons(username) or something and it would return the buttons that the most recent reply included. If the most recent reply had no buttons, it would return something like null or undefined.

So the usage would be like:

bot.replyAsync(username, message, this).then(function(reply) {
    let buttons = bot.lastButtons(username);
    let slackButtons = [];
    if (buttons !== undefined) {
        buttons.each(function(button) {
            slackButtons.push({
                type: "button",
                name: button.name,
                value: button.value,
                text: button.text
            });
        });
    }

    slack_client.sendMessage(username, {
        "text": reply,
        "attachments": [ slackButtons ]
    });
});
dcsan commented 7 years ago

HTML syntax sounds like a good idea, and makes sense to implement for various platforms eg FBM

I'm a bit wary of the syntax to prepend lines, with & we have been bitted sooo many times by someone re-ordering lines to move a ^ to start of a block, then we get no response... is there any reason we can't have inline JSON blocks?

+ choose one!
{
  "button": {
      "label": "red"
   }
...
}

it's a bit hacky (personally I prefer YAML) but people know JSON. then you could also use JSON parsers to validate etc. or maybe CSON or some other simpler markup without all the damn quotes etc.

or i guess if you want html then just enclose it in {{ }} like a templating language?

{{
<button label='red'/>
}}
zbrba commented 7 years ago

Hey all, just a quick message to check in on this.

Has anything been implemented or does anyone have an example of how they do this?

We'd love to be able to tie metadata with a specific response and have that accessible.

//Something like the above:
+ choose one
- Which of these colors is your favorite?
& <button value="red">I like red!</button>
& <button value="blue">I like blue!</button>

//Where a:  
var reply = brain_rs.reply('test user', 'choose one');

//Would yield reply as:
{
reply: 'Which of these colors is your favorite?',
meta: '<button value="red">I like red!</button><button value="blue">I like blue!</button>'
}

//Or better yet:
+ choose one
- Which of these colors is your favorite?
& {buttons: [{code: 'red', label:' I like red!'}, {code: 'blue', label:' I like blue!'}]}

{
reply: 'Which of these colors is your favorite?',
meta: {buttons: [{code: 'red', label:' I like red!'}, {code: 'blue', label:' I like blue!'}]}
}

Any thoughts on how to attach this type of data to the response? Or if there is a better way I'd really appreciate the input.

dcsan commented 7 years ago

you could write your own post parser, so when you get the reply back from the Rivescript you JSON.parse() it? a bit silly but that seems to be the current state.

dcsan commented 7 years ago

I tried to think of a mini protocol that would be scalable, so that if someone is playing on a text-only client they could still have a playable experience. you could even describe inline games in this way

https://docs.google.com/presentation/d/1Gb5aza9MJpPl3KG08grO4mccrnwJV9KDdb0b5xJK43g/edit?usp=sharing

image

it's a bit out of date now since i wrote that up before Messenger platform, but we did something like that with RiveScript before.