Chatbot With Angular and DialogFlow

Posted By :Shreyash Singh |27th November 2020

 

 

There are so many ways to build a chatbot by using a wide variety of collaboration platforms such as Slack, Facebook Messenger, and HipChat etc.

But here we will build a chatbot from scratch to production using Angular (latest release), DialogFlow, and AWS.

 

To get started, we have to create a brand new Angular project using the Angular CLI:

ng new smartchatbot --style=scss

1. The Chatbot Architecture

Here we will split our chat application into different components and where each component will be able to communicate with each others using attribute directives

2. The Message Entity

Here we create an empty class by using the following command:

ng generate class models/message

This message entity will have 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. The Message List Component

Now generate a new component by using below command :

ng generate component components/message-list

Now, we can show(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 component of this 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 we have used @app/models instead of the relative path; it's called an alias. To be able to use aliases, we have to add the paths( as shown below) properties to our tsconfig.json file like this: 

"paths" : {

  "@app/*" : ["app/*"],
  "@env/*" : ["environments/*"]
}

Note: here we have also added @env alias to be able to access environment variables from anywhere in our application. 

4. The Message Item Component

Now let's build a component that will going display a message in our message list so now we will create a component as below :

ng generate component components/message-item

In message-item.component.html, we will add the following :

<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 structure of this 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. The Message Form The Component

 

Now let's build the form through which we will be able to send the messages:

ng generate component components/message-item

Now, In message-form.component.html, we will add the following :

<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 here 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() function will be called each time a user clicks the Send button.

That's it! Now you will see that it's working 

ng serve

Right now At this moment, you won't get any kind response — that's where NLP comes in : 

6. NLP Backend

Here we have choose to go with DialogFlow. Sign up to DialogFlow and create a new chat agent:

Then, follow the step and enable the Small Talk feature to have a simple chat:

Note: Here you can easily change the responses to the questions if you don't like them. moving forward ,now  you can create your own Intents & Entities 

Now you have to copy the DialogFlow Client Access Token. It will be used for making queries.

And then Paste the token into your environments/environment.ts file as shown below :

export const environment = {
  production: false,
  token: 'YOUR DIALOGFLOW TOKEN'
};

7. The DialogFlow Service

Now generate a DialogFlow Service that will make some calls the DialogFlow API to retrieve the corresponding response from it as shown below :

ng generate service services/dialogflow

This uses the DialogFlow API to process normal language in the form of text. Each API requests include the Authorization field in the HTTP header portion :

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;
  }
}

 

Now we have to update the sendMessage() function 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');
  }

And finally, in app.component.html, we will 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. Deploying to AWS

Generate production-build :

ng build --env=prod

This build artifacts will be stored in the dist/ directory.

Next step is , we create an S3 bucket with the AWS CLI as below :

aws s3 mb s3://smartchatbot-mlabouardy

Now we will upload the build to the bucket: 

aws s3 cp dist/ s3://smartchatbot-mlabouardy --recursive --grants read=uri=http://acs.amazonaws.com/groups/global/AllUsers

Finally,we will turns website hosting on for the bucket: 

aws s3 website s3://smartchatbot-mlabouardy --index-document index.html

Now If we point our browser to the S3 Bucket URL, we should see the chatbox. 

 

Thanks, 

Shreyash Singh

 


About Author

Shreyash Singh

Shreyash singh Is a Frontend Developer. He is having a good knowledge of HTML5, CSS3, Bootstrap 4, JavaScript, Angular 6+, TypeScript. He is also good In UX (Sketch).

Request For Proposal

[contact-form-7 404 "Not Found"]

Ready to innovate ? Let's get in touch

Chat With Us