#!/usr/bin/env bash # ============================================================================= # 离线机部署脚本(在【不能联网】的机器上跑) # # 自动识别打包模式: # A) 自包含包(含项目内 python/):解压到【任意目标路径】,默认当前目录。 # bash deploy.sh 包.tar.gz [目标父目录] # 例: bash deploy.sh bundle.tar.gz /opt # B) venv 包:解压到 / 还原到相同绝对路径(要求同路径/同用户/同架构)。 # bash deploy.sh 包.tar.gz # # 前提:与打包机【同 CPU 架构(x86_64)】且【glibc 不比打包机老】。 # 离线机不需要 uv / python / gcc / 联网。 # ============================================================================= set -euo pipefail BUNDLE="${1:-/tmp/ocr_offline_bundle.tar.gz}" TARGET="${2:-$(pwd)}" # 自包含模式的解压目标父目录 log() { echo -e "\n\033[1;32m==> $*\033[0m"; } warn() { echo -e "\033[1;33m[警告] $*\033[0m"; } [ -f "$BUNDLE" ] || { echo "找不到包: $BUNDLE"; exit 1; } log "[1/3] 兼容性 + 模式识别" echo " 架构: $(uname -m)(需与打包机一致,一般 x86_64)" echo " glibc: $(ldd --version 2>/dev/null | head -1 | awk '{print $NF}')(不能比打包机老)" # 看包里第一个条目:以 / 或 data/ 之类绝对路径开头 = venv 模式;以纯目录名开头 = 自包含 # 注意:head 关管道会让 tar 收到 SIGPIPE 返回非零,配合 set -e/pipefail 会误退出,故加 || true FIRST="$(tar tzf "$BUNDLE" 2>/dev/null | head -1 || true)" echo " 包内首条目: $FIRST" PROJDIR="" if printf '%s' "$FIRST" | grep -qE '^(/|root/|home/|data/|usr/|opt/)'; then # ---------- venv 模式:解压到 / ---------- log "[2/3] venv 模式 → 解压到 / (还原到原绝对路径)" tar xzf "$BUNDLE" -C / # 项目目录 = 第一条目里到 ocr_data 那一段的绝对路径(取含项目名的目录) PROJDIR="/$(printf '%s' "$FIRST" | sed -E 's#(.*/[^/]*ocr[_-]?data)/.*#\1#')" warn "venv 模式:必须解压到相同路径/同用户,否则 venv 失效" else # ---------- 自包含模式:解压到目标目录 ---------- log "[2/3] 自包含模式 → 解压到 $TARGET" mkdir -p "$TARGET" tar xzf "$BUNDLE" -C "$TARGET" TOP="$(printf '%s' "$FIRST" | cut -d/ -f1)" PROJDIR="$TARGET/$TOP" fi echo " 项目目录: $PROJDIR" log "[3/3] 离线自检" cd "$PROJDIR" || { echo "进项目目录失败: $PROJDIR"; exit 1; } # shellcheck disable=SC1091 source activate.sh ok=1 ck() { if eval "$2" >/dev/null 2>&1; then echo " ✓ $1"; else echo " ✗ $1"; ok=0; fi; } ck "python" "python --version" ck "import cv2(headless)" "python -c 'import cv2'" ck "import numpy" "python -c 'import numpy'" ck "import faster_whisper" "python -c 'import faster_whisper'" ck "import qcloud_cos" "python -c 'import qcloud_cos'" ck "ffmpeg(bin/)" "ffmpeg -version" ck "ffmpeg 支持 AV1" "ffmpeg -hide_banner -decoders | grep -iE 'dav1d|av1'" ck "coscli" "./coscli-linux-amd64 --help" MODEL="$(python -c "import json;print(json.load(open('config/config.json'))['audio'].get('model_size','small'))" 2>/dev/null || echo small)" ck "whisper 模型离线加载" "python -c \"from faster_whisper import WhisperModel; WhisperModel('$MODEL',device='cpu',compute_type='int8')\"" echo if [ "$ok" -eq 1 ]; then log "全部就绪 ✅ 可离线运行" echo " cd $PROJDIR && source activate.sh" echo " python main.py --source-list ./text2 --max-workers 12" else warn "有项目未通过(见上面 ✗)。常见原因:架构/glibc 不匹配;venv 模式下路径/用户不一致" fi