- 新增 PaddleOCR 本地高精度 OCR 服务支持,包括 Dockerfile、API 服务和 provider 实现 - 在 docker-compose 中集成 RapidOCR 和 PaddleOCR 服务,并配置健康检查 - 优化后端 API 路由前缀,移除 `/api` 以简化代理配置 - 更新 Nginx 配置以正确传递请求头和代理 WebSocket 连接 - 在前端设置页面添加 PaddleOCR 和 RapidOCR 的测试与配置选项 - 修复后端 Dockerfile 以支持 Python 原生模块构建 - 更新 OCR 设置指南,反映当前服务状态和部署方式 - 添加上传文件调试日志和权限设置
167 lines
4.3 KiB
Python
167 lines
4.3 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""
|
|
PaddleOCR HTTP API Service
|
|
基于 PaddlePaddle 官方镜像的 OCR HTTP 服务
|
|
"""
|
|
|
|
from flask import Flask, request, jsonify
|
|
from paddleocr import PaddleOCR
|
|
import base64
|
|
import io
|
|
from PIL import Image
|
|
import logging
|
|
|
|
# 配置日志
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# 初始化 PaddleOCR
|
|
ocr = PaddleOCR(
|
|
use_angle_cls=True,
|
|
lang='ch',
|
|
use_gpu=False,
|
|
show_log=False
|
|
)
|
|
|
|
app = Flask(__name__)
|
|
|
|
@app.route('/', methods=['GET'])
|
|
def index():
|
|
"""健康检查"""
|
|
return jsonify({
|
|
"message": "PaddleOCR Server is running!",
|
|
"version": "2.7.0",
|
|
"endpoints": {
|
|
"/": "GET - 健康检查",
|
|
"/ocr/scan": "POST - OCR 识别"
|
|
}
|
|
})
|
|
|
|
@app.route('/ocr/scan', methods=['POST'])
|
|
def ocr_scan():
|
|
"""OCR 识别接口"""
|
|
try:
|
|
# 获取请求数据
|
|
data = request.get_json()
|
|
|
|
if not data or 'image' not in data:
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Missing image data"
|
|
}), 400
|
|
|
|
# 解码图片
|
|
image_data = data['image']
|
|
if isinstance(image_data, str):
|
|
# Base64 编码
|
|
if image_data.startswith('data:image'):
|
|
image_data = image_data.split(',')[1]
|
|
image_bytes = base64.b64decode(image_data)
|
|
else:
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Invalid image format"
|
|
}), 400
|
|
|
|
# 转换为 PIL Image
|
|
image = Image.open(io.BytesIO(image_bytes))
|
|
|
|
# 执行 OCR
|
|
result = ocr.ocr(image, cls=True)
|
|
|
|
# 解析结果
|
|
if result and result[0]:
|
|
texts = []
|
|
for line in result[0]:
|
|
box = line[0]
|
|
text_info = line[1]
|
|
texts.append({
|
|
"text": text_info[0],
|
|
"confidence": float(text_info[1]),
|
|
"box": box
|
|
})
|
|
|
|
all_text = "\n".join([t["text"] for t in texts])
|
|
|
|
return jsonify({
|
|
"success": True,
|
|
"data": {
|
|
"texts": texts,
|
|
"fullText": all_text
|
|
}
|
|
})
|
|
else:
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "No text detected"
|
|
}), 200
|
|
|
|
except Exception as e:
|
|
logger.error(f"OCR Error: {str(e)}")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": str(e)
|
|
}), 500
|
|
|
|
@app.route('/ocr/text', methods=['POST'])
|
|
def ocr_text():
|
|
"""简化的 OCR 接口,只返回文本"""
|
|
try:
|
|
data = request.get_json()
|
|
|
|
if not data or 'image' not in data:
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Missing image data"
|
|
}), 400
|
|
|
|
# 解码图片
|
|
image_data = data['image']
|
|
if isinstance(image_data, str):
|
|
if image_data.startswith('data:image'):
|
|
image_data = image_data.split(',')[1]
|
|
image_bytes = base64.b64decode(image_data)
|
|
else:
|
|
return jsonify({
|
|
"success": False,
|
|
"error": "Invalid image format"
|
|
}), 400
|
|
|
|
image = Image.open(io.BytesIO(image_bytes))
|
|
|
|
# 执行 OCR
|
|
result = ocr.ocr(image, cls=True)
|
|
|
|
# 提取文本
|
|
if result and result[0]:
|
|
texts = [line[1][0] for line in result[0]]
|
|
all_text = "\n".join(texts)
|
|
|
|
return jsonify({
|
|
"success": True,
|
|
"data": {
|
|
"text": all_text,
|
|
"lines": texts
|
|
}
|
|
})
|
|
else:
|
|
return jsonify({
|
|
"success": True,
|
|
"data": {
|
|
"text": "",
|
|
"lines": []
|
|
}
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"OCR Error: {str(e)}")
|
|
return jsonify({
|
|
"success": False,
|
|
"error": str(e)
|
|
}), 500
|
|
|
|
if __name__ == '__main__':
|
|
logger.info("Starting PaddleOCR API server on port 8866...")
|
|
app.run(host='0.0.0.0', port=8866, debug=False)
|