Video: Bots: 12. Building custom components in Intelligent Bots – SDK
[MUSIC] Truly understanding the Oracle Intelligent Bots SDK is a key knowledge required for custom component developers. This video is all about the SDK. Welcome. My name is Frank Nimphius and I am from the Oracle Mobile Platform Team. And with no further ado, Let's go straight in. To communicate with a custom component, the bot sends a request payload that contains the bot context. The context includes the state of variables defined in the dialog flow, results from the language recognition, entities extracted from the user input, as well as input parameters defined for the component.
And those that have both? Well, you guess! The text function gives you access to the recent user text input. It allows you, for example, to pass the user- provided input string to a search engine, or to parse it in the custom component for the information that you're interested in. The input string may be the string that got processed by the Oracle Intelligent Bots NLP engine, but could also be other text provided by the user. Note that it's always the last user input that you have access to. If your custom component has input parameters defined, then using the properties function is how you access the parameter values. In this example, the component input parameter names are entityName and nlpResultVariable. It's important for you to understand, however, that the properties function does not reference context variables, as they are defined in the dialog flow, but only those that you have defined for the custom component.
The nlpresult function gives you access to the entities that were extracted from a user string. A good use case for when to use this function is when you have an unknown number of entities in a sentence. Let's take a currency converter as an example. Users may request the conversion of a base amount and a base currency into multiple target currencies. How many? Well, you don't know. So this is where the nlpresult function comes in handy, because it returns an array of entities matching a provided entity name. The request function returns the full payload the component service receives from the bot as part of the component POST method invocation. Though I said I'm only introducing those functions that I think are frequently used, this is not one of them! However, I think it's very important to know about the request function if you're an advanced developer.
For example, you may want to log the incoming bot payload or parse information not exposed through the SDK. Be mindful, however, when using the request function: it requires a very good, in-depth understanding of the JSON structure of the bot payload. This is why it's advanced. Messenger clients don't behave the same in terms of functionality they support and the layouts they can render. And we'll talk about layouts in a minute. So to optimize the custom component response for a specific messenger client, you need to know what client the bot is talking to. The channelType function provides this information to you. At the time of recording, the channel types it detects are Facebook, Webhook, and Tester, which is the identifier used for the visual tester embedded in Oracle Intelligent Bots. To the time when you watch this video, there are most likely other channels that we support–and that it can access–from this function.
You use the variable function to read from, and write to, context variables defined in the dialog flow. As shown in this example, you can also use the variable function to read from the user profile. And of course, you can read and write to user scope variables, too. As a reminder, user scope variables are defined with a user string followed by a "dot" as a prefix of the variable name. If you write to a variable that does not exist in the current context of the user scope or the dialog scope, then this variable will be created. A use case for creating context variables in the code or for a custom component is if a component wants to keep track of its own internal state in cases where the component is called more than once in the course of a conversation. The reply function allows you to send responses back to the bot for display in the messenger client. As shown in the sample, you can see multiple replies within a single component response, with each message displayed in its own bubble. Well, agreed–text bubbles don't make a very compelling layout, so how about lists, cards, or even carousel? Depending on the type of the messenger that is used, you have an option to build better layouts.
For example, Facebook Messenger supports a variety of templates which are all documented on the Facebook developer website. Let me give you an example. The code you see here is from a bot that queries animal pictures from the pixabay.com website. Each animal is displayed on a card in a carousel with its name and image using the Facebook Messenger generic template. As you can see, the response is composed as a JSON document according to the Facebook template requirements, and then passes an argument to the SDK reply function. The transition function allows custom components to suggest a next state for the Dialog Engine to navigate. The function is called either with no arguments, or with a string argument that matches an entry in the supported action property of the component metadata. The bot designer associates a return action string with a state in the dialog flow to navigate to. For example, let's assume we build a component that returns a formatted string for a date.
The component metadata has two supported actions defined: "success," in case of a parsing success, and "invalidArgument," in the case that the string cannot be parsed into at formatted date. Now let's follow the happy path and assume that the date parsing turned out to be very successful. In this case, a custom component returns the success string as an outcome, as defined in the component metadata. The BotML that we see here defines the two outcomes of the custom component as actions. The actions are mapped to states that are defined within the dialog flow. In case of successful date parsing, the custom component returns the success string, which in this example, leads to the dialog flow navigating to the handleParseSuccess state. This is how conditional outcomes of a custom component can influence the flow of a conversation the bot has with the user.
So when would you use an empty argument in a call to a transition? Hmm. The empty argument actually is a convenience for custom components with a single outcome. A call to transitions with no argument just does what it says: it triggers the Dialog Engine to navigate to the next state without indicating what the next state should be. I mean, what if you don't call transition at all? Well, in this case, the component finishes its work, but the Dialog Engine doesn't navigate to a next state. This means that the next user input again hits the same custom component. A use case for when not to transition is when a custom component integrates with backend systems that need to go into a dialog with the user to complete the task. Here the custom component passes the user conversations through while not transitioning until the backend system is satisfied. The keepTurn function probably is the hardest to understand, especially when put in combination with the conversation.
transition. So let's start with an analogy before looking at a technical use case. In a typical human conversation, participants talk in a sequence, which means that Person A says something that Person B responds to, and then Person A says something new, which Person B voices another response, and so on. Bots behave the same, in that a user input is followed by a bot response. This bot response then is followed by another user input, which could be a selection from a choice, or a new input. Also, in human conversation, it may happen that User A says something that User B responds to with multiple replies. For example imagine you're in Rome: "Excuse me, sir. Can you tell me how to get from here to the Colosseum?" "Of course, so let me get my map…so we are here you want to go there..
. so this would be the direct route…I wouldn't recommend this…You want to take public transportation…." I guess you got the idea. Well, the same needs to be possible with a bot conversation in which the bot responds with one, two three, four–or many replies–without the user issuing another response. And this is what exactly keepTurn will help you with. Now let's look at the technical example. Say you've created a custom component that updates a context variable with a list of values. In this example, the context variable name is listdata and the list of values is defined as a comma-separated string. To display the list of data, a System.List component is used to reference the listdata variable. So in your custom component, you issue a conversation.transition to transition to a next state that holds this very same component. Normally, as a conversation between the bot and a user is sequential, the user would need to provide a response. However, in this case, no user input is required. So to suppress the need for user input, your custom component needs to call conversation.
keepTurn (true). With conversation.keepTurn set to true, the transition from the custom component state to the System.List happens immediately and the values saved by the variable are displayed. For use cases where you don't want this to happen, but you want to have the user provide input in between, you need to call keepTurn(false). The only exception to this is when you use conversation.reply because this will implicitly set keepTurn to false. Phew! [exhales] The last part definitely was hard to understand, right? I hope I did a good job here and you are all well set knowing when to use keepTurn(true) and when not. However, it seems, now, we're done. Oh, wait! Wait! Wait! Wait! Wait! You probably have seen on the code lines that there is a done() called at the end of each, so maybe I should lose a word on what this is all about.
done() is not a function of the SDK, but a callback that is passed from the shell object to the component's invoke function. The callback must be invoked by the custom component to signal to the shell object that it has finished its work. Without calling done() at the end, no response will be sent to the bot, which means the bot keeps on waiting until eventually, it times out. So with this information, we are really done. So I hope you enjoyed this video and hope you tune back into this channel for the next. [MUSIC].