首次提交

This commit is contained in:
2026-09-28 16:09:31 +08:00
commit 4a6839319a
71 changed files with 12144 additions and 0 deletions

75
scripts/deploy.sh Normal file
View File

@@ -0,0 +1,75 @@
#!/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