From 2fea777600d8ca22e121029edd8bb7a819544ea6 Mon Sep 17 00:00:00 2001 From: dekun Date: Sat, 18 Jul 2026 00:31:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20OCR=20=E5=9C=A8=E4=B8=80=E9=94=AE?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=97=B6=E6=B3=A8=E5=86=8C=20systemd=20?= =?UTF-8?q?=E5=BC=80=E6=9C=BA=E8=87=AA=E5=90=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EOF Co-authored-by: Cursor --- deploy/install.sh | 18 ++--- deploy/ocr-common.sh | 110 ++++++++++++++++++--------- deploy/ocr-screen.sh | 55 +++++++++----- deploy/ocr-worker/install-service.sh | 47 +++++------- deploy/repair.sh | 2 +- deploy/update.sh | 7 +- docs/DEPLOY.md | 4 + 7 files changed, 142 insertions(+), 101 deletions(-) diff --git a/deploy/install.sh b/deploy/install.sh index aa9a982..ef5ec88 100644 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -207,17 +207,17 @@ setup_backend() { } setup_ocr_gpu() { - if command -v nvidia-smi >/dev/null; then - log_info "检测到 NVIDIA GPU,OCR 将常驻显存 (screen)" + if command -v nvidia-smi >/dev/null && nvidia-smi >/dev/null 2>&1; then + log_info "检测到可用 NVIDIA GPU" nvidia-smi --query-gpu=name,memory.total --format=csv,noheader 2>/dev/null || true else - log_warn "未检测到 NVIDIA GPU,OCR 将使用 CPU(较慢)" + log_warn "未检测到可用 NVIDIA GPU,OCR 将使用 CPU(systemd 开机自启)" fi if [[ -x "${INSTALL_DIR}/deploy/install-ocr-deps.sh" ]]; then bash "${INSTALL_DIR}/deploy/install-ocr-deps.sh" || log_warn "OCR 系统库安装跳过" fi install_ocr_worker - start_ocr_screen + start_ocr_service wait_ocr_healthy 30 || log_warn "OCR 后台加载中,继续安装主程序…" } @@ -286,11 +286,11 @@ print_summary() { echo " 访问: http://${ip}:${WEB_PORT}" echo " 管理员: admin / admin123(请立即修改)" echo "" - echo " 【同机 OCR — GPU 常驻 screen】" + echo " 【同机 OCR — systemd 开机自启】" echo " OCR 地址: http://127.0.0.1:${OCR_PORT}" - echo " 状态: bash ${INSTALL_DIR}/deploy/ocr-screen.sh status" - echo " 进入终端: screen -r ocr-worker (Ctrl+A D 退出)" - echo " 重启 OCR: bash ${INSTALL_DIR}/deploy/ocr-screen.sh restart" + echo " 状态: systemctl status ocr-worker" + echo " 重启 OCR: systemctl restart ocr-worker" + echo " 日志: journalctl -u ocr-worker -f" echo "" echo " 【Ollama — 其他电脑】" echo " 地址: ${OLLAMA_BASE_URL}" @@ -306,7 +306,7 @@ print_summary() { } main() { - log_info "一键部署开始(主程序 + OCR/GPU/screen | Ollama 外置)" + log_info "一键部署开始(主程序 + OCR/systemd | Ollama 外置)" require_root setup_deploy_proxy check_os diff --git a/deploy/ocr-common.sh b/deploy/ocr-common.sh index e36ba42..82d1060 100644 --- a/deploy/ocr-common.sh +++ b/deploy/ocr-common.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash -# OCR Worker 共用函数:同机 GPU 识别 + screen 常驻 +# OCR Worker 共用函数:同机 RapidOCR + systemd 开机自启 OCR_SCREEN_NAME="${OCR_SCREEN_NAME:-ocr-worker}" OCR_PORT="${OCR_PORT:-23567}" +OCR_SERVICE_NAME="${OCR_SERVICE_NAME:-ocr-worker}" ocr_worker_dir() { echo "${INSTALL_DIR}/deploy/ocr-worker" @@ -21,8 +22,10 @@ detect_ocr_use_gpu() { fi return fi - # auto - if command -v nvidia-smi >/dev/null && ldconfig -p 2>/dev/null | grep -q libcudnn; then + # auto:有 nvidia-smi 且能看到 GPU 才开(无卡时驱动在也会失败) + if command -v nvidia-smi >/dev/null \ + && nvidia-smi >/dev/null 2>&1 \ + && ldconfig -p 2>/dev/null | grep -q libcudnn; then echo "true" else echo "false" @@ -45,41 +48,64 @@ ocr_screen_running() { screen -list 2>/dev/null | grep -q "\.${OCR_SCREEN_NAME}[[:space:]]" } -start_ocr_screen() { - local worker_dir log_file - worker_dir="$(ocr_worker_dir)" - if [[ ! -x "${worker_dir}/.venv/bin/uvicorn" ]]; then - log_warn "OCR Worker 未安装,跳过 screen 启动" - return 1 - fi - if ! command -v screen >/dev/null; then - log_error "未安装 screen,请 apt install screen" - return 1 - fi - - log_info "启动 OCR Worker → screen「${OCR_SCREEN_NAME}」(RapidOCR, 端口 ${OCR_PORT})" +stop_ocr_screen() { if ocr_screen_running; then + log_info "停止旧版 OCR screen 会话…" screen -S "${OCR_SCREEN_NAME}" -X quit 2>/dev/null || true sleep 1 fi - - mkdir -p "${INSTALL_DIR}/logs" 2>/dev/null || true - log_file="${INSTALL_DIR}/logs/ocr-worker.log" - - screen -dmS "${OCR_SCREEN_NAME}" bash -c " - cd '${worker_dir}' && - export OCR_PORT='${OCR_PORT}' OCR_HOST=0.0.0.0 && - exec bash run.sh >> '${log_file}' 2>&1 - " - sleep 2 - log_info "OCR 日志: ${log_file}" } -stop_ocr_screen() { - if ocr_screen_running; then - log_info "停止 OCR screen 会话…" - screen -S "${OCR_SCREEN_NAME}" -X quit 2>/dev/null || true +# 注册并启用 systemd(一键部署 / 更新时调用) +setup_ocr_systemd() { + local worker_dir use_gpu + worker_dir="$(ocr_worker_dir)" + if [[ ! -x "${worker_dir}/.venv/bin/uvicorn" ]]; then + log_warn "OCR Worker 未安装,跳过 systemd 注册" + return 1 fi + + use_gpu="$(detect_ocr_use_gpu)" + stop_ocr_screen + + log_info "注册 systemd 服务 ${OCR_SERVICE_NAME}(OCR_USE_GPU=${use_gpu}, 端口 ${OCR_PORT})…" + cat > "/etc/systemd/system/${OCR_SERVICE_NAME}.service" </dev/null || true + stop_ocr_screen +} + +# 兼容旧脚本名 +start_ocr_screen() { + start_ocr_service } wait_ocr_healthy() { @@ -92,24 +118,32 @@ wait_ocr_healthy() { return 0 fi if (( i % 5 == 0 )); then - echo -ne "\r${YELLOW}[INFO]${NC} 仍在等待 OCR… ${i}/${max}(可另开终端: tail -f ${INSTALL_DIR}/logs/ocr-worker.log)" + echo -ne "\r${YELLOW}[INFO]${NC} 仍在等待 OCR… ${i}/${max}(journalctl -u ${OCR_SERVICE_NAME} -f)" fi sleep 2 done echo "" log_warn "OCR 尚未响应(可能仍在下载/加载模型,主程序可先继续)" - log_warn "稍后执行: bash ${INSTALL_DIR}/deploy/ocr-screen.sh status" + log_warn "稍后执行: systemctl status ${OCR_SERVICE_NAME}" return 1 } show_ocr_status() { echo "" - echo "--- OCR Worker (screen: ${OCR_SCREEN_NAME}) ---" - if ocr_screen_running; then - echo "screen: 运行中" - screen -list 2>/dev/null | grep "${OCR_SCREEN_NAME}" || true + echo "--- OCR Worker (systemd: ${OCR_SERVICE_NAME}) ---" + if systemctl is-enabled "${OCR_SERVICE_NAME}" &>/dev/null; then + echo "开机自启: $(systemctl is-enabled "${OCR_SERVICE_NAME}" 2>/dev/null)" else - echo "screen: 未运行" + echo "开机自启: 未注册" + fi + if systemctl is-active "${OCR_SERVICE_NAME}" &>/dev/null; then + echo "服务状态: active" + else + echo "服务状态: $(systemctl is-active "${OCR_SERVICE_NAME}" 2>/dev/null || echo inactive)" + fi + if ocr_screen_running; then + echo "screen(旧): 仍在运行(建议交由 systemd 接管)" + screen -list 2>/dev/null | grep "${OCR_SCREEN_NAME}" || true fi if curl -sf "http://127.0.0.1:${OCR_PORT}/health" 2>/dev/null; then echo "" diff --git a/deploy/ocr-screen.sh b/deploy/ocr-screen.sh index 5f07b27..90ae3a0 100644 --- a/deploy/ocr-screen.sh +++ b/deploy/ocr-screen.sh @@ -1,53 +1,66 @@ #!/usr/bin/env bash -# OCR Worker screen 管理(主程序同机部署时使用) +# OCR Worker 管理(systemd 开机自启;兼容旧 screen 命令) set -euo pipefail INSTALL_DIR="${INSTALL_DIR:-/opt/secondary-school-grade-archive}" -# shellcheck source=common.sh -source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/common.sh" # shellcheck source=ocr-common.sh source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/ocr-common.sh" +# 最小日志(单独运行时) +if ! declare -F log_info >/dev/null 2>&1; then + RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' + log_info() { echo -e "${GREEN}[INFO]${NC} $*"; } + log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } + log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } +fi + usage() { cat < - start 启动 OCR Worker(screen 后台,GPU 常驻) - stop 停止 screen 会话 - restart 重启 - status 查看 screen / health / GPU - attach 进入 screen 终端(Ctrl+A D 退出) - + start 启动 OCR(systemd,开机自启) + stop 停止 OCR + restart 重启 OCR + status 查看服务 / health + enable 仅注册开机自启(不重启) + logs 跟踪日志 EOF } cmd="${1:-status}" - case "${cmd}" in start) - start_ocr_screen + start_ocr_service wait_ocr_healthy || true + show_ocr_status ;; stop) - stop_ocr_screen + stop_ocr_service + log_info "OCR 已停止" ;; restart) - stop_ocr_screen - sleep 1 - start_ocr_screen + stop_ocr_service + start_ocr_service wait_ocr_healthy || true + show_ocr_status ;; status) show_ocr_status ;; + enable) + setup_ocr_systemd + log_info "已 enable,启动请: bash deploy/ocr-screen.sh start" + ;; + logs) + journalctl -u "${OCR_SERVICE_NAME}" -f + ;; attach) - if ocr_screen_running; then - screen -r "${OCR_SCREEN_NAME}" - else - log_error "screen 未运行,请先: bash deploy/ocr-screen.sh start" - exit 1 - fi + log_warn "OCR 已改为 systemd,不再使用 screen attach" + log_info "查看日志: journalctl -u ${OCR_SERVICE_NAME} -f" + ;; + -h|--help|help) + usage ;; *) usage diff --git a/deploy/ocr-worker/install-service.sh b/deploy/ocr-worker/install-service.sh index 113a471..a3a9b45 100644 --- a/deploy/ocr-worker/install-service.sh +++ b/deploy/ocr-worker/install-service.sh @@ -1,10 +1,22 @@ #!/usr/bin/env bash -# 注册 OCR Worker 为 systemd 服务(后台常驻) +# 注册 OCR Worker 为 systemd 服务(后台常驻 + 开机自启) +# 推荐:由 deploy/install.sh / update.sh 自动调用;也可单独执行。 set -euo pipefail ROOT="$(cd "$(dirname "$0")" && pwd)" +INSTALL_DIR="${INSTALL_DIR:-$(cd "${ROOT}/../.." && pwd)}" PORT="${OCR_PORT:-23567}" +# shellcheck source=../ocr-common.sh +source "$(cd "$(dirname "$0")/.." && pwd)/ocr-common.sh" + +# 提供最小 log_*,以便单独运行 +if ! declare -F log_info >/dev/null 2>&1; then + log_info() { echo "[INFO] $*"; } + log_warn() { echo "[WARN] $*"; } + log_error() { echo "[ERROR] $*" >&2; } +fi + if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then echo "请使用 root 运行: sudo bash install-service.sh" exit 1 @@ -15,39 +27,18 @@ if [[ ! -d "${ROOT}/.venv" ]]; then exit 1 fi -chmod +x "${ROOT}/start.sh" "${ROOT}/check.sh" "${ROOT}/install.sh" +chmod +x "${ROOT}/start.sh" "${ROOT}/check.sh" "${ROOT}/install.sh" 2>/dev/null || true -cat > /etc/systemd/system/ocr-worker.service < 服务状态:" 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)" +curl -sS "http://127.0.0.1:${PORT}/health" || echo "(尚未就绪,请稍等后: curl http://127.0.0.1:${PORT}/health)" echo "" -echo "局域网地址: http://$(hostname -I 2>/dev/null | awk '{print $1}'):${PORT}" -echo "成绩档案系统设置 OCR 地址填: http://192.168.8.6:${PORT} (按实际 IP 修改)" +echo "管理: systemctl status|restart|stop ocr-worker" +echo "日志: journalctl -u ocr-worker -f" diff --git a/deploy/repair.sh b/deploy/repair.sh index bf1bed6..f5009ff 100644 --- a/deploy/repair.sh +++ b/deploy/repair.sh @@ -22,7 +22,7 @@ log_info "开始修复 grade-archive 服务…" stop_legacy_pm2 install_ocr_deps_safe if [[ -x "${INSTALL_DIR}/deploy/ocr-worker/.venv/bin/uvicorn" ]]; then - start_ocr_screen || log_warn "OCR screen 启动失败" + start_ocr_service || log_warn "OCR systemd 启动失败" wait_ocr_healthy || log_warn "OCR 未就绪" fi setup_systemd_service diff --git a/deploy/update.sh b/deploy/update.sh index 72c8bbc..7250ed5 100644 --- a/deploy/update.sh +++ b/deploy/update.sh @@ -39,11 +39,10 @@ pip_install_with_fallback -r requirements.txt deactivate cd "${INSTALL_DIR}" -log_info "更新 OCR Worker 并重启 screen…" +log_info "更新 OCR Worker 并重启 systemd 服务…" install_ocr_worker -stop_ocr_screen -start_ocr_screen -wait_ocr_healthy || log_warn "OCR 加载中,稍后: bash deploy/ocr-screen.sh status" +start_ocr_service +wait_ocr_healthy || log_warn "OCR 加载中,稍后: systemctl status ocr-worker" stop_legacy_pm2 install_ocr_deps_safe diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index 07cf016..ccc3536 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -196,8 +196,12 @@ systemctl status grade-archive # 查看状态 ```bash sudo systemctl stop ocr-worker sudo systemctl start ocr-worker +sudo systemctl status ocr-worker +journalctl -u ocr-worker -f ``` +一键部署会自动 `systemctl enable ocr-worker`,重启后 OCR 随系统启动。 + 停止后浏览器访问 `http://<服务器IP>:23566` 会无法连接;启动后即可恢复。 ---