# Documentation of quick tips to build a Flask app
## Project structure
Since we want to keep things consistent, so we gonna use the same guide of anh Minh and Felix.
Clone the files of the repository
```bash
git clone https://github.com/dhminh1024/flask_doc.git
```
Change directory
```bash
cd flask_doc
```
Create the following folders and files
* app
* templates
* base.html
* static
* js
* index.js
* css
* style.css
* images
* blueprints
* __ init__.py
* middlewares
* models
* main.py
```bash
mkdir app app/templates app/static app/static/js app/static/css app/static/images app/blueprints app/middlewares app/models
touch app/main.py app/templates/base.html app/static/js/index.js app/static/css/style.css
touch app/blueprints/__init__.py
```
Add jquery (optional)
```bash
mv ./jquery-3.4.1.min.js app/static/js/
```
Add Canvas (optional)
```bash
mv ./index.js app/static/js/index.js
```
Add Coderschool logo (optional)
```bash
mv ./images/coderschool-logo.png app/static/images/
rm -r images
```
Add this code in **app/main.py**
```python
from flask import Flask, render_template
from blueprints import *
app = Flask(__name__)
app.register_blueprint(home)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000, debug=True)
```
> *Hints: most of this code can be automaticaly generated with a VSCode Extension called flask-snippets by only writting "fapp"*
> 
## Generating a new blueprint of our Flask app
> A blueprint is a template for generating a "section" of our Flask app
In **flask_doc** directory, run this code
```bash
export NEW_BLUEPRINT=home
mkdir app/blueprints/$NEW_BLUEPRINT
touch app/blueprints/$NEW_BLUEPRINT/__init__.py app/blueprints/$NEW_BLUEPRINT/blueprint.py
echo "from .$NEW_BLUEPRINT import $NEW_BLUEPRINT" >> app/blueprints/__init__.py
echo "from .blueprint import $NEW_BLUEPRINT" > app/blueprints/$NEW_BLUEPRINT/__init__.py
printf \
"from flask import Blueprint, render_template, request\n\
\n\
$NEW_BLUEPRINT = Blueprint('$NEW_BLUEPRINT', __name__)\
\n\
@$NEW_BLUEPRINT.route('/home')\n\
def route_name():\n\
return render_template('$NEW_BLUEPRINT.html') \n\
" > app/blueprints/$NEW_BLUEPRINT/blueprint.py
cp ./sample_page.html app/templates/$NEW_BLUEPRINT.html
```
> Hints: change 'home' to make a new blueprint (line 1 & 14)
## HTML Template
Add this code in **app/templates/base.html**
```html
<!doctype html>
<html lang="en">
<head>
<title>Title</title>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<!-- CSS -->
<link href="static/css/style.css" rel="stylesheet">
</head>
<body class="text-center">
{% block content%} {% endblock %}
<script src="static/js/jquery-3.4.1.min.js"></script>
<script src="static/js/index.js"></script>
<!-- AJAX optional -->
<script type="text/javascript">
$("#myButton").click(function(){
$('#result').text(' Predicting...');
var $SCRIPT_ROOT = {{request.script_root|tojson|safe}};
var canvasObj = document.getElementById("canvas");
var img = canvasObj.toDataURL('image/jpeg');
$.ajax({
type: "POST",
url: $SCRIPT_ROOT + "/upload/",
data: img,
success: function(data){
$('#result').text('Predictions ' + data);
}
});
});
</script>
</body>
</html>
```
> *Hints: most of this code can be automaticaly generated with VSCode Extensions called Bootstrap 4, Font awesome 4, Font Awesome 5 Free & Pro snippets by only writting "b4-$"*
<a id="run_app"></a>
## Run the app
Change directory
```bash
cd app
```
Run the app
```bash
python main.py
```
:confetti_ball: Congratulation, you have just created your Flask app. Here is the link of your Flask app: http://127.0.0.1:8000/home
## Html for MNIST example
Replace the code of **app/templates/home.html** by this code
```html
{% extends "base.html" %} {% block content %}
<div style="margin-top:50px">
<img class="mb-4" src="static/images/coderschool-logo.png" alt="" />
<h1 class="h3 mb-3 font-weight-normal">Please draw a number</h1>
<canvas id="canvas" width="400" height="400"></canvas>
<h1 class="h3 mb-3 font-weight-normal" id="result">Predictions:</h1>
<button id="myButton" class="btn btn-primary " type="submit">
Predict
</button>
<button id="clearButton" class="btn btn-success" type="submit">
Clear
</button>
<p class="mt-5 mb-3 text-muted">© Mariana 2019</p>
</div>
{% endblock %}
```
## Python for MNIST example
In **flask_doc** directory, run this code to generate the blueprint related to upload
```bash
export NEW_BLUEPRINT=upload_api
mkdir app/blueprints/$NEW_BLUEPRINT
touch app/blueprints/$NEW_BLUEPRINT/__init__.py app/blueprints/$NEW_BLUEPRINT/blueprint.py
echo "from .$NEW_BLUEPRINT import $NEW_BLUEPRINT" >> app/blueprints/__init__.py
echo "from .blueprint import $NEW_BLUEPRINT" > app/blueprints/$NEW_BLUEPRINT/__init__.py
printf \
"from flask import Blueprint, render_template, request\n\
\n\
$NEW_BLUEPRINT = Blueprint('$NEW_BLUEPRINT', __name__)\
\n\
@$NEW_BLUEPRINT.route('/upload_api')\n\
def route_name():\n\
return render_template('$NEW_BLUEPRINT.html') \n\
" > app/blueprints/$NEW_BLUEPRINT/blueprint.py
cp ./sample_page.html app/templates/$NEW_BLUEPRINT.html
```
Replace the code of **app/blueprints/upload_api/blueprint.py** by this code
> You might need to run ```pip install tensorflow``` and ```pip install werkzeug==0.15.4``` if it hasn't be done before
```python
from flask import Blueprint, render_template, request
import tensorflow as tf
import re
import base64
import numpy as np
def parse_image(imgData):
img_str = re.search(b"base64,(.*)", imgData).group(1)
img_decode = base64.decodebytes(img_str)
with open('output.png', "wb") as f:
f.write(img_decode)
return img_decode
model = tf.keras.models.load_model('models/mnist.h5')
upload_api = Blueprint('upload_api', __name__)
@upload_api.route('/upload/', methods=['POST'])
def upload():
image = parse_image(request.get_data())
image = tf.image.decode_jpeg(image, channels=1)
image = tf.image.resize(image, [28, 28])
# Change background to black and normalize data
image = (255 - image)/255.0
image = tf.reshape(image, (1, 28, 28))
prediction = model.predict(image)
prediction = np.argmax(prediction, axis=1)
return str(prediction)
```
Replace the code of **app/main.py** by this code
```python
from flask import Flask, render_template
from blueprints import *
app = Flask(__name__)
app.register_blueprint(home)
app.register_blueprint(upload_api)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000, debug=True)
```
Rename your model "**mnist.h5**" and add it to the folder **app/models**
> You don't have any model yet? [Try with this one](https://drive.google.com/file/d/1u-YZR8i3HUZCH5QWUi1dBokPD4SDKxL5/view?usp=sharing)
Then [run again your app](#run_app)