Flask Interactive Web Application Development Tips

Sameer Mahajan
6 min readJun 8, 2023

Introduction

Any functionality you develop needs to be packaged and delivered as an application for end users to consume and use. The web application is a popular choice these days for its flexibility, interoperability, and accessibility. Flask is a micro framework written in Python for developing web applications. It is lightweight and still very rich in capability.

Here is a typical architecture of the Flask web app-based environment:

The web application is deployed on a remote server, even in the cloud. The end user interacts with it from a browser with javascript.

Flask Web App Architecture

Hello World

Learning any program starts with a simple ‘Hello World” program. Here is the hello world flask web app.

Insall flask as:

$ pip install Flask

Write a simple program as

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"

in a file called hello.py Then run the program as

$ flask --app hello run --host=0.0.0.0

From your browser open the URL http://127.0.0.1:5000 and connect to your app to start interacting with it.

Various Components

Server-side code

Flask’s server-side code is in Python. Modern web applications use meaningful URLs to the liking of their users. The functions are bound to a URL using the route() decorator. E.g.

@app.route('/hello')
def hello():
return 'Hello, World'

here it is bound to the/hello URL. We can also pass an argument to the method while invoking it as:

@app.route('/hello/<name>')
def hello(name):
return 'Hello, ‘ + name

Here we are passing the name by invoking the hello method as http://127.0.0.1:5000/hello/Sameer so that it will greet us with our name like Sameer here.

HTML

Dynamic web applications also have static content and it comes from HTML templates. Flask configures the Jinja2 template engine for us automatically. Templates can be used to generate any type of text file. For web applications, we will primarily be generating HTML pages, but we can also generate markdown, plain text for emails, and anything else. To render a template we can use the render_template() method. All we have to do is provide the name of the template and the variables we want to pass to the template engine as keyword arguments. We put all the templates in a folder named “templates”. Here’s a simple example of how to render a template:

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)

templates/hello.html

<!doctype html>
<title>Hello from Flask</title>
<h1>Hello {{ name }}!</h1>

Active Javascript

Javascript code makes the client side interactive. It is either embedded in HTML or stored in static/js folder and pointed to by the script tag of HTML, src attribute specifying the file location. One thing to note here is that the javascript execute in a browser environment in this case which is a lot different from node.js or any other server-side framework.

Interaction

The end user interacts with the Flask web app by opening a URL e.g. http://127.0.0.1:5000/hello/Sameer in her browser. As we saw earlier, it invokes the server-side method specified at that route. The server returns the response to the user, typically rendered in the browser. The client-side can also invoke a server method using a javascript specifying a callback which will be executed on the server response.

Eventing

The client-server interaction is typically an event based as you can see from the callback mentioned above. It is augmented by my end user’s interaction with the UI e.g. opening a URL in the browser (as we already saw before), click of a button, submitting a form, etc.

Sessions

A session is an important object in Flask where we can keep all the context about ongoing interaction with a specific user. This is implemented on top of cookies. To use sessions, we have to set a secret key. Here is a simple example of using a session:

app = Flask(__name__)
app.secret_key = "Sameer"

@app.route('/', methods=['POST', 'GET'])
def index():
if request.method == "POST":
answer = session["number"] * session["times"]
else:
session["number"] = random.randint(1,10)
session["times"] = random.randint(1,10)

Here is a GET request, we are generating two random numbers and storing them in the session object. In a POST request later, we are computing their product.

Generating dynamic content on the server side

Sometimes we need to generate content dynamically on the server side. We can do so by generating that dynamic content in our Python method and returning it as a response like:

@app.route('/random)
def random():
number = random.randint(1,10)
file = “./numbers/” + str(number) + “.wav”
with wave.open(file, 'rb') as f:
return Response(r.read(),mimetype='audio/wav')

Here we are generating a random number between 1 and 10 on the server side and returning corresponding audio recordings of the number to client to play in its browser.

Rendering dynamic server-side content in client browser

Sometimes you may want to return the content from the server to the client but render it as a part of the complete page including other buttons, forms, etc. For this, you would make use of the “url_for” construct in your HTML template. E.g.

<audio controls autoplay>
<source src="{{ url_for('random') }}" type="audio/wav">
Your browser does not support the audio element.
</audio>

Here in our HTML, we are embedding an audio control specifying the path of “random”. Then in your server-side code, you would have something like this:

@app.route('/')
def index():
return render_template(“index.html”)

@app.route('/random)
def random():
number = random.randint(1,10)
file = “./numbers/” + str(number) + “.wav”
with wave.open(file, 'rb') as f:
return Response(r.read(),mimetype='audio/wav')

Now when you hit the home path, the HTML template gets rendered. As a part of this rendering the audio control gets rendered. The url_for of the audio control invokes the /random route on the server exercising the corresponding code that returns the audio recording. This audio recording gets rendered on the client as a part of the template and plays in the browser.

Sending custom data from client to server

You may want to capture some custom user data on the client side and send it over to the server. It can be done using javascript. Here is a javascript function that is sending recorded audio to the server.

function sendAudioData(audioBlob) {
console.log("sending audio data");
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:5000/");
xhr.setRequestHeader("Content-Type", "audio/wav")
xhr.send(audioBlob)
}

Rendering server response in client browser

You may want to capture the server response to the above request and render it in the browser. You can do it by using the onreadystatechange callback as below.

xhr.onreadystatechange = function() {
alert(xhr.responseText)
}

Rendering server response along with complete template in client browser

At times you may want to render the complete page updated by the server's response to your query. You can make use of document.write method in javascript for the same. Here is the complete code:

function sendAudioData(audioBlob) {
console.log("sending audio data");
const xhr = new XMLHttpRequest();
xhr.open("POST", "http://127.0.0.1:5000/");
xhr.setRequestHeader("Content-Type", "audio/wav")
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
document.write(xhr.responseText);
}
}
xhr.send(audioBlob)
}
PaadasML Flask App

Here is a link to our hosted app if you want to take a look: https://paadas-flask-app.onrender.com/ Note that currently its speech recognition is way off that we are still investigating.

You can check out a complete app, along with its source code, developed using all these concepts and more with some significant interesting functionality at: https://github.com/sameermahajan/PaadasMLFlaskApp

Future steps

Like any other work, this is a work in progress. The following are some enhancements I am still investigating:

  • The audio control, despite the ‘autoplay’ HTML attribute, does not always auto-play in all browsers.
  • The recordings of the audio are required to be started and stopped on the client side with clicks of buttons. I want to automate even that so that it automatically starts recording when the user starts answering and stops detecting silence. It might require support from the underlying library, recorder.js in this case.
  • I want to make the client-server dialogue seamless without any intervention like clicks of buttons etc.
  • As you can see it has a single web application. I want to scale it to multiple applications to cater to a large number of users with some database backend as we saw in the initial architectural diagram.

Acknowledgments

Thanks, Shivaji Mutkule for all the help enhancing the app! Thanks Selina Arokiaswamy for hosting the app!

--

--

Sameer Mahajan

Generative AI, Machine Learning, Deep Learning, AI, Traveler