Develop Your Own Voice assistant using Flask and deploy using OpenShift

Ankush Chavan
15 min readMar 27, 2021

The world is always amazed by looking at the technological progress that we are making in the field of automation and Artificial Intelligence that brings comfort to our lives. There are multiple things involved in this evolution and one of the key aspects of this intelligence is speech recognition technologies. On daily basis, we use voice assistants like Siri, Google Assistant, etc multiple times. Have you ever wondered how these voice assistants work? And if you could able to create your own?

In this article, I will show you how to develop your own voice assistant from the scratch and as we progress, we will add lots of advanced features to this assistant like it can automatically provision an entire Hadoop cluster for you or it can launch EC2 instances for you and many more. Not only that, this article will guide you on how to create a CI/CD pipeline for your code using Jenkins and deploying the backend on the AWS cloud. We will create the web app using one of the Python frameworks Flask. Interesting? Further, we will deploy this web app using OpenShift so that we can utilize the extended capabilities of the traditional Kubernetes.

First of all, let us see what we will be covering and building in this article.

RoadMap of this project:

  1. Creating WebApp using Flask
  2. Creating backend using Python and CGI
  3. Deploying the backend on AWS cloud
  4. Installing Jenkins on AWS EC2 instance
  5. Creating a CI/CD pipeline using Jenkins
  6. Adding speech recognition to the Web App
  7. Deploying Web App using RedHat OpenShift

Step 1: Creating WebApp using Flask

For creating Web Apps using Flask we must be required python installed and using the pip(python package installer) we will install the Flask library.

$ pip3 install flask

When we create an app in Flask, the entry point of the application is the app.py file. Inside this app.py file, we will write all of the routes for our web app.

Flask automatically detects the HTML files present inside the templates/ directory as templates. So, we will place all of our HTML files inside the templates/ folder.

app.py

Here, the / route is the default route of the application.

Now, as the user come to the application, we need to present them the menu of the services that we are offering. For presenting the menus, we will create a menu.html page inside the templates/ folder and add a route /menu to it.

For presenting the different services, we will create the webpages of the respective services inside the templates/ folder as shown below.

Web App file structure

Currently, we are implementing AWS, Linux Commands, Docker, Hadoop cluster, and Kubernetes Cluster features.

You can find the code for Web App here —

Step 2: Creating backend using Python and CGI

The backend of this application includes the code that will actually execute on the servers to provide the desired functionality. This code is generally a python script that will do certain things like running Linux commands or provisioning a Kubernetes cluster, etc. As this code is running on the servers, the Web App should come to the appropriate file and provide the information that is required to run the backend code. For this purpose, we need to use the concept of Common Gateway Interface (CGI). Using the concept of CGI, we will create endpoints on the server, and using these endpoints the WebApp can call and use the backend services.

For using the concept of CGI, we will install the httpd web server on the servers.

$ yum install httpd

The httpd web server will provide us one folder named /var/www/cgi-bin/, inside this folder, we will write all of our backend code.

But this code will be executed by the apache user and for some commands, we need to provide the sudo password. But we can't provide passwords directly to the prompt through the Web App. So, we will go to the /etc/sudoers file and change the configuration of the apache user. We will allow an apache user to run all commands and we will disable the password prompt for this user.

/etc/sudoers file

Now, we are ready to write the backend code.

Let’s look at one of the backend codes for running the Linux commands.

comamnd.py

Making the command.py file executable.

$ chmod +x command.py

For running the above file, the request from the Web App should come with a field variable named command. This variable contains the command that the user had asked to run. The script above will retrieve the command from the field variable named command and provide this command to the run_command() function that will execute this command on the server and finally the output of the command will be sent back to the Web App as a response. This overall concept acts as an API call.

Let’s look at how the WebApp can send the request to the server to run the above code and how the response will be retrieved by the Web App.

In the WebApp code, we will create one folder named commands and inside this folder, we will create one file command.py. The command.py file will have a function that will go to the endpoint, run the code and retrieve the response.

commands/command.py

The function above will go to the URL with the field variable command that will have the command given by the user. This will execute the script inside the command.py file on the server and get the response inside the res variable. We will get this response in the text format inside the contents variable and finally return that response.

You can find the complete backend code here:

Step 3: Deploying the backend on AWS cloud

We have our backend code ready and now let’s deploy this code on the AWS cloud.

We will use AWS EC2 instance for deploying the backend code. So, let’s provision one instance for deploying backend code.

For the sake of this project, I had allowed access to all of the ports inside this instance.

Login to this EC2 instance and Install the httpd package that is the httpd web server.

$ yum install httpd

Now, go to the /var/www/cgi-bin folder

$ cd /var/www/cgi-bin/

Inside this directory, copy all of your backend code. Make sure that all of the .py files are executable.

Now, start and enable the httpd webserver

$ systemctl start httpd
$ systemctl enable httpd

Finally, we had successfully deployed our backend on the AWS cloud. So, this is the right time to show you the frontend(Web App) and backend working together.

Step 4: Installing Jenkins on AWS EC2 instance

As we progress and keep on enhancing the code, after every commit in the master branch we want that the enhanced features should be available to the user immediately after the push. But for achieving this, every time, after pushing the code to GitHub, we are required to go to the backend servers and download the code there manually. This is a time-consuming task, so we thought to create a CI/CD pipeline for the backend code. And one of the best tools for creating a CI/CD pipeline is Jenkins. So, let’s first install Jenkins on AWS EC2.

We will install the Jenkins in the same EC2 instance where we had deployed our backend code. So, log in to the EC2 instance and follow the following steps for installing Jenkins.

  1. Jenkins is written in the Java language. So, for installing the Jenkins, Java should be installed on the machine.
$ sudo yum install java-1.8.0

2. Add Jenkins repository and import the key

$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo$ sudo rpm — import https://pkg.jenkins.io/redhat/jenkins.io.key

3. Install Jenkins

$ sudo yum install jenkins -y

4. Start and enable Jenkins

$ systemctl start jenkins
$ systemctl enable jenkins

5. Accessing Jenkins through the web browser

Jenkins works on port 8080 by default. We already had allowed access to all of the ports on the EC2 instance. So, for accessing the Jenkins, we have to go to port 8080 of the public IP of the EC2 instance.

https://INSTANCE_IP:8080

The very first window of Jenkins will ask for the admin password. We can get the default admin password provided by Jenkins by running the following command on the instance where we had installed Jenkins.

$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Now, log in using this password, and after login don’t forget to create an admin user for logging into Jenkins next time.

6. Installing suggested plugins and creating the first admin user

Now, Jenkins is ready to use.

Step 5: Creating an End-to-End CI/CD pipeline using Jenkins

Before going forward, let’s discuss what is an End-to-End CI/CD pipeline?

We as a developer want to focus on the development part and deliver the code faster to the actual consumer through the application. But if we required higher agility, we need to replace the manual work of integrating the code, deploying, and delivering the code. So, for achieving this we have to create an automated pipeline.
Here, we want that, as soon as we push the code to the SCM tool (GitHub), the code should be downloaded on the servers and test cases should run to check if the code is passing tests. If the code passes the tests, it should be deployed to the servers in the production. If you look at this flow, this pipeline starts at one end that is when the developer pushes the code, and ends at another end that is the code will be available to the consumers. That's why this pipeline is known as the End-to-End pipeline.

We will be creating a similar pipeline that will start as soon as the developer pushes the code to GitHub and that code will be deployed to the servers automatically.

Let’s create a CI/CD pipeline for backend code.

Go to Jenkins dashboard and click on New Item.

Name this project and select type as a freestyle project.

Select Source Code management as Git and provide the GitHub repository URL of the backend code and the branch.

As we want that the job should run as soon as the code is uploaded, we have to set triggers. Select the GitHub hook trigger for GITScm polling.

Now, as soon as code is uploaded to GitHub, the GitHub will come to Jenkins and ask to run the job. For GitHub to come to Jenkins, we have to create webhooks in the GitHub repository. (We will do it a bit later. Let’s first finish creating a job.)

Now, when the job triggers, we want to download a code in the directory /var/www/cgi-bin/ from the Git repository.

Go to the Build option and inside Execute shell write the following commands:

Save the job.

We are asking to run the commands as a root user. So, the prompt will ask for the root user password. But we want that the should run without asking any password. The commands in the Jenkins job are executed by the jenkins user. So, we will give root user permissions to the jenkins user and also set it to not ask for the password. For this, go to the /etc/sudoers file in the EC2 instance where Jenkins is installed and write the following entry for jenkins user.

Now, let’s create a webhook in the GitHub repository.

Go to the backend code repository in GitHub, go to settings and click on the Webhooks option from the left menus. Click on Add-webhook.

In the Payload URL, add the URL like this:

http://INSTANCE_PUBLIC_IP:8080/github-webhook/

Select the event to trigger the webhook as Send me anything.

Add webhook.

Send the payload and if you see the green tick, that means the payload is delivered and the GitHub can go to the Jenkins.

Now, we are all set to test if the pipeline works correctly.

Push the code to the master branch of the backend code repository and see if it triggers the job.

Finally, the CI/CD pipeline is implemented successfully.

Step 6: Adding speech recognition to the Web App

This feature works something like this — When the user clicks on the microphone icon on the web app, it will start listening to the user's voice. After the user spoked what he wants, it will convert this audio into text. And inside this text, it will start looking for certain keywords. By finding the keywords, the function will match certain conditions, and based on the conditions, it will route to the appropriate feature.

For eg. If the user spoke the line “launch the hadoop cluster for me” then this function will look for certain keywords like launch, hadoop, cluster, and based on this keywords, it will route to the appropriate service.

For implementing the speech recognition, we will use two python libraries named pyaudio and speechrecognition.

$ pip install pyaudio
$ pip install speechrecognition

Go to the app.py file inside the Web App and add the following function.

This function will get executed when the user clicks the microphone icon button on the menu page.

Let’s see the speech recognition feature in action.

Step 7: Deploying Web App using RedHat OpenShift

Now, we have our entire project ready and the final step is to deploy the Web App so that the world can use it. And what else could be better than OpenShift that provides Kubernetes with extended capabilities?

We will use minikube a single-node OpenShift cluster for deploying the Web App for the sake of this demo.

Let’s start

  1. Log in to the OpenShift (minishift) console and create a new project.

After login, you will see the minishift console like below.

If you are logging in for the first time, you will see no projects. To work in OpenShift, we required to create a project and every resource will be launched inside a project. So, let's first create a project named terminalui.

2. Create a build and deployment

As we had created a new project, it will be empty. For creating the build click on catalog.

Now, the entire catalog will be shown to us. As our Web App is created using Flask that is a Python framework, select Python from the catalog.

Click next.

Click on advanced options.

Enter the name for the build and provide an URL of the public git repository. In the Git Reference, you can optionally provide a branch name or the tag, by default the reference is set to master branch. Optionally, you can provide context dir as well, by default it is set to the / directory.

For providing access to the Web Application from the public world, check the option to create a route to the application.

Select the target port on which your application will run inside an OS (POD).
In this case, our application is running on port 8080.

Finally, click on create and this will create a build configuration for us.

3. Understanding how the build is created

For understanding the internals of how the build is created for a Flask application, let us see the logs of the build that we had created.

In these logs, you can see that the GitHub repository is cloned and OpenShift had automatically started installing the required packages. Have you wondered how OpenShift gets to know which packages this application required?

Lemme explain to you…

We had uploaded one requirements.txt file with the Web App and this file contains the names of the packages that this application required. As we are using Python builder image, OpenShift is so much intelligent that, it will automatically detect this requirements.txt file and starts installing the required packages.
Once the required packages are installed, it will build an image with Web App code and the installed packages, and push this image to the OpenShift private registry.

After that, it will automatically create a deployment and expose it by creating a route.

Now, we can access our application on the above URL.

You can see in the above screenshot that the Web App is accessible through the route provided by the OpenShift and it’s working as expected. So, finally, we had successfully deployed the application using the OpenShift Container Platform.

I hope you loved this concept of integrating multiple high-end technologies for achieving real-world kind of implementation of the project. I would love to know if you find this article helpful. Show some appreciation through applauds if you like this article.

For any help or suggestions connect with me on Twitter at @TheNameIsAnkush or find me on LinkedIn.

Thank you!

--

--