Botkit: Alternative to convo.repeat() with changing variables?

Created on 19 Sep 2017  路  16Comments  路  Source: howdyai/botkit

I'm looking for a way to repeat a question, keep the two default response patterns but use changing variables in the repeated question. From what I understand, a question once asked will remain compiled (for lack of a better term) and not change even if the variable used during creation changed. Here is what I tried:

bot.startConversation(message, (err, convo) => {

  convo.setVar('foo', "bar")

  convo.ask({
    text: "how about {{vars.foo}}?",
    quick_replies: [
       {  content_type: "text",
          title: "yes",
          payload: "YES" },
       {  content_type: "text",
          title: "no",
          payload: "NO" }
      ]}, [

         { pattern: "yes",
           callback: function(response, convo){
              // placeholder for actual logic
              convo.next() }
          },
          { pattern: "no",
            callback: function(response, convo){

                   convo.setVar('foo', "buzz")
                   convo.repeat()
                   convo.next() }
        }])
})

In this example, the goal is to have the first question be "How about bar?" and when repeated "How about buzz". In the actual application, every repetition after a user saying "no" would take the next item from an array of arbitrary length to be inserted and repeat the question. If the user answers with "yes", then move on.

Is there a different approach recommended for this kind of problem?

help wanted

Most helpful comment

Hi @gcfabri. See the code below. I changed the simplified example from above, so please be aware that this isn't the actual working code. So apologies if there are are typos. But the logic should be the same.

bot.createConversation(message, (err, convo) => {

  convo.setVar('foo', "bar")

  convo.addMessage({text:"hi there", action:"my_question"}, 'default')

  convo.addQuestion({
    text: "how about {{vars.foo}}?",
    quick_replies: [
       {  content_type: "text",
          title: "yes",
          payload: "YES" },
       {  content_type: "text",
          title: "no",
          payload: "NO" }
      ]}, [

         { pattern: "yes",
           callback: function(response, convo){
              // placeholder for actual logic
              convo.gotoThread('goodbye_message')
              convo.next() }
          },
          { pattern: "no",
            callback: function(response, convo){

                   convo.setVar('foo', "buzz")

                   convo.gotoThread('my_question')
                   convo.next() }
        }],{},'my_question')

  convo.addMessage({text: "goodbye"}, 'goodbye_message')

  convo.activate()

})

Hope that helps, let me know if you have more questions.

All 16 comments

So I found a way to achieve what I wanted by creating (instead of starting) a conversation, naming the messages / questions and then instead of using convo.repeat() using convo.gotoThread('the_question')

Would still be interested if this is the best approach to repeat a question with changing variables. Thanks!

@CitiVince I am so glad to hear that you achieved this with threads!

I was going to suggest exactly this approach! Yes, this is the best way to achieve what you want to do.

@benbrown great, thanks for your feedback!

Hey @CitiVince, could you give a sample of your code? I'll appreciate.

Hi @gcfabri. See the code below. I changed the simplified example from above, so please be aware that this isn't the actual working code. So apologies if there are are typos. But the logic should be the same.

bot.createConversation(message, (err, convo) => {

  convo.setVar('foo', "bar")

  convo.addMessage({text:"hi there", action:"my_question"}, 'default')

  convo.addQuestion({
    text: "how about {{vars.foo}}?",
    quick_replies: [
       {  content_type: "text",
          title: "yes",
          payload: "YES" },
       {  content_type: "text",
          title: "no",
          payload: "NO" }
      ]}, [

         { pattern: "yes",
           callback: function(response, convo){
              // placeholder for actual logic
              convo.gotoThread('goodbye_message')
              convo.next() }
          },
          { pattern: "no",
            callback: function(response, convo){

                   convo.setVar('foo', "buzz")

                   convo.gotoThread('my_question')
                   convo.next() }
        }],{},'my_question')

  convo.addMessage({text: "goodbye"}, 'goodbye_message')

  convo.activate()

})

Hope that helps, let me know if you have more questions.

@CitiVince , thanks for your attention. Is correct to go to a thread before its creation? I am facing an error on console like: "debug: WARN: gotoThread() to an invalid thread! my_question"

bot.createConversation(message, (err, convo) => {
    const phoneRegex = new RegExp(/^(?:(?:\+|00)?(55)\s?)?(?:\(?([1-9][0-9])\)?\s?)?(?:((?:9\d|[2-9])\d{3})\-?(\d{4}))$/i);
    convo.setVar('sample', _.sample(messageStore.inobraxContact));
    convo.addQuestion('{{vars.sample}}', [
      {
        pattern: phoneRegex,
        callback: (response, convo) => {
          convo.say(_.sample(messageStore.getInTouchSoon));
          convo.next();
        }
      },
      {
        default: true,
        callback: (response, convo) => {
          convo.say('Invalid Response');
          convo.setVar('sample', _.sample(messageStore.inobraxContact));
          convo.gotoThread('question');
        }
      }
    ], 'question');
    convo.activate();
  });

@gcfabri I'm also still discovering the details of botkit, but here are some observations that could help you:

  • at the end of .addQuestion() you're missing an object to extract responses, which in my case is empty but probably needs to be passed along.
convo.addQuestion({text:"something"},[/* patterns & callbacks */], {}, 'thread_name')
  • add convo.next() after convo.gotoThread()

  • you probably need to have one thread named default to define the conversation's entry point. Since you only have the question, try naming that default

Hope that helps!

The convo pushes messages to "ask" or "say" in an array : convo.sent
You can easily change the first message in convo.sent before preforming convo.repeat()
convo.set[0].text = ""How about buzz"

hope that helps !

@Raniazy that's great to know, thank you very much! Can you by any chance point me to a documentation / thread that gives more insights to what's happening behind the scenes?

Hey @CitiVince
Here's a link to botkit's docs : https://github.com/howdyai/botkit/tree/master/docs
it has cool examples

By the way. The solution I gave you was found no where, I just tought about it by chance, and it worked very well. :smile:

@CitiVince thank you. I forgot to add a 'default' thread. It is working properly now.
@Raniazy nice, thank you.

I've tried convo.gotoThread instead of convo.repeat in order to add some convo.say before repeating the question.
My problem is it seems an addQuestion thread has to be named "default" or the question won't fire. But when i'm calling gotoThread("default"), it is the previous question that fire (Q-2), not the last (Q-1). What am I missing?

You can add questions to any thread - just make sure to pass it in as the last parameter to addQuestion. (there are 4 parameters in total)

https://botkit.ai/docs/core.html#convoaddquestion

Hey @benbrown what i 'm trying to understand is:

  1. Is it correct that a thread in convo.addQuestion can only be named "default"?
  2. Is it normal that my firstQuestion will be repeated when call convo.gotoThread in the example below?
firstQuestion = function(response, convo) {
    convo.addQuestion("my first question",
        function(response, convo) {
            switch (response.quick_reply.payload) {
                    case "yes":
                        yesThread(response, convo);
                        break;
                    case "no":
                        noThread(response, convo);
                        break;
                    default:
                        convo.repeat();
                }
                convo.next();
        }, {}, "default"
    );
};

secondQuestion = function(response, convo) {
    convo.addQuestion("my second question",
        function(response, convo) {
            switch (response.quick_reply.payload) {
                    case "yes":
                        yesThread(response, convo);
                        convo.addMessage({text:'Say this before repeat', action: "default"}, "addedMessage")
                        convo.gotoThread("addedMessage"); 
                        break;
                    case "no":
                        noThread(response, convo);
                        break;
                    default:
                        convo.repeat();
                }
                convo.next();
        }, {}, "default"
    );
};

I expect secondQuestion to be repeat instead...

hey @benbrown , I still can't find my way out of this :( any thought on my question above?

Was this page helpful?
0 / 5 - 0 ratings