If you've ever spoken to voice-based personal assistants such as Siri or Google Now, or chatted with one of the many text-based bots active on messaging platforms such as Facebook Messenger and Kik, you probably realize how fun, intuitive, and powerful conversational user interfaces can be. However, because most natural languages are extremely complex, creating such interfaces from scratch tends be hard. Fortunately, there's IBM Watson.
By using the IBM Watson Conversation service, you can create AI-powered conversational user interfaces in minutes, often with just a few lines of code. In this tutorial, I'll introduce you to the service and show you how to use it in Android apps.
Prerequisites
To make the most of this tutorial, you'll need the following:
- an IBM Bluemix account
- the latest version of Android Studio
- a device running Android 4.4 or higher
1. Creating a Conversation Service
Before you can use the the IBM Watson Conversation API, you must create a Conversation service on the IBM Bluemix platform and acquire login credentials for it. To do so, sign in to the Bluemix console, navigate to Services > Watson, and press the Create Watson service button. In the next screen, choose Conversation from the catalog of available services.
In the configuration form that's displayed next, type in an appropriate name for the service and press the Create button.
2. Creating a Conversation Workspace
A Conversation service can work only if it has at least one Conversation workspace associated with it. For now, you can think of a workspace as a collection of rules and configuration details, which defines the capabilities and personality of your conversational UI.
The Bluemix console has an easy to use tool that allows you to create and manage workspaces. To launch it, press the Launch tool button.
In the next screen, press the Create button to create a new workspace. In the dialog that pops up, give a meaningful name to the workspace and choose a language for it.
Once the workspace has been created, you are expected to add intents, entities, and dialog details to it.
While intents defines actions a user can perform using your conversational UI, entities define objects that are relevant to those actions. For example, in the sentence "book me a ticket from New York to Chicago", "book a ticket" would be an intent, and "New York" and "Chicago" would be entities. Dialog details define the actual responses the conversational UI generates, and how its conversations flow.
Step 1: Create Intents
In this tutorial, we'll be creating a very simple Android chatbot capable of performing the following actions:
- greet the user
- introduce itself
- quote inspirational quotes
Accordingly, our chatbot needs three intents.
Press the Create New button to create the first intent. In the form that shows up, name the intent #Greeting, provide a few sample words or sentences the user might use for the intent, such as "hi" and "hello", and press the Done button.
The best thing about the Watson Conversation service is that it intelligently trains itself using the sample user inputs you provide to the intent. Consequently, it will be able to respond to several variations of those sample inputs. For example, it will be able to correctly match words and phrases such as "howdy", "good morning", and "yo!" to the #Greeting intent.
Press the Create New button again to create the next intent. Name it #Name, and provide the following user examples.
Similarly, name the third intent #RequestQuote, and provide the following user examples.
Step 2: Create a Dialog
Our chatbot is so simple that we don't need to define any entities for it. Therefore, we can now directly start specifying how it responds to each intent we created.
Start by going to the Dialog tab and pressing the Create button. In the next screen, you'll see that two dialog nodes are created for you automatically: one named Welcome, which is to greet the user, and one named Anything else, which is to catch inputs the bot doesn't understand.
For now, let's leave the Anything else node as it is, and configure the Welcome node. In the dialog that pops up, type in #Greeting in the If bot recognizes field, and then add a few responses. Obviously, the more responses you add, the more human-like your chatbot will be.
Next, create a new node for the #Name intent by pressing the Add Node button. Again, fill the form shown appropriately.
The node for the #RequestQuote intent is going to be slightly different. We won't be manually typing in a few inspirational quotes as the responses of this node because doing so would make our bot too static and uninteresting. Instead, our Android chatbot should be able to fetch quotes from an external API. Therefore, the responses of this node should be sentences that ask the user to wait while the bot searches for a new quote.
At this point, our workspace is ready. You can test it right away by clicking the speech balloon icon. Feel free to test it with a variety sentences to make sure that it associates the right intents with them.
Step 3: Determine Credentials
To be able to use the Conversation service in an Android app, you'll need its username and password. Additionally, you'll need the ID of the Conversation workspace. Therefore, go to the Deploy section and switch to the Credentials tab.
You should now be able to see the credentials you need. After noting them all down, you can close the Bluemix console.
3. Android Studio Project Setup
Although it is possible to interact with the Conversation service using any Android networking library, using the Watson Java SDK is a better idea because it offers a very intuitive and high-level API. To add it to your Android Studio project, add the following compile
dependency in the app
module's build.gradle file:
compile 'com.ibm.watson.developer_cloud:java-sdk:3.7.2'
Additionally, we'll be needing the Fuel networking library to fetch inspirational quotes from a remote server, and the Design support library to able to work with a few Material Design widgets.
compile 'com.android.support:design:23.4.0' compile 'com.github.kittinunf.fuel:fuel-android:1.9.0'
Both Fuel and the Watson Java SDK require your app to have the INTERNET
permission, so don't forget to ask for it in your project's manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
Lastly, open the res/values/strings.xml file and add the Conversation service's username and password, and the Conversation workspace's ID to it as <string>
tags:
<string name="username">1234567890-abde-12349-abdef</string><string name="password">ABCD123456</string><string name="workspace">abdefg1234567890-abcdef</string>
You can now press the Sync Now button to complete the project setup.
4. Defining a Layout
We will be creating a text-based bot in this tutorial. Therefore, our app's layout should contain an EditText
widget where users can type in their messages, and a TextView
widget where the user-bot conversation can be shown. Optionally, you can place the EditText
widget inside a TextInputLayout
container to make sure that it follows the Material Design guidelines.
It's also a good idea to place the TextView
widget inside a ScrollView
container to make sure that long conversations aren't truncated.
<android.support.design.widget.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:id="@+id/user_input_container"><EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="Message" android:id="@+id/user_input" android:imeOptions="actionDone" android:inputType="textShortMessage"/></android.support.design.widget.TextInputLayout><ScrollView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/user_input_container"><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/conversation" android:textSize="16sp" /></ScrollView>
Note that we've set the value of the EditText
widget's imeOptions
attribute to actionDone
. This allows users to press a Done button on their virtual keyboards when they've finished typing their messages.
5. Using the Conversation Service
The ConversationService
class of the Watson SDK has all the method's you'll need to communicate with the Conversation service. Therefore, the first thing you need to do in your Activity
class is create an instance of it. It's constructor expects a version date, the service's username, and its password.
final ConversationService myConversationService = new ConversationService( "2017-05-26", getString(R.string.username), getString(R.string.password) );
Next, to be able to work with the widgets present in the layout XML file, you must get references to them using the findViewById()
method.
final TextView conversation = (TextView)findViewById(R.id.conversation); final EditText userInput = (EditText)findViewById(R.id.user_input);
When the users have finished typing their input messages, they will be pressing the Done button on their virtual keyboards. To be able to listen to that button-press event, you must add an OnEditorActionListener
to the EditText
widget.
userInput.setOnEditorActionListener(new TextView .OnEditorActionListener() { @Override public boolean onEditorAction(TextView tv, int action, KeyEvent keyEvent) { if(action == EditorInfo.IME_ACTION_DONE) { // More code here } return false; } });
Inside the listener, you can call the getText()
method of the EditText
widget to fetch the user's message.
The TextView
widget will be displaying both the messages of the user and the replies of the bot. Therefore, append the message to the TextView
widget using its append()
method.
final String inputText = userInput.getText().toString(); conversation.append( Html.fromHtml("<p><b>You:</b> " + inputText + "</p>") ); // Optionally, clear edittext userInput.setText("");
The user's message must be sent to the Conversation service wrapped in a MessageRequest
object. You can create one easily using the MessageRequest.Builder
class.
MessageRequest request = new MessageRequest.Builder() .inputText(inputText) .build();
Once the request is ready, you must pass it to the message()
method of the ConversationService
object, along with the workspace's ID. Finally, to actually send the message to the Conversation service, you must call the enqueue()
method.
Because the enqueue()
method runs asynchronously, you will also need a ServiceCallback
object to get the service's response.
myConversationService .message(getString(R.string.workspace), request) .enqueue(new ServiceCallback<MessageResponse>() { @Override public void onResponse(MessageResponse response) { // More code here } @Override public void onFailure(Exception e) {} });
Inside the onResponse()
method, you can call the getText()
method of the MessageResponse
object to get the Conversation service's response.
final String outputText = response.getText().get(0);
You can now append the response to the TextView
widget again using its append()
method. However, make sure you do so inside the runOnUiThread()
method because you are currently on a different thread.
runOnUiThread(new Runnable() { @Override public void run() { conversation.append( Html.fromHtml("<p><b>Bot:</b> " + outputText + "</p>") ); } });
Our bot is almost ready. If you try running the app, you'll be able to get correct responses from it for the #Greeting and #Name intents. It still can't recite inspirational quotes though. Therefore, we must now add code to explicitly look for the #RequestQuote intent and generate a response manually.
To extract the name of the detected intent from the MessageResponse
object, you must call its getIntents()
method, which returns a list of MessageResponse.Intent
objects, pick the first item, and call its getIntent()
method.
if(response.getIntents().get(0).getIntent() .endsWith("RequestQuote")) { // More code here }
There are many websites with free APIs you can use to fetch inspirational quotes. Forismatic is one of them. Its REST API provides quotes as plain text, which you can directly use in your app.
To make an HTTP request to the Forismatic API's URL, all you need to do is call the get()
method of the Fuel
class. Because the method runs asynchronously, you must handle the HTTP response by calling the responseString()
method and passing a Handler
object to it.
Inside the success()
method of the handler, you can simply append the quote to the TextView
widget. The following code shows you how:
String quotesURL = "https://api.forismatic.com/api/1.0/" + "?method=getQuote&format=text&lang=en"; Fuel.get(quotesURL) .responseString(new Handler<String>() { @Override public void success(Request request, Response response, String quote) { conversation.append( Html.fromHtml("<p><b>Bot:</b> " + quote + "</p>") ); } @Override public void failure(Request request, Response response, FuelError fuelError) { } });
The bot is now complete, and will be able to generate the right responses for all the intents we added to the workspace.
Conclusion
Conversational user interfaces are all the rage today. They are so easy to use that everybody loves them. In this tutorial, you learned the basics of creating such interfaces on the Android platform using the IBM Watson Conversation service.
There's a lot more the service can do. To learn more about it, you can refer to the official documentation.
And be sure to check out some of our other posts on using machine learning for your Android apps!
- Machine LearningCoding an Android App With IBM Watson Machine Learning
- Android SDKHow to Use Google Cloud Machine Learning Services for Android
- Android SDKHow to Use the Google Cloud Vision API in Android Apps
- Android SDKCreate an Intelligent App With Google Cloud Speech and Natural Language APIs
- Android ThingsAndroid Things and Machine Learning