To make Iris understand variations of text and understand the user's intent, we will now run all questions asked through the natural language processor.
- [Instructor] What's the best way to add Wit to our project? The easiest way would be to simply add this API request into handleOnMessage on slackClient here. While this seems legit, it means tight coupling between the natural language processing API we use and the slackClient itself. What if we later decide to use another service for that or to implement the language processing part locally? So I'd rather move this into a dedicated module and pass it into slackClient as language processing service to be used.
So let's create a file witClient.js in our Server folder. Right-click on Server, select New File, then type in witClient.js. On top of it, we will again add use strict. And now we will use another way of initiating a function. This time, we will use a different pattern as in slackClient to initialize a module.
So we add module.exports equals function, we call it witClient, and it takes a token. Now let's create an inner function or closure. So we define the variable, ask equals function ask, and this function takes a message.
For now, we will just log out the message and the token for that we add console.log ask and log out the message. Let's copy-paste this and change this to token and log out the token here. The interesting thing here is that token is not part of this inner function, but it's defined in this enclosing scope, and we will see what this is all about a little bit later.
One important part is now that we have to return something from this initialization function, so we return some anonymous object, and this object contains a function ask, ask property, that we also call ask. Now in run.js, we will now define the Wit token as we did it with the Slack token before, put it right above the Slack token, const witToken equals, and we stored it before, I have it in this wit.txt file, so hit Copy, and paste it over here.
And now we will initialize our witClient by adding const witClient equals require, we have to add the path here again, it's in server slash witClient, and we call this init function directly with this witToken as parameter here.
We want to use our witClient in our slackClient, so we add witClient as new parameter here, and now in slackClient we now add a new module global, nlp, it's null, and we also have to add this new parameter here, so we call it nlpClient, and then store this in this variable here, nlp equals nlpClient.
In handleOnMessage, we will now use this by calling let's remove this console log here and replace it with nlp.ask(message). In this case, not message, but message.txt, because the message is this whole object and text contains really what the user typed in into Slack. Let's try this out now. So let's start IRIS again, node run, bin/run.js, oh, we have an error here, what is it? We have a typo in this require, or are we missing something from the path? Yes, this require, we have to add a slash here, let's try it again.
Now it runs, and let's open Slack again and type in some message. IRIS has returned with our test message here, and on our console we see that the message is a log and also the token. Interestingly, the token is locked out, even though we returned the ask function and called it out of its context. This is what makes closure so powerful, they maintain this code in which they have been declared.
Now in witClient.js, on top of it, we will now require this SuperAgent, we call it request equals require superagent. For the request itself, let's revisit the API request we coded before. So we see that we have to add a header field with the Bearer token. And maybe there is a module for it, so let's look at the source code.
You see, as we discussed before, we can now think about if it really makes sense to add this new dependency to our project, because we see that the implementation is actually quite frivolous, so we will do it on our own. So now open Visual Studio Code again, open witClient.js, and in ask, we will now implement this request and add request.get, and we will use this API string here, let's copy this part from here, put it into witClient, and we have to add a few things here so on this request we set this authorization bearer, and this is quite easy, so we have just to add a field Authorization and add Bearer plus our token and then we have this run query parameter here, the query and we have it right here in Wit, it will be this string here, this number, so we add this as object v is this number here, and then we have to add our query and the query obviously is the message we got, so we add query, q, is message.
And when the request returns, so on end, we get a callback back with error and response as parameter, like that, and the callback function will now contain first an error handler, so if there is an error we return the callback and now we see already that ask actually has to be an asynchronous function that takes a callback at this callback up here, because that's a function that is to be called when this function returns asynchronously, and so return, if an error, we return the callback with the error and to terminate this call.
If we add another way of error logging because if the result is that status code is not 200, because this is the HTTP code for everything is fine, we will return the callback with an error message saying Expected status 200 but got plus statusCode we actually got, that's fine.
Now we will use a helper function that can deal with this response from Wit, because it does not make sense to implement all of that now inside this API query function, so we will add const witResponse equals handleWitResponse and this gets the result dot body, and how could this handleWitResponse look like? We will put it up here, because it does not have to be part of the exported module, and simply call it function handleWitResponse and it gets some response and for now we will simply log this out just to see that everything is working.
Next we have to change the call to ask in slackClient because, remember, we are now asynchronous and we need a callback to be passed in. So we open slackClient and add to this nlp.ask we add this callback again as a six error function that takes an error or a result and will then first deal with the error again, so if there is an error what should we do then? I would say we should first log it out, because for us, for debugging purposes, to know what was wrong.
But then we will simply return from this function and just do nothing here. And when we are finally done we want to send a message with an answer here, for now we will just copy this message part here. So we will first fix the indentations here. So we will first call the natural language processor and if everything goes well we will for now just again send out our test message here.
Or let's change the little bit here and call it Sorry, I did not understand. Because currently we don't understand it. Let's save this, and let's try this out. So we run IRIS again, now we open Slack again, so what should now happen? We are now asking a question, and this time it should already be something that matches what we configured in Wit, so we ask what's the time in Rome? Looking into our terminal, we see that Wit correctly returned us an intent and a location, and now we just have to build this in properly in our slackClient.
So let's update our ask method again and work with this result object we get here. So if let's handle some case if we get no intent back, no intent object as we see here in the terminal, so if there is no res.intent, we will return a message on Slack that will be return rtm.sendMessage, and what will we reply on this case? We will reply Sorry, I don't know what you are talking about.
And we also have to declare define the channel where it has to be sent to, as before, message.channel. Next we handle the case when everything went right, so we use result dot intent, and as we see here, intent is actually an array, so we use this first array argument here, so res.intent.value equals time, so it's a time intent and we get a location object as well.
This is already great, but currently we still cannot handle this properly, so we will return a new message, let's copy this here, and the message will be, let's use back ticks here, then we can use variables here. Back ticks, and we will tell the user I don't yet know the time in and this is stored in res.locaton.value, and we send it to message.channel.
And then for any other yet unhandled intents, so there is this else condition, again, return that we currently don't know what is talked about, but we will also in this case log out the response because we just want to know which data we got here that we can handle at a later time. So now let's save this and let's re-run IRIS and ask how late is it in Vienna? What we forgot is that now in witClient we have to actually in the end, let's remove this for now, and we have to call the callback to return here.
That's quite typically an error here, actually. So when everything went fine, we actually want to return the response, so we will simply return it here by calling the callback response, because what we did, we actually never called the method, we just created the callback method we just created here in slackClient. So let's try it, actually it should work now, and ask again.
And let's also review here the handleWitResponse as we see here, we'll have this console.log, and here we have to actually return res.entities here. Let's rerun this and ask again how late is it in Vienna, and we get a response back that yet we don't know the time in Vienna, but we will actually know very soon. So in this video, we set up natural language processing to let IRIS understand the meaning of a question.
Next we will implement the microservices and logic that provides the answer to that.
After explaining some basics about Node.js and microservices, Daniel shows you how to sketch out the planned architecture for your application and get the boilerplate code, modules, and credentials in place. Next, he shows how to create a bot user in Slack, connect to Slack, and post messages. He also shows you how to get your bot to process variations in text by creating logic that delegates the processing of intent to dedicated modules. Lastly, he shows how to register additional services and he covers how to use monitoring to identify architectural or performance issues.
- Using Slack APIs
- Sketching out a Slack bot architecture
- Setting up a project and choosing modules
- Creating and naming your bot
- Connecting to Slack
- Setting up and using natural language processing
- Routing by intents
- Implementing geocoding and time calculation
- Adding and monitoring services