Chatbot With Angular 5 and DialogFlow
I have seen many posts on how to build a chatbot for a wide variety of collaboration platforms such as Slack, Facebook Messenger, HipChat ... So I decided to...
Join the DZone community and get the full member experience.
Join For FreeI have seen many posts on how to build a chatbot for a wide variety of collaboration platforms such as Slack, Facebook Messenger, and HipChat. So, I decided to build a chatbot from scratch to production using Angular (latest release v5.0.0), DialogFlow, and AWS.
Here is how our chatbot will look at the end of this post:
Note: This project is open-source and can be found on my GitHub.
To get started, create a brand new Angular project using the Angular CLI:
ng new smartbot --style=scss
1. Chatbot Architecture
We will split our chat app into different components and each component will be able to communicate with others using attribute directives:
2. Message Entity
Create an empty class by issuing the following command:
ng generate class models/message
The message entity has three fields:
export class Message {
content: string;
timestamp: Date;
avatar: string;
constructor(content: string, avatar: string, timestamp?: Date){
this.content = content;
this.timestamp = timestamp;
this.avatar = avatar;
}
}
3. Message List Component
Generate a new component:
ng generate component components/message-list
Now, we can display the messages by iterating over them:
<div class="chatlist">
<ul class="list-group">
<message-item *ngFor="let msg of messages" [message]="msg"></message-item>
</ul>
</div>
The code of this component should look like this:
import { Component, OnInit, Input } from '@angular/core';
import { Message } from '@app/models';
@Component({
selector: 'message-list',
templateUrl: './message-list.component.html',
styleUrls: ['./message-list.component.scss']
})
export class MessageListComponent implements OnInit {
@Input('messages')
private messages : Message[];
constructor() { }
ngOnInit() {
}
}
Note the usage of @app/models
instead of the relative path; it's called an alias. To be able to use aliases, we have to add the paths
properties to our tsconfig.json
file like this:
"paths" : {
"@app/*" : ["app/*"],
"@env/*" : ["environments/*"]
}
Note: I also added @env
alias to be able to access environment variables from anywhere in our application.
4. Message Item Component
Let's build a component that will simply display a message in our message list:
ng generate component components/message-item
In message-item.component.html
, add the following content:
<li class="list-group-item">
<img [src]="message.avatar" class="avatar"/>
<div class="message">
{{message.content}}
</div>
<div class="timeform">
<i class="fa fa-clock-o" aria-hidden="true"></i> <span class="timestamp">at {{message.timestamp | date : 'dd/MM/yyyy' }}</span>
</div>
</li>
The code of the component should look like this:
import { Component, OnInit, Input } from '@angular/core';
import { Message } from '@app/models';
@Component({
selector: 'message-item',
templateUrl: './message-item.component.html',
styleUrls: ['./message-item.component.scss']
})
export class MessageItemComponent implements OnInit {
@Input('message')
private message: Message;
constructor() { }
ngOnInit() {
}
}
5. Message Form Component
Let's build the form that will be responsible for sending the messages:
ng generate component components/message-item
In message-form.component.html
, add the following content:
<div class="chatcontrol">
<input type="text" class="form-control chatinput" [(ngModel)]="message.content"/>
<button class="btn btn-success sendbtn" (click)="sendMessage()">Send</button>
</div>
...and its corresponding typescript code in message-form.component.ts
:
import { Component, OnInit, Input } from '@angular/core';
import { Message } from '@app/models';
@Component({
selector: 'message-form',
templateUrl: './message-form.component.html',
styleUrls: ['./message-form.component.scss']
})
export class MessageFormComponent implements OnInit {
@Input('message')
private message : Message;
@Input('messages')
private messages : Message[];
ngOnInit() {
}
public sendMessage(): void {
this.message.timestamp = new Date();
this.messages.push(this.message);
this.message = new Message('', 'assets/images/user.png');
}
}
The sendMessage()
method will be called each time a user clicks the Send button.
That's it! Try it by yourself and you will see that it's working.
ng serve
At this moment, you won't get any response — that's where NLP comes into play
6. NLP Backend
I choose to go with DialogFlow. Sign up for DialogFlow and create a new agent:
Then, enable the Small Talk feature to have a simple chat:
Note: You can easily change the responses to the questions if you don't like them. To go further, you can create your own Intents & Entities as described in my previous tutorial.
Copy the DialogFlow Client Access Token. It will be used for making queries.
Paste the token into your environments/environment.ts
file:
export const environment = {
production: false,
token: 'YOUR DIALOGFLOW TOKEN'
};
7. DialogFlow Service
Generate a DialogFlow Service that will make calls the DialogFlow API to retrieve the corresponding response:
ng generate service services/dialogflow
It uses the DialogFlow API to process natural language in the form of text. Each API requests include the Authorization field in the HTTP header.
import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Observable } from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import { environment } from '@env/environment';
@Injectable()
export class DialogflowService {
private baseURL: string = "https://api.dialogflow.com/v1/query?v=20150910";
private token: string = environment.token;
constructor(private http: Http){}
public getResponse(query: string){
let data = {
query : query,
lang: 'en',
sessionId: '12345'
}
return this.http
.post(`${this.baseURL}`, data, {headers: this.getHeaders()})
.map(res => {
return res.json()
})
}
public getHeaders(){
let headers = new Headers();
headers.append('Authorization', `Bearer ${this.token}`);
return headers;
}
}
Update the sendMessage()
method in MessageFormComponent
as follows:
public sendMessage(): void {
this.message.timestamp = new Date();
this.messages.push(this.message);
this.dialogFlowService.getResponse(this.message.content).subscribe(res => {
this.messages.push(
new Message(res.result.fulfillment.speech, 'assets/images/bot.png', res.timestamp)
);
});
this.message = new Message('', 'assets/images/user.png');
}
Finally, in app.component.html
, copy and paste the following code to include the message-list
and message-form
directives:
<div class="chatform">
<message-list [messages]="messages"></message-list>
<message-form [message]="message" [messages]="messages"></message-form>
</div>
8. Deployment to AWS
Generate production-grade artifacts:
ng build --env=prod
The build artifacts will be stored in the dist/
directory.
Next, create an S3 bucket with the AWS CLI:
aws s3 mb s3://smartbot-mlabouardy
Upload the build artifacts to the bucket:
aws s3 cp dist/ s3://smartbot-mlabouardy --recursive --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers
Finally, turns website hosting on for your bucket:
aws s3 website s3://smartbot-mlabouardy --index-document index.html
If you point your browser to the S3 Bucket URL, you should see the chatbox:
And that's it!
Published at DZone with permission of Mohamed Labouardy, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments