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'
|