Files
PicAnalysis/backend/scripts/rapidocr_server.py
锦麟 王 f8472987f0 feat: 实现多 OCR 提供商架构和完整设置页面
## 主要变更

### OCR 架构
- 新增多提供商 OCR 系统 (Tesseract.js, Baidu OCR, RapidOCR)
- 添加 Provider 基类接口和工厂模式
- 支持 provider 自动选择和降级处理
- 新增 RapidOCR Python HTTP 服务 (端口 8080)

### 路径修复
- 修复 Windows 平台路径解析问题
- 统一路径处理工具 (lib/path.ts)
- 修复 uploads 目录定位问题

### 设置页面重构
- 三个标签页:API 配置、OCR 配置、AI 配置
- API 服务器地址配置
- OCR 服务商配置(Tesseract.js, RapidOCR, 百度 OCR)
- AI 服务商配置(智谱 GLM, MiniMax, DeepSeek, Kimi, OpenAI, Anthropic)

### 端口配置
- 前端端口: 13056
- 后端端口: 13057

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:00:22 +08:00

115 lines
3.5 KiB
Python

"""
RapidOCR HTTP Server
为 Node.js 后端提供 OCR API 服务
"""
from rapidocr_onnxruntime import RapidOCR
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import base64
import numpy as np
from io import BytesIO
from PIL import Image
import cv2
# 初始化 RapidOCR
ocr = RapidOCR()
class OCRHandler(BaseHTTPRequestHandler):
def _set_cors(self):
"""设置 CORS"""
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
self.send_header('Access-Control-Allow-Headers', 'Content-Type')
def _send_json(self, data, status=200):
"""发送 JSON 响应"""
self.send_response(status)
self.send_header('Content-Type', 'application/json')
self._set_cors()
self.end_headers()
self.wfile.write(json.dumps(data, ensure_ascii=False).encode('utf-8'))
def do_OPTIONS(self):
"""处理 OPTIONS 请求"""
self.send_response(200)
self._set_cors()
self.end_headers()
def do_GET(self):
"""健康检查"""
if self.path == '/health':
self._send_json({"status": "ok", "service": "rapidocr"})
else:
self._send_json({"error": "Not found"}, 404)
def do_POST(self):
"""处理 OCR 请求"""
if self.path == '/ocr':
try:
content_length = int(self.headers['Content-Length'])
post_data = self.rfile.read(content_length)
data = json.loads(post_data.decode('utf-8'))
# 获取图片数据
images = data.get('images', [])
if not images:
self._send_json({"error": "No images provided"}, 400)
return
# 处理第一张图片
image_base64 = images[0]
image_data = base64.b64decode(image_base64)
# 转换为 OpenCV 格式
nparr = np.frombuffer(image_data, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if img is None:
self._send_json({"error": "Failed to decode image"}, 400)
return
# 执行 OCR
result, _ = ocr(img)
# 格式化结果
ocr_results = []
for line in result:
ocr_results.append({
"text": line[0],
"score": float(line[1]),
"box": line[2]
})
# 计算平均置信度
avg_confidence = 0
if ocr_results:
avg_confidence = sum(r["score"] for r in ocr_results) / len(ocr_results)
self._send_json({
"code": 200,
"msg": "success",
"data": ocr_results
})
except Exception as e:
self._send_json({"error": str(e)}, 500)
else:
self._send_json({"error": "Not found"}, 404)
def log_message(self, format, *args):
"""减少日志输出"""
pass
def run_server(port=8080):
"""启动服务器"""
server_address = ('', port)
httpd = HTTPServer(server_address, OCRHandler)
print(f"RapidOCR Server running on port {port}")
print(f"Health check: http://localhost:{port}/health")
print(f"OCR endpoint: http://localhost:{port}/ocr")
httpd.serve_forever()
if __name__ == '__main__':
run_server()