Commit
·
0380f70
1
Parent(s):
833d26b
Use FastAPI instead of Flask
Browse files- app.py +100 -83
- requirements.txt +1 -0
app.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
| 1 |
# from flask import Flask, request, jsonify, render_template, make_response
|
| 2 |
# from flask_cors import CORS
|
| 3 |
-
|
|
|
|
|
|
|
| 4 |
import numpy as np
|
| 5 |
import cv2
|
| 6 |
|
|
@@ -10,6 +12,11 @@ from src.prediction import predict_img, optimize_img, update_patch
|
|
| 10 |
from src.utils import cv_to_pil, pil_to_cv
|
| 11 |
|
| 12 |
app = FastAPI()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
# UPLOAD_FOLDER = './uploads'
|
| 15 |
# app = Flask(__name__, template_folder='/client', static_folder='/client')
|
|
@@ -21,90 +28,100 @@ app = FastAPI()
|
|
| 21 |
# supports_credentials=True
|
| 22 |
# )
|
| 23 |
|
|
|
|
| 24 |
@app.get("/api/health_check")
|
| 25 |
def read_root():
|
| 26 |
return {"status": "ok"}
|
| 27 |
|
| 28 |
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
#
|
| 39 |
-
#
|
| 40 |
-
#
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
#
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
#
|
| 77 |
-
#
|
| 78 |
-
#
|
| 79 |
-
#
|
| 80 |
-
#
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
#
|
| 99 |
-
#
|
| 100 |
-
#
|
| 101 |
-
#
|
| 102 |
-
#
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# from flask import Flask, request, jsonify, render_template, make_response
|
| 2 |
# from flask_cors import CORS
|
| 3 |
+
import uvicorn
|
| 4 |
+
import logging
|
| 5 |
+
from fastapi import FastAPI, File, UploadFile, Form, Response
|
| 6 |
import numpy as np
|
| 7 |
import cv2
|
| 8 |
|
|
|
|
| 12 |
from src.utils import cv_to_pil, pil_to_cv
|
| 13 |
|
| 14 |
app = FastAPI()
|
| 15 |
+
logger = logging.getLogger('uvicorn')
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
def to_byte_response(img):
|
| 19 |
+
return cv2.imencode('.png', img)[1].tobytes()
|
| 20 |
|
| 21 |
# UPLOAD_FOLDER = './uploads'
|
| 22 |
# app = Flask(__name__, template_folder='/client', static_folder='/client')
|
|
|
|
| 28 |
# supports_credentials=True
|
| 29 |
# )
|
| 30 |
|
| 31 |
+
|
| 32 |
@app.get("/api/health_check")
|
| 33 |
def read_root():
|
| 34 |
return {"status": "ok"}
|
| 35 |
|
| 36 |
|
| 37 |
+
@app.post('/api/process')
|
| 38 |
+
async def process(
|
| 39 |
+
hue: str = Form(...),
|
| 40 |
+
saturation: str = Form(...),
|
| 41 |
+
lightness: str = Form(...),
|
| 42 |
+
contrast: str = Form(...),
|
| 43 |
+
kelvin: str = Form(...),
|
| 44 |
+
img: UploadFile = File(...)
|
| 45 |
+
):
|
| 46 |
+
# logger.info(img)
|
| 47 |
+
# imgfile = request.files['img']
|
| 48 |
+
# img_array = np.asarray(bytearray(imgfile.stream.read()), dtype=np.uint8)
|
| 49 |
+
img_array = np.frombuffer(await img.read(), dtype=np.uint8)
|
| 50 |
+
img_array = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
|
| 51 |
+
|
| 52 |
+
logger.info(img)
|
| 53 |
+
logger.info(img_array)
|
| 54 |
+
logger.info(img_array.shape)
|
| 55 |
+
|
| 56 |
+
# data = request.form
|
| 57 |
+
hue_int = int(hue)
|
| 58 |
+
saturation_int = float(saturation)
|
| 59 |
+
lightness_int = float(lightness)
|
| 60 |
+
contrast_int = int(contrast)
|
| 61 |
+
kelvin_int = int(kelvin)
|
| 62 |
+
|
| 63 |
+
img_array = control_contrast(img_array, contrast_int)
|
| 64 |
+
img_array = control_HSV(img_array, hue_int, saturation_int, lightness_int)
|
| 65 |
+
|
| 66 |
+
img_pil = cv_to_pil(img_array)
|
| 67 |
+
img_pil = control_kelvin(img_pil, kelvin_int)
|
| 68 |
+
processed_img = pil_to_cv(img_pil)
|
| 69 |
+
|
| 70 |
+
return Response(content=to_byte_response(processed_img), media_type="image/png")
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
@app.post('/api/predict/{process_name}')
|
| 74 |
+
async def predict(
|
| 75 |
+
process_name: str,
|
| 76 |
+
img: UploadFile = File(...)
|
| 77 |
+
):
|
| 78 |
+
if not process_name in ['cyanotype_mono', 'cyanotype_full', 'salt', 'platinum']:
|
| 79 |
+
return { 'error': 'process name is invalid' }
|
| 80 |
+
|
| 81 |
+
img_array = np.frombuffer(await img.read(), dtype=np.uint8)
|
| 82 |
+
img_array = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
|
| 83 |
+
|
| 84 |
+
# if 'colorpatch' in request.files:
|
| 85 |
+
# patchfile = request.files['colorpatch']
|
| 86 |
+
# patch_array = np.asarray(bytearray(patchfile.stream.read()), dtype=np.uint8)
|
| 87 |
+
# colorpatch = cv2.imdecode(colorpatch_array, cv2.IMREAD_COLOR)
|
| 88 |
+
# update_patch(process_name, colorpatch)
|
| 89 |
+
|
| 90 |
+
predicted_img = predict_img(process_name, img_array)
|
| 91 |
+
|
| 92 |
+
return Response(content=to_byte_response(predicted_img), media_type="image/png")
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
@app.post('/api/optimize/{process_name}')
|
| 96 |
+
async def optimize(
|
| 97 |
+
process_name: str,
|
| 98 |
+
img: UploadFile = File(...)
|
| 99 |
+
):
|
| 100 |
+
if not process_name in ['cyanotype_mono', 'cyanotype_full', 'salt', 'platinum']:
|
| 101 |
+
return { 'error': 'process name is invalid' }
|
| 102 |
+
|
| 103 |
+
img_array = np.frombuffer(await img.read(), dtype=np.uint8)
|
| 104 |
+
img_array = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
|
| 105 |
+
|
| 106 |
+
# if 'colorpatch' in request.files:
|
| 107 |
+
# patchfile = request.files['colorpatch']
|
| 108 |
+
# patch_array = np.asarray(bytearray(patchfile.stream.read()), dtype=np.uint8)
|
| 109 |
+
# colorpatch = cv2.imdecode(colorpatch_array, cv2.IMREAD_COLOR)
|
| 110 |
+
# update_patch(process_name, colorpatch)
|
| 111 |
+
|
| 112 |
+
(opt_img, preview_img) = optimize_img(process_name, img_array)
|
| 113 |
+
|
| 114 |
+
h, w = preview_img.shape[:2]
|
| 115 |
+
if process_name.endswith('full'):
|
| 116 |
+
opt_img = np.reshape(opt_img, (h, w, 3))
|
| 117 |
+
else:
|
| 118 |
+
opt_img = np.reshape(opt_img, (h, w, 1))
|
| 119 |
+
opt_img = np.array([[[i[0]] * 3 for i in j] for j in opt_img], dtype=np.uint8)
|
| 120 |
+
|
| 121 |
+
optimized_img = cv2.hconcat([opt_img, preview_img])
|
| 122 |
+
|
| 123 |
+
return Response(content=to_byte_response(optimized_img), media_type="image/png")
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
if __name__ == "__main__":
|
| 127 |
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
requirements.txt
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
-i https://pypi.org/simple
|
| 2 |
fastapi==0.74.*
|
| 3 |
uvicorn[standard]==0.17.*
|
|
|
|
| 4 |
absl-py==1.2.0; python_version >= '3.6'
|
| 5 |
astunparse==1.6.3
|
| 6 |
cachetools==5.2.0; python_version ~= '3.7'
|
|
|
|
| 1 |
-i https://pypi.org/simple
|
| 2 |
fastapi==0.74.*
|
| 3 |
uvicorn[standard]==0.17.*
|
| 4 |
+
python-multipart
|
| 5 |
absl-py==1.2.0; python_version >= '3.6'
|
| 6 |
astunparse==1.6.3
|
| 7 |
cachetools==5.2.0; python_version ~= '3.7'
|