Linking QiChat and Code

Giving smart answers: adding callbacks

So, we know how to control QiChat from code. Now let’s look at the other direction: controlling our code from QiChat.

We can trigger code callbacks from QiChat:

  1. With a bookmark
  2. With variable callbacks
  3. With an ^execute statement

1. Callbacks on bookmarks

First, it’s a bit annoying that we have to restart our whole app every time we want a new question.

Let’s add a user rule instead of a question, so that we can just ask “challenge me”:

u:(challenge me) %MULTIPLY_CHALLENGE
Okay, what's, $numberA times, $numberB ?
   u1:($result)
   Right! %RERANDOMIZE
   u1:(~wrongNumbers)
   Wrong! %RERANDOMIZE

Of course, Pepper will still ask the same question ... so add this bookmark listener in onRobotFocusGained:

randomize()
qiChatbot.addOnBookmarkReachedListener {
   when (it.name) {
       "RERANDOMIZE" -> randomize()
   }
}
// Start the dialogue
chat.run()

Now, each time you ask for a new challenge, you will get a different question.

Bookmarks are also very useful for triggering anything in the rest of your code: robot movement, web services, tablet display, etc.

But for tablet display, let’s use variables:

2. Callbacks on variables

Now let’s say want to show numbers on the tablet; we’ll use a variable, $show, that will contain the text we want to show on the tablet:

u:(challenge me) %MULTIPLY_CHALLENGE
Okay, what's, $numberA times, $numberB ? $show="$numberA x $numberB"
   u1:($result)
   $show="right!" right! %RERANDOMIZE
   u1:(~wrongNumbers)
   $show="wrong!" wrong! %RERANDOMIZE

Open the activity layout, and select the main text label (that should say “Hello World!”):

  • Make it very large, like “80sp”
  • Set its id to “tabletLabel”
    You can now a callback to the $show variable in onRobotFocusGained, and set this view’s text content.:
qiChatbot.variable("show").addOnValueChangedListener {
   runOnUiThread {
       tabletLabel.text = it
   }
}

... now the tablet will reflect in real time the value of the QiChat variable.

3. Blocking calls with ^execute

Now, let’s say we want to add a bit of suspense in our answer; something like:

  • What’s seven times eight
  • Uh, forty-eight
  • forty-eight … (pause) … wrong! It’s 56!

How would we implement that pause?

One way to do it is with an ^execute statement; like a bookmark, an ^execute can trigger a callback in the code, but unlike the bookmark, this callback will be executed synchronously - i.e. Pepper will not speak until the call is done.

u:(challenge me) %MULTIPLY_CHALLENGE
Okay, what's, $numberA times, $numberB ? $show="$numberA x $numberB"
   u1:($result)
   $result ^execute(drumRoll) $show="right!" right! %RERANDOMIZE
   u1:(_~wrongNumbers)
   $1 ^execute(drumRoll) $show="wrong!" wrong! It's $result ! %RERANDOMIZE

Because of its blocking nature, the code to handle an executor is a bit more complex, you will need to:

  • Build a dedicated “executor” object
  • Pass a table of executors to the Chatbot
    So in your onRobotFocusGained, add:
val executors : Map<String, QiChatExecutor> = hashMapOf(
   "drumRoll" to DrumRollExecutor(qiContext)
)
qiChatbot.executors = executors

You then need to create a dedicated “DrumRollExecutor” class, as an inner class of the main activity:

private inner class DrumRollExecutor(qiContext: QiContext) :
       BaseQiChatExecutor(qiContext) {
   override fun runWith(params: List<String>) {
       Thread.sleep(1_000)
   }
   override fun stop() {}
}

This could be a good place to play an actual drum roll sound (using android’s media player).

4. Differences between different ways of triggering callbacks

In this step we’ve seen three different ways to call code from QiChat; here are their main differences:

%BOOKMARK

  • Non-interrupting
  • You can’t pass parameters

$variable=value

  • Non-interrupting
  • Useful for simple cases
  • Not called if the assigned value is the same!

^execute(funcName, param1, param2)

  • Interrupts the sentence
  • You can pass any number of parameters

The interrupting vs. non-interrupting distinction is important: “How %SHOWTABLET are you today?” will be pronounced correctly, but “How ^execute(showTablet) are you today?” will be pronounced as “How. Are you today?”

In general, you should mostly use bookmark for simple cases, and ^execute for when it’s really needed - when you need to block the sentence or, as we’ll see in next step, when you need to pass several parameters.