OCR Worker: add check and systemd install scripts.
This commit is contained in:
@@ -112,12 +112,18 @@ def run_ocr_on_bytes(content: bytes) -> dict:
|
|||||||
|
|
||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
def warmup():
|
def warmup():
|
||||||
buf = __import__("io").BytesIO()
|
"""延迟预热,不阻塞 HTTP 服务启动。"""
|
||||||
Image.new("RGB", (120, 40), color=(255, 255, 255)).save(buf, format="JPEG")
|
import threading
|
||||||
try:
|
|
||||||
run_ocr_on_bytes(buf.getvalue())
|
def _run():
|
||||||
except Exception:
|
buf = __import__("io").BytesIO()
|
||||||
pass
|
Image.new("RGB", (120, 40), color=(255, 255, 255)).save(buf, format="JPEG")
|
||||||
|
try:
|
||||||
|
run_ocr_on_bytes(buf.getvalue())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
threading.Thread(target=_run, daemon=True, name="ocr-warmup").start()
|
||||||
|
|
||||||
|
|
||||||
@app.get("/health")
|
@app.get("/health")
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# OCR Worker 一键诊断
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PORT="${OCR_PORT:-23567}"
|
||||||
|
VENV="${ROOT}/.venv"
|
||||||
|
|
||||||
|
echo "========== OCR Worker 诊断 =========="
|
||||||
|
echo "目录: ${ROOT}"
|
||||||
|
echo "端口: ${PORT}"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "--- 1. 虚拟环境 ---"
|
||||||
|
if [[ -d "${VENV}" ]]; then
|
||||||
|
echo "OK .venv 存在"
|
||||||
|
else
|
||||||
|
echo "FAIL 未安装,请运行: bash install.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- 2. 端口监听 ---"
|
||||||
|
if command -v ss >/dev/null; then
|
||||||
|
if ss -tln | grep -q ":${PORT} "; then
|
||||||
|
echo "OK 端口 ${PORT} 正在监听"
|
||||||
|
ss -tlnp | grep ":${PORT} " || true
|
||||||
|
else
|
||||||
|
echo "FAIL 端口 ${PORT} 无服务 — 请先启动:"
|
||||||
|
echo " OCR_USE_GPU=true bash start.sh"
|
||||||
|
echo " 或: sudo bash install-service.sh"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
netstat -tln 2>/dev/null | grep ":${PORT} " || echo "FAIL 端口 ${PORT} 无服务"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- 3. HTTP 健康检查 ---"
|
||||||
|
if command -v curl >/dev/null; then
|
||||||
|
resp="$(curl -sS -m 3 "http://127.0.0.1:${PORT}/health" 2>&1)" || true
|
||||||
|
if [[ -n "${resp}" ]]; then
|
||||||
|
echo "OK ${resp}"
|
||||||
|
else
|
||||||
|
echo "FAIL curl 无响应(服务未启动或启动失败)"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "跳过(无 curl)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- 4. GPU ---"
|
||||||
|
if command -v nvidia-smi >/dev/null; then
|
||||||
|
nvidia-smi --query-gpu=name,memory.used,memory.total --format=csv,noheader
|
||||||
|
else
|
||||||
|
echo "未检测到 nvidia-smi"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- 5. Python 依赖 ---"
|
||||||
|
if [[ -d "${VENV}" ]]; then
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "${VENV}/bin/activate"
|
||||||
|
python3 - <<'PY' || true
|
||||||
|
try:
|
||||||
|
import paddle
|
||||||
|
print("OK paddle", paddle.__version__)
|
||||||
|
except Exception as e:
|
||||||
|
print("FAIL paddle:", e)
|
||||||
|
try:
|
||||||
|
import paddleocr
|
||||||
|
print("OK paddleocr")
|
||||||
|
except Exception as e:
|
||||||
|
print("FAIL paddleocr:", e)
|
||||||
|
try:
|
||||||
|
import fastapi, uvicorn
|
||||||
|
print("OK fastapi/uvicorn")
|
||||||
|
except Exception as e:
|
||||||
|
print("FAIL fastapi:", e)
|
||||||
|
PY
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "--- 6. systemd ---"
|
||||||
|
if systemctl is-active ocr-worker &>/dev/null; then
|
||||||
|
systemctl status ocr-worker --no-pager -l | head -15
|
||||||
|
elif [[ -f /etc/systemd/system/ocr-worker.service ]]; then
|
||||||
|
echo "服务已安装但未运行: sudo systemctl start ocr-worker"
|
||||||
|
else
|
||||||
|
echo "未安装 systemd 服务(可选): sudo bash install-service.sh"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "===================================="
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# 注册 OCR Worker 为 systemd 服务(后台常驻)
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PORT="${OCR_PORT:-23567}"
|
||||||
|
|
||||||
|
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
|
||||||
|
echo "请使用 root 运行: sudo bash install-service.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -d "${ROOT}/.venv" ]]; then
|
||||||
|
echo "请先运行: bash ${ROOT}/install.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
chmod +x "${ROOT}/start.sh" "${ROOT}/check.sh" "${ROOT}/install.sh"
|
||||||
|
|
||||||
|
cat > /etc/systemd/system/ocr-worker.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=Grade Archive OCR Worker (PaddleOCR)
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=${ROOT}
|
||||||
|
Environment=OCR_USE_GPU=true
|
||||||
|
Environment=OCR_PORT=${PORT}
|
||||||
|
Environment=OCR_HOST=0.0.0.0
|
||||||
|
ExecStart=${ROOT}/.venv/bin/uvicorn app:app --host 0.0.0.0 --port ${PORT} --log-level info
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable ocr-worker
|
||||||
|
systemctl restart ocr-worker
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
echo ""
|
||||||
|
echo "==> 服务状态:"
|
||||||
|
systemctl status ocr-worker --no-pager -l | head -20
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==> 健康检查:"
|
||||||
|
curl -sS "http://127.0.0.1:${PORT}/health" || echo "(尚未就绪,请稍等 30 秒后重试: bash check.sh)"
|
||||||
|
echo ""
|
||||||
|
echo "局域网地址: http://$(hostname -I 2>/dev/null | awk '{print $1}'):${PORT}"
|
||||||
|
echo "成绩档案系统设置 OCR 地址填: http://192.168.8.6:${PORT} (按实际 IP 修改)"
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# 在带 NVIDIA 显卡(如 RTX 3060 Ti)的 Linux 机器上安装 OCR Worker
|
# 在带 NVIDIA 显卡的 Linux 机器上安装 OCR Worker
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
ROOT="$(cd "$(dirname "$0")" && pwd)"
|
||||||
@@ -9,37 +9,65 @@ PORT="${OCR_PORT:-23567}"
|
|||||||
echo "==> OCR Worker 安装目录: ${ROOT}"
|
echo "==> OCR Worker 安装目录: ${ROOT}"
|
||||||
|
|
||||||
if ! command -v python3 >/dev/null; then
|
if ! command -v python3 >/dev/null; then
|
||||||
echo "请先安装 python3"
|
echo "错误: 请先安装 python3"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
python3 -m venv "${VENV}"
|
if [[ -d "${VENV}" ]]; then
|
||||||
|
echo "==> 已有虚拟环境,跳过 python3 -m venv"
|
||||||
|
else
|
||||||
|
python3 -m venv "${VENV}"
|
||||||
|
fi
|
||||||
|
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source "${VENV}/bin/activate"
|
source "${VENV}/bin/activate"
|
||||||
pip install -U pip wheel
|
pip install -U pip wheel
|
||||||
|
|
||||||
# Paddle GPU(CUDA 11.8,适配多数 3060 Ti 驱动)
|
install_paddle() {
|
||||||
pip install paddlepaddle-gpu==2.6.2 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
|
if command -v nvidia-smi >/dev/null 2>&1; then
|
||||||
|
local cuda_major
|
||||||
|
cuda_major="$(nvidia-smi 2>/dev/null | sed -n 's/.*CUDA Version: \([0-9]*\)\.[0-9]*/\1/p' | head -1)"
|
||||||
|
cuda_major="${cuda_major:-11}"
|
||||||
|
echo "==> 检测到 NVIDIA GPU,CUDA 主版本: ${cuda_major}"
|
||||||
|
if [[ "${cuda_major}" -ge 12 ]]; then
|
||||||
|
echo "==> 安装 paddlepaddle-gpu (CUDA 12.x)…"
|
||||||
|
pip install paddlepaddle-gpu==2.6.2 -i https://www.paddlepaddle.org.cn/packages/stable/cu123/ \
|
||||||
|
|| pip install paddlepaddle-gpu==2.6.2 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
|
||||||
|
else
|
||||||
|
echo "==> 安装 paddlepaddle-gpu (CUDA 11.x)…"
|
||||||
|
pip install paddlepaddle-gpu==2.6.2 -i https://www.paddlepaddle.org.cn/packages/stable/cu118/
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "==> 未检测到 GPU,安装 CPU 版 paddlepaddle…"
|
||||||
|
pip install paddlepaddle==2.6.2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_paddle
|
||||||
pip install -r "${ROOT}/requirements.txt"
|
pip install -r "${ROOT}/requirements.txt"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==> 验证依赖…"
|
||||||
|
python3 -c "import fastapi, uvicorn, paddle; print('paddle', paddle.__version__, 'OK')"
|
||||||
|
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
安装完成。
|
安装完成。
|
||||||
|
|
||||||
启动(前台测试):
|
【重要】你已经在目录 ${ROOT} 时,不要再 cd deploy/ocr-worker,直接:
|
||||||
|
|
||||||
cd ${ROOT}
|
cd ${ROOT}
|
||||||
OCR_USE_GPU=true OCR_PORT=${PORT} bash start.sh
|
OCR_USE_GPU=true bash start.sh
|
||||||
|
|
||||||
局域网地址示例:
|
另开终端测试(服务启动后):
|
||||||
http://192.168.x.x:${PORT}
|
curl -s http://127.0.0.1:${PORT}/health
|
||||||
|
|
||||||
在成绩档案「系统设置 → AI 模型」里填写 OCR 服务地址:
|
应返回: {"status":"ok","gpu":true}
|
||||||
http://192.168.x.x:${PORT}
|
|
||||||
|
|
||||||
可选环境变量:
|
注册为 systemd 服务(推荐,后台常驻):
|
||||||
OCR_USE_GPU=true # 使用显卡(默认 true)
|
sudo bash ${ROOT}/install-service.sh
|
||||||
OCR_API_KEY=随机字符串 # 局域网鉴权(可选)
|
|
||||||
OCR_MAX_SIDE=1280 # 识别长边上限
|
诊断:
|
||||||
OCR_PORT=${PORT} # 监听端口
|
bash ${ROOT}/check.sh
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -6,12 +6,21 @@ VENV="${ROOT}/.venv"
|
|||||||
HOST="${OCR_HOST:-0.0.0.0}"
|
HOST="${OCR_HOST:-0.0.0.0}"
|
||||||
PORT="${OCR_PORT:-23567}"
|
PORT="${OCR_PORT:-23567}"
|
||||||
|
|
||||||
|
export OCR_USE_GPU="${OCR_USE_GPU:-true}"
|
||||||
|
export OCR_HOST="${HOST}"
|
||||||
|
export OCR_PORT="${PORT}"
|
||||||
|
|
||||||
if [[ ! -d "${VENV}" ]]; then
|
if [[ ! -d "${VENV}" ]]; then
|
||||||
echo "未找到虚拟环境,请先运行: bash install.sh"
|
echo "未找到虚拟环境,请先在本目录运行: bash install.sh"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# shellcheck disable=SC1091
|
# shellcheck disable=SC1091
|
||||||
source "${VENV}/bin/activate"
|
source "${VENV}/bin/activate"
|
||||||
cd "${ROOT}"
|
cd "${ROOT}"
|
||||||
exec uvicorn app:app --host "${HOST}" --port "${PORT}"
|
|
||||||
|
echo "==> 启动 OCR Worker: http://${HOST}:${PORT} (GPU=${OCR_USE_GPU})"
|
||||||
|
echo " 按 Ctrl+C 停止。后台运行请用: sudo bash install-service.sh"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
exec uvicorn app:app --host "${HOST}" --port "${PORT}" --log-level info
|
||||||
|
|||||||
Reference in New Issue
Block a user