85 lines
3.9 KiB
Bash
85 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# 离线部署打包脚本(在【能联网】的机器上跑)
|
||
#
|
||
# 两种模式自动识别:
|
||
# A) 自包含模式(已跑过 make_portable.sh,项目内有 ./python + ./models)
|
||
# → 打包里只含项目这一个文件夹,离线机解压到【任意路径/任意用户】即可。
|
||
# B) venv 模式(只有 .venv)
|
||
# → 打项目 + /root 下的 uv Python + HF 缓存,离线机要解压到相同路径。
|
||
#
|
||
# 用法: bash pack.sh
|
||
# 产物: /tmp/ocr_offline_bundle.tar.gz
|
||
# =============================================================================
|
||
set -euo pipefail
|
||
|
||
cd "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
PROJECT_DIR="$(pwd)"
|
||
OUT="${1:-/tmp/ocr_offline_bundle.tar.gz}"
|
||
|
||
log() { echo -e "\n\033[1;32m==> $*\033[0m"; }
|
||
warn() { echo -e "\033[1;33m[警告] $*\033[0m"; }
|
||
have() { command -v "$1" >/dev/null 2>&1; }
|
||
|
||
PBASE="$(basename "$PROJECT_DIR")"
|
||
PPARENT="$(dirname "$PROJECT_DIR")"
|
||
|
||
# 运行时数据排除(部署不需要,打进去又慢又大)。用项目目录名作前缀,两种模式通用。
|
||
RT_DIRS=(split video composite coscli_output srt info info_error log)
|
||
EXCLUDES=(--exclude='*.log' --exclude='__pycache__' --exclude='*.pyc'
|
||
--exclude="$PBASE/数据.jsonl")
|
||
for d in "${RT_DIRS[@]}"; do EXCLUDES+=(--exclude="$PBASE/$d"); done
|
||
|
||
# 选最快的压缩器:pigz 多线程(输出仍是标准 gzip,离线机普通 tar xzf 就能解)
|
||
if have pigz; then
|
||
COMPRESS="pigz"; log "用 pigz 多线程压缩(快)"
|
||
else
|
||
COMPRESS="gzip -1"; warn "未装 pigz,用 gzip -1;想更快可先 yum install -y pigz"
|
||
fi
|
||
|
||
if [ -x "$PROJECT_DIR/python/bin/python3" ]; then
|
||
# ---------- A) 自包含:只打项目目录(用相对名),可解压到任意路径 ----------
|
||
log "自包含模式(项目内含 ./python + ./models)"
|
||
[ -d "$PROJECT_DIR/models" ] || warn "没看到 ./models,确认 make_portable.sh 跑完整了"
|
||
tar "${EXCLUDES[@]}" --use-compress-program="$COMPRESS" -cf "$OUT" \
|
||
-C "$PPARENT" "$PBASE"
|
||
MODE="自包含(解压到任意路径/用户)"
|
||
else
|
||
# ---------- B) venv:打项目(绝对路径) + 外部 Python + HF 缓存 ----------
|
||
[ -d .venv ] || { echo "既没有 ./python 也没有 .venv,请先 setup_server.sh 或 make_portable.sh"; exit 1; }
|
||
# shellcheck disable=SC1091
|
||
source .venv/bin/activate
|
||
|
||
log "venv 模式:确保 headless opencv + 预下载模型"
|
||
uv pip uninstall opencv-python 2>/dev/null || true
|
||
uv pip install opencv-python-headless \
|
||
--index-url "${PIP_MIRROR:-https://repo.huaweicloud.com/repository/pypi/simple}" 2>/dev/null \
|
||
|| echo "(headless 可能已装,忽略)"
|
||
MODEL="$(python -c "import json;print(json.load(open('config/config.json'))['audio'].get('model_size','small'))")"
|
||
HF_HUB_OFFLINE=0 TRANSFORMERS_OFFLINE=0 HF_ENDPOINT="${HF_ENDPOINT:-https://hf-mirror.com}" \
|
||
python -c "from faster_whisper import WhisperModel; WhisperModel('$MODEL',device='cpu',compute_type='int8'); print('模型已缓存')"
|
||
|
||
PYDIR="$(dirname "$(dirname "$(readlink -f .venv/bin/python)")")"
|
||
HFCACHE="${HF_HOME:-$HOME/.cache/huggingface}"
|
||
echo " uv Python: $PYDIR 模型缓存: $HFCACHE"
|
||
|
||
log "打包项目(绝对路径) + Python + 模型缓存"
|
||
# 项目用绝对路径(还原到原位),外部两目录同理
|
||
EXABS=(--exclude='*.log' --exclude='__pycache__' --exclude='*.pyc'
|
||
--exclude="${PROJECT_DIR#/}/数据.jsonl")
|
||
for d in "${RT_DIRS[@]}"; do EXABS+=(--exclude="${PROJECT_DIR#/}/$d"); done
|
||
tar "${EXABS[@]}" --use-compress-program="$COMPRESS" -cf "$OUT" \
|
||
-C / "${PROJECT_DIR#/}" -C / "${PYDIR#/}" -C / "${HFCACHE#/}"
|
||
MODE="venv(离线机需解压到相同路径/用户)"
|
||
fi
|
||
|
||
echo
|
||
log "完成 ✅ $OUT ($(du -h "$OUT" | cut -f1))"
|
||
echo "模式: $MODE"
|
||
cat <<EOF
|
||
|
||
下一步:
|
||
scp $OUT root@离线机:/tmp/
|
||
bash deploy.sh /tmp/$(basename "$OUT") # 自包含模式可加目标路径: bash deploy.sh 包 /opt
|
||
EOF
|