To continue from where we left over-
Step8. Setting up our webhook:-
Now we’ll shell out our serverless webhook function so that we can progressively build on it as we go along by typing below command-
serverless create --template aws-nodejs --path invoiceBot
This will create a nodejs boiler plate . “path” in above command simply means ” path to the folder where I want to create my webhook “
This will use read made boilerplate to setup basic shell that deploys as an aws lambda as shown in above figure.
As you can see we’ve handler.js file ,where our nodejs code will reside. You can see we’ve function called “hello” being exported out of this file. This is our lamda function where you’ve an incoming event which brings in “GET” or “POST” parameters & when you return this object ,you’re returning response , which has an http status code of 200 and body which carries back stringify JSON object . You can also configure custom header as needed. And all of this without the need of bootstrap and express or restify server.
This file is written using yaml, A language that is simple to understand and is bit like JSON without curly braces. Remove all the commented codes so it becomes easy to read and comprehend.
This file tell us that our service will be named “Invoicebot” on aws lambda and it’ll use “nodejs12.x” version. This version no. is not something that you can arbitrarily set .aws offers limited support for nodejs versions and this changes from time to time.
Right now I can see one lambda function called “hello”. The “handler” is actual function that serves the “hello” lambda . “handler.hello” refers to handler.js and module called “hello” inside of it which is exported out from that file.Let’s change this to “invoiceBot”. Likewise change the function name to “invoiceBot” in handler,js file too.
Advantage of Lambda function:-
Since lambda functions are invoked ondemand and they’re not online all the time ,so huge advantage that you get as a result is that you’re billed for only that tiny amount of time when the function is up and running and not when it’s idle.And functions are invoked one events . You can run functions on all kinds of events across aws services.
What we want here is DialogFlow should be able to post requests to URL which should then run on our webhook function .This will be made possible using aws api gateway service, which is sort of bridge between the outside world and our function.The Gateway offers the URL ,to where client can place calls and when the call is received , It routes the call to lambda within http event . This event then triggers the function, which then respond and response is then relayed back to the client .
Let’s define when exactly this lambda function should respond . This will be done by block called “events”, where we’ll need “http” event . The first thing that we’ll set here is “path” , which is endpoint name itself, in our case “invoicebot”.
Notice that this is all lower case as opposed to the name of our function ,which has an uppercase “B” in “invoicebot”. “path” should ideally be in lowercase , though it’s not any convention of any sort. Finally we’ll define “post” http method ,that will trigger this lambda .A post request placed to the URL ,which framework will provide , will trigger this function. Last but not least, we’ll create new block called “plugins” . The serverless framework has community of plugins that simplifies and sweeten up your development workflow . Once such plugin is “serverless-offline”, which allows you to run your webhook locally while in development as a server. So first we’ll add it in yml file and then I’ll run below command to initialize and create a package.json file.
Now I’ll install serverless-offline as development dependency by typing below command-
npm i serverless-offline --save-dev
This enables us to finally type “sls offline” or “serverless offline” to bring up our webhook as server locally. Our webhook is now being severed locally on port “3000”.
Step 9. IAM policy for accessing secrets
Now the lambda function that we’re going to write needs to talk to SSM parameter store for fetching and decrypting the private key , client Email & sheet Id that we’ve stored earlier. On aws , any resource that wishes to talk to another resource must possess an IAM policy. This policy is a document that explicitly grants granular permission not just to services but its macro level features. For instance you may only read parameters but not right to them. A lambda function also needs to possess such policy and here’s what it looks like.
This is a JSON object written in a very specific format as defined by Amazon. Here “Action” is very specific task that you’re requesting permission for , in our case we want to get parameters from SSM service. The “Effect” defines whether you wish to allow or not a particular service. And “Resource” is a unique Amazon resource name that is assigned to everything on aws. It incorporates service name ,ssm ,region(where we’re operating in) , amazon account ID and finally what are you trying to access , in our case parameters ,all parameters start with word “parameter/<parameter 1>.
"aarn:aws:ssm:<region name>:<Amazon account ID>:parameter/*
Asterisk (*) simply says this policy applies to all parameters in our store. This policy is a JSON object and we need to define this in serverless.yml file. So let’s write as follows-
You can get your “Amazon account ID” by going to “My Account” section of “aws.amazon.com”.
Step 10. Accessing secrets in webhook:
Now since our lambda function has an IAM policy that grants it permission to read and decrypt secret from SSM parameter store. Let’s actually use them access secrets in our webhook so we can read them when needed. So first we need to install aws-param-store package. This package provides easy to access helper function that can be used to fetch and decrypt secrets & parameters from SSM parameter store. This package internally uses official aws sdk. So you have to download that as well by using below command-
- npm i firstname.lastname@example.org
- npm i email@example.com
Here we’ve written one function which will access our credentials (emailID & password) from SSM parameter store and these secrets/credentials will be used further in our code.
Kindly note that if one is hesitant to store credentials or other such sensitive information on cloud then they can put their environment variables, configurable stuffs or other credentials in configuration file called yml file which they can access in their code further.
Step 11. newBill Intent:-
In Dialogflow we’ll add some training phrases like below, which will trigger this intent.
- I wish to want generate a new invoice
- Take new order
- new order
- take new quotation
- New quotation
- I wish to make new quotation
While building chatbot for production, you can add all sort of training phrases which you think customer may type in his query.
And you can keep on adding all kinds of user phrases here. Then we’ll hit on “Enable webhook call for this intent” under “Fulfilment” tab. It enables webhook call when this intent is reached. Make sure you hit the save button to not only save changes but also to let dialogflow internally train the Natural Language processing model to recognise the training phrases that have been added and act accordingly.
Step 11 . Actions and Parameters in Dialogflow:-
This is where you ask user to give inputs like below and tag it with some parameter to store user’s input so It can be relayed back to your code ,in which you handle user’s inputs as per your needs-
- Please provide Organization name..
- Please input invoice number..
- Please provide product details..
- How much advance do you want customer to pay ?
Let’s say you tag each of the above actions with OrgName , invNum, prdDetails & advance respectively.
And you need to tag each parameter with one Entity. There’re bunch of system entities available already. However you can always create a list of custom entities of your own.
Step 12 .Handling newBill Intent:-
Whenever Dialogflow calls our webhook , It sends an object like below-
This object contains many things but we’re interested in “displayName” property from the Intent object which spells the name of intent being fired. You can thus use it to create handlers for all kinds of intents as per your NLP model. Therefore we’ll extract queryResult object first by parsing the incoming body of the post request that we get through event.body then from this incoming object we’ll extract displayName property like so.
This is our handler.js file where we’re handling the newBill Intent. Similar to this you can create handler to handle all kinds of intents as per your NLP models.
first we extract queryResult by parsing incoming body of post request which we get through event.body then from this incoming object we’ll extract displayName property.Then we’ll simply use if block to check if displayName is newBill. If so then we’ll handle the response and return a response back to dialog flow so it can be relayed back to use on whatsapp.
Now we need a function that fetches the content of user’s input (for eg, Org Name, Invoice No.,Product Details etc) and transform data as per our need. So for that we’ve written one function called “getQuotation”. This we’ll talk about in our next post. So stay tuned!!