Published on

How to create a Chatbot using Angular + Node.js - Part 2

Our Chatbot in action!

Figure 1: Our Chatbot in action!

In this world of ever increasing demand for customer support, Chatbots are extensively used by numerous organizations, ranging from small start-ups to Fortune 500 companies, to fill this growing need. That’s why in this post we are going to reveal how to build a Chatbot using Angular, Node/Express.js and Google Dialogflow!

This post is part 2 of 2 in this series so if you haven’t read the first post here please do so, as this post is a continuation of the first. As for the main content for this post, we are going to cover the setup & implementation of the frontend Angular application for our Chatbot.

Frontend Setup

First we need a new Angular application, so run the ng new <project_name> command in order to build it. In the prompts that follows, chose to include Angular routing while selecting CSS as the stylesheet format.

Angular CLI in action!

Figure 2: Angular CLI in action!

Now, we can create the Chat and Message components in our Angular app by running these commands:

ng generate component chat
ng generate component message

The Chat component will hold the chat window itself while the Message component will be used for each message in the chat modal.

We will also need to create a service for the Chat component so let’s do so by navigating into the chat directory and running the following command:

ng generate service chat
Folder structure for the Chat component

Figure 3: Folder structure for the Chat component

After this, we have to define our models for this application. To do so, add a new folder in the src/app path called models. Next, create 3 typescript files to house our model definitions called: message-model.ts, response-message.model.ts, and text-message.model.ts. Finally, let’s add the following code blocks to their corresponding model files:

// for message-model.ts file
export class Message{
    text?: string;
    date: string;
    userOwner: boolean;
}
// for response-message.model.ts file
export class ResponseMesssage{
    responseMessage?: string;
    originalQuery?: string;
    intent?: string;
}
// for text-message.model.ts
export class TextMessage{
    firstname: string;
    text: string;
}

Environment File Setup

An important part of this Angular application is the /environments/environment.ts file(you’ll have to create it if its not already present), because it contains all the data required to connect with the Dialogflow API and the backend application. Here is the code for this file:

// for the environments/environment.ts file
export const environment = {
  production: false,
  firstName: '<your_first_name_here>',
  dialogflow: {
    projectId: "<your_dialogflow_project_id_here>"
  },
  backend: {
    baseUrl: "http://localhost:3000/",
    apiUrl: "http://localhost:3000/api/",
    requestTextUrl: "http://localhost:3000/api/requestText/"
  }
};

And an explanation as to what we just added:

  • The production variable declares that we are in a development environment
  • The firstName field is used by the Chat component to differentiate between the end user’s messages and the Chatbot’s messages. Enter your name for it’s value
  • The dialogflow.projectId variable will need your Dialogflow project’s Project Id as it’s value(if you don’t have a Dialogflow project, check out part 1 of this series to learn how to create one). This can be found in the Edit Agent page on the Dialogflow console(see the screenshot below for more details)
  • The backend.requestTextUrl variable is the backend URL to which chat message data is sent to
Your Project Id can be found in the Edit Agent page

Figure 4: Your Project Id can be found in the Edit Agent page

Now with the application file structure complete, let’s add the logic for our components.

Chat Component Setup

First open the Chat component’s ts file and add the following code:

  export class ChatComponent implements OnInit {
  BACK_ENABLED: boolean = true;
  @Input('messages') messages: Message[];
  @Input('colorBackRight') colorBackRight : string;
  @Input('colorFontRight') colorFontRight: string;
  @Input('colorBackLeft') colorBackLeft: string;
  @Input('colorFontLeft') colorFontLeft: string;

  textInput: string = '';

  constructor(private chatService: ChatService) {}

  ngOnInit() {
  }

  sendMessage() {
    let newMessage: Message = {text: this.textInput, date:"", userOwner:true};

    this.messages.push(newMessage);
    let messageBack: TextMessage = {"firstname": environment.firstName, "text": this.textInput};
    if (this.BACK_ENABLED) {
        this.chatService.sendMessage(messageBack)
        .subscribe((res: ResponseMesssage) => {
            console.log(res);
            let messageReturn: Message = { text: res.responseMessage, date: new Date().toDateString(), userOwner: false}
            // let messageReturn = {"text": res.json().speech_answer, "date": "", "userOwner": false};
            this.messages.push(messageReturn);
        });
    }
    this.textInput = '';
  }

  onKey(event: any) {
    if (event.keyCode == 13) {
      this.sendMessage()
    }
  }
}

Let’s do a quick overview of the important sections we just added:

  • @Input('messages') and @Input('color...') decorators are used to recieve and store input data from the App component into variables in this component. The color decorators are for the Chat window UI, by the way
  • textInput variable will hold the text provided into the chat message box in the Chat window UI
  • The sendMessage() method first creates a TextMessage instance with your first name(how to add this variable will be covered shortly) and your inputted text. Then it sends a POST request to the backend with the TextMessage instance in the request body so that the backend can send that data to Dialogflow via an API call
  • The onKey(event: any) method is just an event listener that calls the sendMessage() method whenever the user hits the Enter key

Now, in the chat.component.html file, let’s build out the Chat component’s UI by adding the following code:

<!--  for chat.component.html file-->
<div class="list-messages">
  <div *ngFor="let message of messages" class="message-container">
    <app-message class="message" [text]="message.text" [date]="message.date" [colorBackRight]="colorBackRight" [colorFontRight]="colorFontRight"
    [colorBackLeft]="colorBackLeft" [colorFontLeft]="colorFontLeft" [owner]="message.userOwner"
    [ngClass]="{'left-message': !message.userOwner, 'right-message': message.userOwner}"></app-message>
  </div>
</div>
<div class="input-message form-group">
  <textarea class="input-text-message form-input" [(ngModel)]="textInput" placeholder="Type text here" (keyup)="onKey($event)"></textarea>
  <i class="fa fa-paper-plane fa-2x input-send" aria-hidden="true" (click)="sendMessage()"></i>
</div>

Finally, we’ll need CSS styles for our Chat component so let’s add the following CSS styles to the chat.component.css file:

/* for chat.component.css */
.list-messages {
    display: flex;
    flex-direction: column;
    height: 88%;
    overflow: auto;
}

.left-message {
    display: flex;
    margin-left: 10px;
}

.right-message {
    display: flex;
    justify-content: flex-end;
    margin-right: 10px;
}

.input-message {
    border-top: 2px solid grey;
    height: 12%;
    background-color:lightskyblue;
}

.input-text-message {
    height: 100%;
    width: 80%;
}

.input-send {
    color: #007bff;
    position: relative;
    left: 7px;
    top: -22px;
}

Chat Service Setup

Let’s not forget to setup our ChatService class. Here is the code for the chat.service.ts file:

export class ChatService {
  constructor(private http: HttpClient) { }


  httpOptions = {
    headers: new HttpHeaders({
      'Access-Control-Allow-Origin':'*',
    })
  };
  sendMessage(textMessage: TextMessage){
    var reqBody = {
      "projectId": environment.dialogflow.projectId,
      "requestText": textMessage.text
    }

    return this.http.post(environment.backend.requestTextUrl, reqBody, this.httpOptions)
  }
}

Now for a general overview of it’s functionalities:

  • The httpOptions object holds the necessary header information required to bypass the CORS policy(visit the Mozilla CORS page for more information on this)
  • The sendMessage method creates and sends a request body, containing the text message received from it’s textMessage parameter along with the Dialogflow Project Id, to the backend. That text message is then sent from the backend to the Dialogflow API to which Dialogflow issues a response that makes its way back to our front application

Message Component Setup

As the second order of business: we must add the typescript logic to the Message component’s ts file. Here is the logic for the message.component.ts file:

export class MessageComponent implements OnInit {
  @Input('text') text: string;
  @Input('date') date: any;
  @Input('owner') owner: boolean;
  @Input('colorBackRight') colorBackRight : string;
  @Input('colorFontRight') colorFontRight: string;
  @Input('colorBackLeft') colorBackLeft: string;
  @Input('colorFontLeft') colorFontLeft: string;

  constructor() { }

  ngOnInit(): void {
  }
}

As you can see, the Message component just takes in color information for it’s UI from the Chat component.

Now let’s build the Message component’s html file:

<div *ngIf="owner" class="content-message right-content">
    <p [ngStyle]="{'background-color': colorBackRight, 'color': colorFontRight}">
        {{text}}
    </p>
</div>
<div *ngIf="!owner" class="content-message left-content">
    <p [ngStyle]="{'background-color': colorBackLeft, 'color': colorFontLeft}">
        {{text}}
    </p>
</div>

Note: If you’re wondering what the purpose of the owner variable is, it is to indicate whether a Message instance is from the Chatbot or the actual end user.

Finally, similar to the Chat component, we need to add the CSS styles for the Message component. Let’s do so in the message.component.css file:

/* for message.component.css */
.content-message {
    width: 80%;
}

.right-content {
    text-align: right;
}

p {
    display: inline-block;
    padding: 5px;
    border-radius: 10px;
}

App Component Setup

Finally, we will setup the default component created for every Angular application ever created: the App component.

First, let’s add the following code to the app.component.ts file:

export class AppComponent {
  title = 'angularChatBot';
  colorBackRight: string = '#007bff';
  colorFontRight: string = '#ffffff';
  colorBackLeft: string = '#eeeeee';
  colorFontLeft: string = '#343a40';
  messages = [];
}

As you see, we’re just defining the desired colors for the Chat component’s UI, along with creating a messages array that will store all the messages transferred between the end user and the Chatbot.

Next up is the App component’s template file app.component.html:

<div class="center chat-container container">
    <app-chat [messages]="messages" [colorBackRight]="colorBackRight" [colorFontRight]="colorFontRight"
    [colorBackLeft]="colorBackLeft" [colorFontLeft]="colorFontLeft" class="center"></app-chat>
</div>

The above template file renders the Chat component to the Angular application’s homepage along with passing the color variables as data to it.

Lastly, we need to provide a CSS style to the div.chat-container element so let us do so in the app.component.css file:

/* for app.component.css */
.chat-container {
    width: 300px;
    height: 550px;
    margin: auto;
    margin-top: 50px;
    border: 1px solid black;
    padding: 0px;
}

Run The Application

All that’s left to do is to start up the backend on one Terminal instance(or CMD if you’re on Windows) and the frontend on another via the npm start command.

After that, just visit http://localhost:4200 on your browser and you should see the following UI:

Your Project Id can be found in the Edit Agent page

Chat application homepage

Figure 5: Chat application homepage

Conclusion

Congrats if you made it this far! You should now have a fully functionally Chatbot application. If you have any questions or concerns please feel free to post a comment below and I will get back to you if I find time.

I hope you found this article helpful. Thanks so much for reading my article! Feel free to follow me on Twitter and GitHub, connect with me on LinkedIn and subscribe to my YouTube channel.