From f7b9d02578b4ea40eec5b1d4fcd0063832acbdf5 Mon Sep 17 00:00:00 2001 From: q Date: Sun, 8 Mar 2026 14:27:38 +0300 Subject: [PATCH] update --- README.md | 7 ++++--- __pycache__/app.cpython-313.pyc | Bin 28169 -> 28266 bytes app.py | 4 ++-- .../paddle_ocr_backend.cpython-313.pyc | Bin 9268 -> 9875 bytes core/paddle_ocr_backend.py | 15 ++++++++++++++- requirements-paddle.txt | 6 +++--- run_service.sh | 4 ++-- scripts/download_models.sh | 14 +++++++------- 8 files changed, 32 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e423342..8e9d00c 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,11 @@ sudo apt-get install -y python3-opencv pip3 install -r requirements.txt ``` -Optional PaddleOCR backend (Python 3.8+ only): +Optional PaddleOCR backend for Python 3.6: ```bash pip3 install -r requirements-paddle.txt ``` +If you see `No matching distribution found for paddleocr>=3.0.0`, use the pinned `2.7.x` requirement above (already set in this repo). ## Models Place your models in `./models` (paths can be overridden via env): @@ -80,8 +81,8 @@ OpenCV from JetPack repos (4.x) usually ships without CUDA dnn. To use CUDA, bui - `PADDLE_LANG` (default `ru`; used when `OCR_BACKEND=paddle`) - `PADDLE_USE_GPU` (default `false`) - `PADDLE_USE_ANGLE_CLS` (default `false`) -- `PADDLE_DET_MODEL_DIR` (default `./models/paddle/PP-OCRv5_mobile_det_infer`) -- `PADDLE_REC_MODEL_DIR` (default `./models/paddle/eslav_PP-OCRv5_mobile_rec_infer`) +- `PADDLE_DET_MODEL_DIR` (default `./models/paddle/PP-OCRv3_mobile_det_infer`) +- `PADDLE_REC_MODEL_DIR` (default `./models/paddle/cyrillic_PP-OCRv3_mobile_rec_infer`) - `PADDLE_CLS_MODEL_DIR` (default empty) - `PADDLE_CPU_THREADS` (default `4`) - `TESSDATA_PREFIX` (path to tessdata / tessdata_best if you install better models) diff --git a/__pycache__/app.cpython-313.pyc b/__pycache__/app.cpython-313.pyc index 7969f80bad33756c7949982ea13bc1b83ad6e6e1..3149092050ab0018a57d50354569f94c1ab8d993 100644 GIT binary patch delta 541 zcmeCY!}#hBBkyNkUM>b8sEb*fS+u3!!*eu2(#yrL{#wx}-#wOUwlA|az*coU{Sg?Pv zixfi^V^Mf;K(OoN7p$_}Zo%&QjKLn3Ou?R$1=y4oy@I`=d><(WQ>X)rqJw>b`eR}o zgZ(Cluvsz&Zti2NVXLpw)YH$+Pf5)w)-Om*Ny$mo4+zlpcMd8uj?c|c%FIcPPf0C_ z&&*3pExIKV;OOGw;~F32>KyOu@8aqc@8TI$WrS`(a%E9wPEKZWJi19msmW+2IrI4h zBaFJmu-St54iBU2W>G0uULX~%ZX*VyX4syV08%Mow}jZ7f&M9Sne3AJpK;x0m#m|V lk{2vfE{msLU=X<>E;+q&Qso6j^9z=_m&NloE9AUn1OWBBl@$O0 delta 409 zcmYL@u`dH*7{O>wy171cYGYs;aMQDU)J48Fx+ zkkm*-ZnKKXe^6!-iOFE(E5bWGPu?fb`^)?KM30`R^e#!wgwLCCwH>*UE;1q8wEbLY2IJ3OTwuu<$ z;?UqXpOCFMznf$y-s^}e6UTxS*F0!k3!rl?Vyk`5Xm^P13XM%^)#I#Sz`m#_KJ3L9 z4#N~X6MEv)S{*!&lQ@AYrcgs2W>lZE1{sbiK^|shvO}G9C_t9I2wi>y%mjrwwE^Z? zK5j>&+n@B(t?t}Yc3knX!%EOStUS{% D2Onkj diff --git a/app.py b/app.py index 78c49b0..83cb354 100644 --- a/app.py +++ b/app.py @@ -69,8 +69,8 @@ OCR_AUTO_LANG = env_bool("OCR_AUTO_LANG", True) PADDLE_LANG = os.getenv("PADDLE_LANG", "ru") PADDLE_USE_GPU = env_bool("PADDLE_USE_GPU", False) PADDLE_USE_ANGLE_CLS = env_bool("PADDLE_USE_ANGLE_CLS", False) -PADDLE_DET_MODEL_DIR = os.getenv("PADDLE_DET_MODEL_DIR", "") -PADDLE_REC_MODEL_DIR = os.getenv("PADDLE_REC_MODEL_DIR", "") +PADDLE_DET_MODEL_DIR = os.getenv("PADDLE_DET_MODEL_DIR", "./models/paddle/PP-OCRv3_mobile_det_infer") +PADDLE_REC_MODEL_DIR = os.getenv("PADDLE_REC_MODEL_DIR", "./models/paddle/cyrillic_PP-OCRv3_mobile_rec_infer") PADDLE_CLS_MODEL_DIR = os.getenv("PADDLE_CLS_MODEL_DIR", "") PADDLE_CPU_THREADS = env_int("PADDLE_CPU_THREADS", 0) MAX_CONTENT_LENGTH = MAX_IMAGE_MB * 1024 * 1024 diff --git a/core/__pycache__/paddle_ocr_backend.cpython-313.pyc b/core/__pycache__/paddle_ocr_backend.cpython-313.pyc index bed4e5ff7bad586a06df762049bab56fc5061786..1bc7287f31cf91f1c5c15408559a343189e51dc2 100644 GIT binary patch delta 1603 zcmZvcdrVtZ9LLYOkCqntqP?`VKue3XWk7IY%m*7|FoxNK!KE_>BD=P?q}%1voO{`r zFBTth1{ayXY+~XcGw}~+GBtMorT^eI<3Ad4Gm-|)X8g~87I8|{7|$s%_wXd=bH3-? z-|L=p?!DL#`EwWb@ORH9@ zEKETSj@LWrGned>ouy}PS(05P<&oW_a@>=wDm;lzo~z=azdTy_UHB3UDKu0IgWj4% z3TZBuo;BG?XYMtP(1>+I$*!Ro+^CkoWo_~{Y^++5(vOfXj>KWFHHO`gw@NrhgL>gD zYd`iBezJ;~OZwoKvSD}8IhH1>Vya`RKAzK6=(4?t55Ohc4d+s@?)zZNVzA}C?A72F z_|UG-RMQ-n+PiUY2fEy0?$ZbaO$OmSP*y>wp2Dc<%dohr1e;F6>!T}TN-whiO|Mwye* zmi4d^#B88V^v&G4cuzF~tH$8MNT&I_xrX&Ii?e7OA4XZ66!$+Jn$p$jyqY%EOyr1q z{MaPPL=-YUHKFPz@zV69p5i=8iiEv+(KdWMukIpbl8|OPpD7BNT-q%1`N=#r2{4Bi zh6kB3KVgg)twhz7X*FZ89f+_-*p8DVvj`thG8s)B=o#9nq>re2ruFWV+eM8Gjp78l z$=Pj*WpB-*w{iX`#Wxj=tIIR4zzQm}C4R1y=F*Tj*|X$o{;21wYwMC*TCNJtcYt;V0ps(>7QONBD&l|L^w3~`8X=nT1-k>CvUj)e zZ+4e=C-{XZrg|YEQl{Bflv?4D^2a&%15}eHhDL@syyJ-BF1X@&3=b7tPJy>%!R4i`S*sQ5LN(I8rP65RAPj^ecog!XFiz1;is8A!#n9)t z{ob9wqp)YGE(*Fbp&IPCZr{5Eyk8r|Zx_C*ZNZjOviuw2t(GBX9s)h$7fp5Ad>5Vw z|G0UK#p8-%R-05zvWd>lufO(7RFl0FcLyJ)$KZz(5j*|>W+UIWl>!K)k{T98GC8GZ z$Scf~g(4^Kb2s2reHdSa3-zC3FXW;-9%5e!p?^L^dKm^84l(2y4l|?}5)AAe$S{Ke z%h3>Sht+5e&Vm$6l>NFBmy3ztg0LetV0nhwG{Tu!Yp|Wk8V2@N7Rx#(CNoo-x}BVb UA7TwQjl+?-qqmR-_J*c^0jAn#YXATM delta 1168 zcmZva%WD%~6vyXeCP@>`tBEmAOq)!Swy6&)REz#%e_|in+FEg1d{i8!Ce_iH>Yb@5 z$nW<9#hpJNXW>Fb1wlk~GwMcgp%vV!yCOdDPq4c2dC%0U)!xO2?>YCL$Gzub|DBD& zcY%Ok;OkY#E#rLrTyO$ToqMh{MpTz9><1>PqAW1CTB}Nq?cvJpD6i^~1zZe`$*3A| zJRvov1|1bvLoBj4Tv%Y2z!F`45ibQ4`;+tpio+sRqoqb#gdymJRWKw}g3~_k4RR|q zV-0&}lp5NaL8y;ny?1F;neloBeWM^$-NSj@?aeNnD=z#!E*SFTU2i+o+EZRPNH>H+ z6hGDsqUJjR{rJ}RX5I@q`&3?bWt0P-`OC=!ukxt%ug(@>qQ&3s5+~NQcdZp4uXT63 z?2~~JSGa*6V9kU^LKA)nWuXn_a1V6ZrLZJ=R+7IJtI>+*Z<1~JI=ZBxo8$&U7l%2Y zBmK)_i)gEeD`Htt?V;FvfX%omo`N1U;?0~7l!bUR?gzuZ7hequ73pR!3hLk}c-Rio zI|;*tO&Cek)$JlVNXT-S5(gEXuC^Wf6FJXe+8Dr)oU<<`e9+so|U(P%~G5Y%^X(Rvbdg< zs`|n5?E4h(YrO(zY$d%6JkC?^!=X$Y^y2AE8ZO}N%uCpYrT<8>niK`Sym+U5VjL&7HovjPbd(234H`7`vOffE!{HqXu4%FV`SVa zo0`V*bYL;T`JQf41p2+Ej$`>IacVu_<@|uhq`gL*$}g8^M@`lg4~~__E9G|fKNcHu RKFtN`vq# 0: kwargs['cpu_threads'] = self.cpu_threads try: - self.engine = PaddleOCR(**kwargs) + self.engine = self._create_engine(kwargs) self.available = True print('[INFO] PaddleOCR backend ready (lang={})'.format(self.lang)) except Exception as exc: @@ -66,6 +66,19 @@ class PaddleOCRBackend(object): self.available = False print('[WARN] Failed to initialize PaddleOCR backend: {}'.format(exc), file=sys.stderr) + def _create_engine(self, kwargs): + try: + return PaddleOCR(**kwargs) + except TypeError as exc: + # Backward compatibility with older PaddleOCR versions. + msg = str(exc) + if 'unexpected keyword argument' not in msg: + raise + relaxed = dict(kwargs) + relaxed.pop('cpu_threads', None) + relaxed.pop('show_log', None) + return PaddleOCR(**relaxed) + def run_ocr(self, img_rgb, return_boxes=True): if not self.available or img_rgb is None: return '', [] diff --git a/requirements-paddle.txt b/requirements-paddle.txt index d885cd6..6ba225f 100644 --- a/requirements-paddle.txt +++ b/requirements-paddle.txt @@ -1,3 +1,3 @@ -# Optional OCR backend dependencies. -# PaddleOCR 3.x supports Python 3.8+. -paddleocr>=3.0.0 +# Optional OCR backend dependencies (Python 3.6 compatible line). +# 2.7.5 is yanked on PyPI; 2.7.3 is usually the safer pin. +paddleocr==2.7.3 diff --git a/run_service.sh b/run_service.sh index 6af84c3..8bc3be6 100755 --- a/run_service.sh +++ b/run_service.sh @@ -15,8 +15,8 @@ export OCR_CONFIG=${OCR_CONFIG:---oem 1 --psm 6} export PADDLE_LANG=${PADDLE_LANG:-ru} export PADDLE_USE_GPU=${PADDLE_USE_GPU:-false} export PADDLE_USE_ANGLE_CLS=${PADDLE_USE_ANGLE_CLS:-false} -export PADDLE_DET_MODEL_DIR=${PADDLE_DET_MODEL_DIR:-./models/paddle/PP-OCRv5_mobile_det_infer} -export PADDLE_REC_MODEL_DIR=${PADDLE_REC_MODEL_DIR:-./models/paddle/eslav_PP-OCRv5_mobile_rec_infer} +export PADDLE_DET_MODEL_DIR=${PADDLE_DET_MODEL_DIR:-./models/paddle/PP-OCRv3_mobile_det_infer} +export PADDLE_REC_MODEL_DIR=${PADDLE_REC_MODEL_DIR:-./models/paddle/cyrillic_PP-OCRv3_mobile_rec_infer} export PADDLE_CLS_MODEL_DIR=${PADDLE_CLS_MODEL_DIR:-} export PADDLE_CPU_THREADS=${PADDLE_CPU_THREADS:-4} # Point to tessdata_best if installed diff --git a/scripts/download_models.sh b/scripts/download_models.sh index 02ca6a8..6656ae4 100755 --- a/scripts/download_models.sh +++ b/scripts/download_models.sh @@ -130,9 +130,9 @@ EAST_URL="https://github.com/argman/EAST/releases/download/model/frozen_east_tex TESS_ENG_URL="https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata" TESS_RUS_URL="https://github.com/tesseract-ocr/tessdata_best/raw/main/rus.traineddata" -# PaddleOCR v5 mobile models (detection + RU/EN recognition) -PADDLE_DET_URL="https://paddle-model-ecology.bj.bcebos.com/paddlex/official_inference_model/paddle3.0.0/PP-OCRv5_mobile_det_infer.tar" -PADDLE_REC_URL="https://paddle-model-ecology.bj.bcebos.com/paddlex/official_inference_model/paddle3.0.0/eslav_PP-OCRv5_mobile_rec_infer.tar" +# PaddleOCR v3 mobile models (good compatibility with paddleocr 2.7.x / Python 3.6) +PADDLE_DET_URL="https://paddle-model-ecology.bj.bcebos.com/paddlex/official_inference_model/paddle3.0.0/PP-OCRv3_mobile_det_infer.tar" +PADDLE_REC_URL="https://paddle-model-ecology.bj.bcebos.com/paddlex/official_inference_model/paddle3.0.0/cyrillic_PP-OCRv3_mobile_rec_infer.tar" if [[ "$DOWNLOAD_CORAL" == "1" ]]; then download_file "$CORAL_MODEL_URL" "$MODELS_DIR/ssd_mobilenet_v2_coco_quant_postprocess_edgetpu.tflite" @@ -144,8 +144,8 @@ if [[ "$DOWNLOAD_EAST" == "1" ]]; then fi if [[ "$DOWNLOAD_PADDLE" == "1" ]]; then - download_and_extract_tar "$PADDLE_DET_URL" "PP-OCRv5_mobile_det_infer" "$PADDLE_DIR" - download_and_extract_tar "$PADDLE_REC_URL" "eslav_PP-OCRv5_mobile_rec_infer" "$PADDLE_DIR" + download_and_extract_tar "$PADDLE_DET_URL" "PP-OCRv3_mobile_det_infer" "$PADDLE_DIR" + download_and_extract_tar "$PADDLE_REC_URL" "cyrillic_PP-OCRv3_mobile_rec_infer" "$PADDLE_DIR" fi if [[ "$DOWNLOAD_TESSDATA" == "1" ]]; then @@ -167,6 +167,6 @@ Recommended env: For PaddleOCR backend: export OCR_BACKEND="paddle" export PADDLE_LANG="ru" - export PADDLE_DET_MODEL_DIR="$PADDLE_DIR/PP-OCRv5_mobile_det_infer" - export PADDLE_REC_MODEL_DIR="$PADDLE_DIR/eslav_PP-OCRv5_mobile_rec_infer" + export PADDLE_DET_MODEL_DIR="$PADDLE_DIR/PP-OCRv3_mobile_det_infer" + export PADDLE_REC_MODEL_DIR="$PADDLE_DIR/cyrillic_PP-OCRv3_mobile_rec_infer" EOF