Introduction
This is the third part of the article series "Python Flask App and Azure Cognitive Services Read API". The first article can be accessed by clicking
here and the second article by clicking
here.
Until now, we have built a simple Python Flask application, integrated it with Read API, and deployed it on Azure. In this article first, we are returning an HTML table built from the table list of multiple lists that we used in the previous article and displayed on the client side. Next, we will try to send this HTML table and some values in order to know how we can send multiple values from server to client.
Converting a list of lists to HTML tables and display it to client
To convert the list of lists to an HTML table, there are many methods. Here, we convert this list of lists into the dataframe and then use the built-in function of pandas to_html() to create an HTML table. If pandas is not installed, use pip to install it:
To import pandas to our project, add an import statement:
Now, replace the return statement of third if of upload_file function in app.py with the code below:
- df = pd.DataFrame(table)
- html_file = df.to_html()
- return html_file
Explanation
First line
Converts table to data frame and the compulsory argument is the list to list and there are many optional arguments for the column heading and so on. Get more info from
here.
Second line
Converts the dataframe to HTML tables the to_html() have many optional arguments like classes,index,table_id,border and so on. Get more info from
here.
Third line
Return the HTML Table thus it can be displayed by the client ie; browser.
Now run your application and you can see the redirection to a new page with an HTML table with the result obtained from Read API.
Passing multiple values as JSON from server to client
We are passing created time along with the HTML table from the server after the processing. In order to do that first we need to get the created time of the result from Read API, we can get it from the JSON it returned. The value of key createdDateTime in the JSON result gives the same result. We can set it to a variable createdTime by the following code,
- createdTime=analysis['createdDateTime']
We need jsonify to create JSON string easily so for that we need to import jsonify from Flask, The following code is the updated Flask import statement,
- from flask import Flask, request,render_template,redirect,jsonify
Now, replace the return statement with the following code in order to return the HTML table (html_file) and created time (createdTime) with the following code:
- return jsonify(HTMLTab=html_file,CreatedTime=createdTime)
Now we are done with server-side updates.
In home.html we need to make some changes so that it can accept JSON string from the server and handle this data. First, we need to add JQuery to our project. You can either download the JQuery module and integrate it (we'll talk about how can we integrate local static files to our Flask project later) or else you can call it from any CDN. Here I'm calling it from CDN, to do that add the following code at the end of your body tag.
- <script type = "text/javascript" src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></script>
We need to display the Created Time which is a string so we use a tag and a resultant table which is an HTML table so we use div tag, For that, we add the following code to specify a space for displaying those:
- <a id="createdTime"></a>
- <div id="HTMLTab"></div>
Now, add a custom script to submit the form and handle the resultant JSON data. Remove the "method='post' enctype='multipart/form-data' action='/uploader'"attributes from form tag as we are now handling this with the custom script. The following is the custom script to be added to home.html.
- <script>
- $(document).ready(function () {
-
- $("#btnSubmit").click(function (event) {
- event.preventDefault();
- var form = $('#fileUploadForm')[0];
- var data = new FormData(form);
-
- $.ajax({
- type: "POST",
- enctype: 'multipart/form-data',
- url: "/uploader",
- data: data,
- dataType:'json',
- processData: false,
- contentType: false,
- cache: false,
- timeout: 600000,
- success: function (data) {
- window.location.href = '/uploads/output.csv';
- $("#createdTime").html(data['CreatedTime']);
- $("#HTMLTab").replaceWith(data['HTMLTab']);
- },
- error: function (e) {
-
- console.log("ERROR : ", e);
-
- }
- });
-
- });
-
- });
- </script>
Yep! We have completed the edits to be made on home.html. Now we can run the application to see the result.
But we know it's is not a good practice to write script inside the HTML document. So now, we are moving the script above to a custom made JS file. The JS file created is a static resource, so we have to make it inside a folder named static which in inside or project folder (here inside the Reader folder). So, create the static folder and inside it create a folder named js (js folder is not mandatory but a best practice js folder for JS files, CSS folder for CSS files, etc...) then create a JS file. I have named the JS file scripts.js. replace the above scripts with a link, as shown in the code below:
- <script type = "text/javascript" src = "{{ url_for('static', filename = 'js/scripts.js') }}" ></script>
The above is an example how we can serve static files in Flask Application. You can use the same method if you want to serve JQuery from your server or add bootstrap or other libraries.
Summary
Now, We have send this HTML table and some values in order to know how we can sent multiple values from server to client.
The final code in home.html,scripts.js and app.py as of now is as shown below,
app.py
- from flask import Flask,request, render_template,send_from_directory,redirect,jsonify
- import json
- import os
- import requests
- import time
- import csv
- import pandas as pd
-
- endpoint = "https://xxxxxx.cognitiveservices.azure.com/"
- subscription_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- dirname = os.path.dirname(__file__)
-
- app = Flask(__name__)
-
- def saveAsCSV(table):
- with open("output.csv", 'a+', newline='') as file:
- writer = csv.writer(file)
- writer.writerows(table)
- def getJSON(image_data):
- text_recognition_url = endpoint + "/vision/v3.0/read/analyze"
- headers = {'Ocp-Apim-Subscription-Key': subscription_key,
- 'Content-Type': 'application/octet-stream'}
- response = requests.post(
- text_recognition_url, headers=headers, data=image_data)
- response.raise_for_status()
- operation_url = response.headers["Operation-Location"]
- analysis = {}
- poll = True
- while (poll):
- response_final = requests.get(
- response.headers["Operation-Location"], headers=headers)
- analysis = response_final.json()
- if ("analyzeResult" in analysis):
- poll = False
- if ("status" in analysis and analysis['status'] == 'failed'):
- poll = False
- return analysis;
- @app.route('/uploads/<filename>')
- def uploaded_file(filename):
- return send_from_directory(dirname,
- filename)
- @app.route('/')
- def home():
- return render_template('home.html')
-
- @app.route('/uploader', methods=['POST'])
- def upload_file():
- if 'file' not in request.files:
- return redirect(request.url)
- file = request.files['file']
- if file.filename == '':
- return redirect(request.url)
- if file:
- analysis=getJSON(file)
- row=[]
- table=[]
- for page in analysis['analyzeResult']['readResults']:
- for word in page['lines']:
- row.append(word['text'])
- table.append(row)
- row=[]
- saveAsCSV(table)
- df = pd.DataFrame(table)
- html_file = df.to_html()
- createdTime=analysis['createdDateTime']
- return jsonify(HTMLTab=html_file,CreatedTime=createdTime)
- return ''
-
-
- if __name__ == '__main__':
- app.run(debug=True)
home.html
- <html>
- <body>
- <form id="fileUploadForm">
- <input type="file" name="file" id="fileSelect">
- <button type="submit" id="btnSubmit">Upload</button>
- </form>
- <a id="createdTime"></a>
- <div id="HTMLTab"></div>
- <script type = "text/javascript" src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></script>
- <script type = "text/javascript" src = "{{ url_for('static', filename = 'scripts.js') }}" ></script>
- </body>
- </html>
scripts.js
- $(document).ready(function() {
- $("#btnSubmit").click(function(event) {
- event.preventDefault();
- var form = $('#fileUploadForm')[0];
- var data = new FormData(form);
- $.ajax({
- type: "POST",
- enctype: 'multipart/form-data',
- url: "/uploader",
- data: data,
- dataType: 'json',
- processData: false,
- contentType: false,
- cache: false,
- timeout: 600000,
- success: function(data) {
- window.location.href = '/uploads/output.csv';
- $("#createdTime").html(data['CreatedTime']);
- $("#HTMLTab").replaceWith(data['HTMLTab']);
- },
- error: function(e) {
-
- console.log("ERROR : ", e);
- }
- });
- });
- });