Charca / bootbot

Facebook Messenger Bot Framework for Node.js
MIT License
974 stars 253 forks source link

Handle unexpected replies from user #108

Closed zeloru closed 6 years ago

zeloru commented 6 years ago

Hello Charca,

User are always curious and enter unexpected replies to test bots. But currently, bootbot doesn't have a way to handle that. It would be great to have something like:

bot.unexpect((payload, chat) => {
    chat.say('I know that you will test me');
    // or
   chat.say('Stop teasing me');
});
temrysh commented 6 years ago

@Charca Same was here: https://github.com/Charca/bootbot/issues/46

zeloru commented 6 years ago

I have a simple solution.

add to Bootbot class:

registerMessages( messages ) { this._messages = messages; }

then we can use:

bot.registerMessages(['hello', 'hi', 'bye'])

in _handleMessageEvent method, add something like:

if keyword not in _messages: emit( this.unexpect )

temrysh commented 6 years ago

@zeloru Is this solving conversation case alike: user is answering to bot's question with two different messages? It is a very common case that users use 'send' instead of 'return'.

zeloru commented 6 years ago

No, unfortunately.

I think Messenger need to tell us if user is typing. Then we can handle the problem correctly. For now, mraaroncruz's anwser is the solution.

zeloru commented 6 years ago

I've found a solution to my problem after reading Bootbot's code.

Since data has captured, we can handle unexpected messages like:

bot.on('message', (payload, chat, data) => {
    const text = payload.message.text;
    if (!data.captured) {
        chat.say("I don't expect that!");
    }
    console.log(`The user said: ${text}`);
});

@tmwd, i've found a workaround to your problem. Because Bootbot allows only 1 answer from user to to our question, to handle 2 or more answers from user, you code something like:

const askFavoriteFood = (convo, nextQuestion) => {
    let question = 'and?'; // or something to confirm user's last answer 
    if(nextQuestion){
        question = `What's your favorite food? Finish with "that's all"`;
    }
        else {
        // you can hack Bootbot code to expose payload, check and save user's message.text
        // if you don't want to response to every user's answer.
        }
        convo.ask(question, (payload, convo, data) => {
        const text = payload.message.text;
        // only ask another question when user finish with "that's all" or whatever you think they may reply
        if (text !== "that's all") { 
            convo.set('food', convo.get('food') + ", " + text); // save user's answer
            askFavoriteFood(convo, false); // nex question is false, call again to handle user's multiple replies
        }
        else {
            convo.say(`Got it, your favorite food is ${convo.get('food')}`).then(() => askGender(convo));
        }
    });
};

const askName = (convo) => {
    convo.ask(`Hello! What's your name?`, (payload, convo, data) => {
        const text = payload.message.text;
        convo.set('name', text);
        convo.say(`Oh, your name is ${text}`).then(() => askFavoriteFood(convo, true)); // next question is true
    });
};
zeloru commented 6 years ago

This issue is closed. But if there is a elegant solution, please let me know.

mraaroncruz commented 6 years ago

@zeloru The way the convo.ask() method works is that it takes

If you look at the docs, you can see some examples of using the expected answers array to set up how you expect the user to react to your question. You can match on regex, exact text, expect a postback or quick reply response.

Then in the fallback answer, you can catch unexpected things and react there.

I don't see how captured is relevant in your situation but maybe I just don't understand your question. captured is meant to be used for the bot level handlers, if you match more than one, bootbot will respond to multiple. You can use captured to see if another bot level handler (ex. bot.on('message', handlerFunc)) has already responded to the incoming message.

I hope that helps. If you have any more questions, you can ask in our slack.

And please close the issue if it's closed. Thank you!