from venv import logger from flask import request, Flask, request from shutil import copy import os from typing import Dict, List, Union from urllib.request import urlretrieve from pathlib import Path from paddleocr import PaddleOCR from hashlib import md5 import time import base64 import io import requests import json ocr = PaddleOCR(use_angle_cls=True, lang="ch", use_gpu=False) app = Flask(__name__) img_dir = Path('imgs') img_dir.mkdir(exist_ok=True) ocr_cache_dict = dict() ocr = PaddleOCR(use_gpu=False, use_angle_cls=True, lang="ch", rec=True) def debugg_log(content: str): with open("log.txt","a") as file: file.write(content) def get_dict_from_request() -> dict: """ get json data from request as much as possible Returns ------- dict request data in dict format """ json = {**request.args} if request.json: json = {**json, **request.json} if request.form: json = {**json, **request.form.to_dict()} return json def download_image(img_url: str) -> str: """ download image or copy image to local from url Parameters ---------- img_url : str url of image to be downloaded Returns ------- str local file path of image Notes ----- if download failed, empty string `''` will be returned """ d = md5(str(img_url).encode()).hexdigest() file_name = f'{img_dir}/{d}.jpg' # NOTE: insecurity # # copy from local file system in the running container # if Path(img_url).exists(): # copy(img_url, file_name) if Path(file_name).exists(): return file_name # download from internet try: urlretrieve(img_url, file_name) return file_name except: return '' def base64_to_file(s: Union[str, bytes]) -> str: """ decode base64 string or bytes and save to local file system Parameters ---------- s : Union[str, bytes] base64 string or bytes Returns ------- str local file path of base64 data """ d = md5(str(s).encode()).hexdigest() file_name = f'{img_dir}/{d}.jpg' if Path(file_name).exists(): return file_name if isinstance(s, str): b = base64.decodebytes(s.encode()) elif isinstance(s, bytes): b = base64.decodebytes(s) else: return '' with open(file_name, 'wb') as f: f.write(b) return file_name @app.route('/api/ocr_hello', methods=['POST']) def get_content() -> str: return 'hello' @app.route('/api/ocr_extract', methods=['POST']) def ocr_extract() -> None: img = request.files.get('file') print(img) # 将img保存到当前目录下 img_path = img.filename content = '' # json_data = request.get_json() # path = json_data['path'] if not img_path: return { 'success': False, 'time_cost': 155, 'results': '解析失败', 'msg': '解析失败' } img.save(img_path) st = time.perf_counter() result = ocr.ocr(img_path, cls=True) app.logger.info(f'leng is {len(result)}') if (len(result) == 1): for idx in range(len(result[0])): res = result[0][idx] content += res[1][0] else: for idx in range(len(result)): res = result[idx] content += res[1][0] return { 'success': True, 'time_cost': format(time.perf_counter() - st), 'results': content, 'msg': '解析完毕' } def timer(func): """装饰器:打印函数耗时""" def decorated(*args, **kwargs): st = time.perf_counter() ret = func(*args, **kwargs) print('time cost: {} seconds'.format(time.perf_counter() - st)) return ret return decorated @app.route('/api/ocr_dec', methods=['POST']) def ocr_text_extract() -> None: """ ocr web api that accept image url, image path and base64 data of image """ app.logger.info(f'receive request') print('receive request 2') st = time.time() json = get_dict_from_request() app.logger.info(f'request dict is {json}') img_url: str = json.get('img_url') app.logger.info(f'request url is {img_url}') base64_data: str = json.get('img_base64') img_path = '' if img_url: img_path = download_image(img_url) elif base64_data: img_path = base64_to_file(base64_data) if not img_path: et = time.time() return { 'success': False, 'time_cost': et-st, 'results': [], 'msg': 'maybe img_url or img_base64 is wrong' } results = ocr_cache_dict.get(img_path) if not results: ocr_result_list = ocr.ocr(img_path) et = time.time() if ocr_result_list is None: ocr_result_list = [] os.remove(img_path) else: # make sure float32 can be JSON serializable ocr_result_list: list = eval(str(ocr_result_list)) results: List[Dict] = [] for each in ocr_result_list: item = { 'confidence': each[-1][1], 'text': each[-1][0], 'text_region': each[:-1] } results.append(item) ocr_cache_dict[img_path] = results et = time.time() return { 'success': True, 'time_cost': et-st, 'results': results, 'msg': '' } def get_file_from_url(url_file: str, target_path: str): send_headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36", "Connection": "keep-alive", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", "Accept-Language": "zh-CN,zh;q=0.8" } req = requests.get(url_file, headers=send_headers, timeout=10) bytes_io = io.BytesIO(req.content) (_, file_name) = os.path.split(url_file) if not os.path.exists(target_path): os.mkdir(target_path) target_path = target_path + file_name with open(target_path, 'wb') as file: file.write(bytes_io.getvalue()) time.sleep(0.1) return target_path if __name__ == '__main__': port = os.environ.get('FLASK_PORT', '') if port.isalnum() and int(port) > 0: port = int(port) else: port = 5000 app.run(host='0.0.0.0', port=port, debug=True)