Passing An HTML Table To Client And Passing Multiple Values As JSON From Server To Client

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.
 
Up 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:
  1. pip install pandas   
To import pandas to our project, add an import statement:
  1. import pandas as pd  
Now, replace the return statement of third if of upload_file function in app.py with the code below:
  1. df = pd.DataFrame(table)  
  2. html_file = df.to_html()  
  3. 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,
  1. 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,
  1. 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:
  1. 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.
  1. <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:
  1. <a id="createdTime"></a>  
  2. <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.
  1. <script>  
  2.        $(document).ready(function () {  
  3.   
  4.            $("#btnSubmit").click(function (event) {  
  5. event.preventDefault();//prevent the default submit action  
  6.                var form = $('#fileUploadForm')[0];  
  7.                var data = new FormData(form);//create and set data from the form to a variable  
  8. ​  
  9.                $.ajax({  
  10.                    type: "POST",//specify request type ie; POST/GET/PUT/...  
  11.                    enctype: 'multipart/form-data',//specify MIME type  
  12.                    url: "/uploader",//specify URL to submit form  
  13.                    data: data,//specify what data to be uploaded  
  14.                    dataType:'json',//specify the data returned is a JSON string  
  15.                    processData: false,// Preventing default data parse behavior  
  16.                    contentType: false,// type of data we're sending  
  17.                    cache: false,//is the data cacheable  
  18.                    timeout: 600000,//seting a timeout  
  19.                    success: function (data) {  
  20.                        window.location.href = '/uploads/output.csv';//download the CSV  
  21. $("#createdTime").html(data['CreatedTime']);//display CreatedTime  
  22.                        $("#HTMLTab").replaceWith(data['HTMLTab']);//display HTML table  
  23.                   },  
  24.                    error: function (e) {  
  25. ​  
  26.                        console.log("ERROR : ", e);//for identifying the error  
  27. ​  
  28.                   }  
  29.               });  
  30. ​  
  31.           });  
  32. ​  
  33.       });  
  34. </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:
  1. <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.
 
The final code in home.html,scripts.js and app.py as of now is as shown below:
 
app.py
  1. from flask import Flask,request, render_template,send_from_directory,redirect,jsonify  
  2. import json  
  3. import os  
  4. import requests  
  5. import time  
  6. import csv  
  7. import pandas as pd  
  8. ​  
  9. endpoint = "https://xxxxxx.cognitiveservices.azure.com/"  
  10. subscription_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx"  
  11. dirname = os.path.dirname(__file__)  
  12. ​  
  13. app = Flask(__name__)  
  14. ​  
  15. def saveAsCSV(table):  
  16.    with open("output.csv"'a+', newline='') as file:  
  17.        writer = csv.writer(file)  
  18.        writer.writerows(table)  
  19. def getJSON(image_data):  
  20. text_recognition_url = endpoint + "/vision/v3.0/read/analyze"  
  21. headers = {'Ocp-Apim-Subscription-Key': subscription_key,  
  22. 'Content-Type''application/octet-stream'}  
  23. response = requests.post(  
  24. text_recognition_url, headers=headers, data=image_data)  
  25. response.raise_for_status()  
  26. operation_url = response.headers["Operation-Location"]  
  27. analysis = {}  
  28. poll = True  
  29. while (poll):  
  30. response_final = requests.get(  
  31. response.headers["Operation-Location"], headers=headers)  
  32. analysis = response_final.json()  
  33. if ("analyzeResult" in analysis):  
  34. poll = False  
  35. if ("status" in analysis and analysis['status'] == 'failed'):  
  36. poll = False  
  37. return analysis;  
  38. @app.route('/uploads/<filename>')  
  39. def uploaded_file(filename):  
  40.    return send_from_directory(dirname,  
  41.                               filename)  
  42. @app.route('/')  
  43. def home():  
  44. return render_template('home.html')  
  45. ​  
  46. @app.route('/uploader', methods=['POST'])  
  47. def upload_file():  
  48. if 'file' not in request.files:  
  49. return redirect(request.url)  
  50. file = request.files['file']  
  51. if file.filename == '':  
  52. return redirect(request.url)  
  53. if file:  
  54. analysis=getJSON(file)  
  55. row=[]  
  56. table=[]  
  57. for page in analysis['analyzeResult']['readResults']:  
  58. for word in page['lines']:  
  59. row.append(word['text'])  
  60. table.append(row)  
  61. row=[]  
  62. saveAsCSV(table)  
  63. df = pd.DataFrame(table)  
  64. html_file = df.to_html()  
  65. createdTime=analysis['createdDateTime']  
  66. return jsonify(HTMLTab=html_file,CreatedTime=createdTime)  
  67. return ''  
  68. ​  
  69. ​  
  70. if __name__ == '__main__':  
  71. app.run(debug=True)  
home.html
  1. <html>  
  2.     <body>  
  3.         <form id="fileUploadForm">  
  4.             <input type="file" name="file"  id="fileSelect">  
  5.                 <button type="submit" id="btnSubmit">Upload</button>  
  6.             </form>  
  7.             <a id="createdTime"></a>  
  8.             <div id="HTMLTab"></div>  
  9.             <script type = "text/javascript" src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" ></script>  
  10.             <script type = "text/javascript" src = "{{ url_for('static', filename = 'scripts.js') }}" ></script>  
  11.         </body>  
  12.     </html>  
scripts.js
  1. $(document).ready(function() {  
  2.     $("#btnSubmit").click(function(event) {  
  3.         event.preventDefault();  
  4.         var form = $('#fileUploadForm')[0];  
  5.         var data = new FormData(form);​  
  6.         $.ajax({  
  7.             type: "POST",  
  8.             enctype: 'multipart/form-data',  
  9.             url: "/uploader",  
  10.             data: data,  
  11.             dataType: 'json',  
  12.             processData: false,  
  13.             contentType: false,  
  14.             cache: false,  
  15.             timeout: 600000,  
  16.             success: function(data) {  
  17.                 window.location.href = '/uploads/output.csv';  
  18.                 $("#createdTime").html(data['CreatedTime']);  
  19.                 $("#HTMLTab").replaceWith(data['HTMLTab']);  
  20.             },  
  21.             error: function(e) {  
  22.                 ​  
  23.                 console.log("ERROR : ", e);​  
  24.             }  
  25.         });​  
  26.     });​  
  27. });