Integrating a Chatbot: Dialogflow

Integrating into the QiSDK application

Now that we know we have a class that can communicate with Dialogflow, let’s plug it in a QiSDK Chatbot.

The way Chatbots work in the QiSDK:

When a human says something, each active chatbot receives an input, a string corresponding to what the human said, and returns a ChatbotReaction (i.e. a possible output) object along with a reply priority. The system will then evaluate all possible reactions, choose one (depending on priority), and execute it.

So now we will create:

  • A DialogflowChatbot object
  • The ChatbotReactions

Create your chatbot reactions

A ChatbotReaction corresponds to an action taken by the chatbot; e.g. typically making Pepper speak (but reactions could also play animations, display content on the tablet, etc.)

We have two kinds of reactions to create:

  • One to make the robot say something
  • One for when there is nothing to say

In your "app" module, create a new class called “SimpleSayReaction”, and give it this code:

class SimpleSayReaction internal constructor(context: QiContext, private val answer: String) :
   BaseChatbotReaction(context) {
   private var sayFuture: Future<Void>? = null

   override fun runWith(speechEngine: SpeechEngine) {
       val say = SayBuilder.with(speechEngine).withText(answer).build()
       sayFuture = say.async().run()
       try {
           sayFuture?.get() // Block until action is done
       } catch (e: ExecutionException) {
           Log.e("SimpleSayReaction", "Error during say: %e")
       }
   }

   override fun stop() {
       sayFuture?.requestCancellation()
   }
}

This will be a basic block that your chatbot will use anytime the robot speaks.

You will also need a reaction for when the chatbot doesn’t have an answer - for now, it doesn’t need to do anything. Create a new class called “EmptyChatbotReaction” and add following code in it

class EmptyChatbotReaction internal constructor(context: QiContext)
   : BaseChatbotReaction(context) {

   override fun runWith(speechEngine: SpeechEngine) {}
   override fun stop() {}
}

Create the actual chatbot

Now that we have our reactions, we can create a Chatbot class, that will

  • Call our Dialogflow library
  • Create the right reaction depending on the result

First create a “DialogflowChatbot” class, and give it this code:

class DialogflowChatbot internal constructor(context: QiContext,
                                            credentialsStream : InputStream
)
   : BaseChatbot(context) {
   companion object {
       private val TAG = "DialogflowChatbot"
   }
   private var dialogflowSessionId = "chatbot-" + UUID.randomUUID().toString()
   private val dataSource = DialogflowDataSource(credentialsStream)

   override fun replyTo(phrase: Phrase, locale: Locale): StandardReplyReaction {
       val input = phrase.text.toString()
       val language = locale.language.toString()
       var answer : String? = null
       try {
           answer = dataSource.detectIntentTexts(input, dialogflowSessionId, language)
           Log.i(TAG, "Got answer: '$answer'")
       } catch (e: Exception) {
           Log.e(TAG, "error", e)
       }
       return if (answer != null) {
           StandardReplyReaction(
               SimpleSayReaction(qiContext, answer), ReplyPriority.NORMAL
           )
       } else {
           StandardReplyReaction(
               EmptyChatbotReaction(qiContext), ReplyPriority.FALLBACK
           )
       }
   }
}

Note: be careful with the “Locale” class, make sure to import the one from the QiSDK and not from java.util.

Then in your MainActivity, make sure you have the usual QiSDK lifecycle calls (QiSDK.register etc.), and create and run a “chat” action containing this chatbot in your onRobotFocusGained callback:

private lateinit var chat : Chat

override fun onRobotFocusGained(qiContext: QiContext) {
   val credentials = applicationContext.resources.openRawResource(R.raw.credentials)
   val dialogflowChatbot = DialogflowChatbot(qiContext, credentials)
   chat = ChatBuilder.with(qiContext).withChatbot(dialogflowChatbot).build()
   chat.async().run()
}

Run it!

You can now run this application on Pepper and get an answer from Dialogflow.