Skip to content

优化:记录预测模型来源路径 #26

优化:记录预测模型来源路径

优化:记录预测模型来源路径 #26

name: 同步到 Hugging Face Space
on:
push:
branches:
- main
workflow_dispatch:
concurrency:
group: sync-huggingface-space
cancel-in-progress: true
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: 检出仓库
uses: actions/checkout@v4
with:
fetch-depth: 1
lfs: true
- name: 安装同步工具
run: |
sudo apt-get update
sudo apt-get install -y git-lfs rsync
git lfs install
- name: 准备部署包
env:
GH_TOKEN: ${{ github.token }}
MODEL_URL_SECRET: ${{ secrets.MODEL_URL }}
MODEL_URL_VAR: ${{ vars.MODEL_URL }}
MODEL_RELEASE_TAG: ${{ vars.MODEL_RELEASE_TAG || 'model' }}
MODEL_RELEASE_ASSET: ${{ vars.MODEL_RELEASE_ASSET || 'BILSTM_Att.pt' }}
run: |
set -euo pipefail
STAGING_DIR="${RUNNER_TEMP}/hf-staging"
rm -rf "${STAGING_DIR}"
mkdir -p "${STAGING_DIR}"
rsync -a README.md Dockerfile requirements.txt requirements-lite.txt main.py .env.example .gitattributes "${STAGING_DIR}/"
rsync -a api BILSTM_Att Data_CrawlProcess tool_utils frontend "${STAGING_DIR}/"
rm -rf \
"${STAGING_DIR}/frontend/.next" \
"${STAGING_DIR}/frontend/out" \
"${STAGING_DIR}/frontend/node_modules" \
"${STAGING_DIR}/frontend/tsconfig.tsbuildinfo"
find "${STAGING_DIR}" -type d -name "__pycache__" -prune -exec rm -rf {} +
find "${STAGING_DIR}" -type f \( -name "*.pyc" -o -name "*.pyo" \) -delete
MODEL_URL="${MODEL_URL_SECRET:-${MODEL_URL_VAR:-}}"
MODEL_PATH="${STAGING_DIR}/static/saved_model/BILSTM_Att.pt"
downloaded_model=0
if [ -n "${MODEL_URL}" ]; then
mkdir -p "${STAGING_DIR}/static/saved_model"
echo "正在从 MODEL_URL 下载模型到 static/saved_model/BILSTM_Att.pt"
if curl -L --fail --retry 3 --retry-delay 10 --retry-all-errors \
"${MODEL_URL}" \
-o "${MODEL_PATH}"; then
downloaded_model=1
else
echo "::warning::MODEL_URL 下载失败,将尝试 GitHub Release Asset。"
rm -f "${MODEL_PATH}"
fi
fi
if [ "${downloaded_model}" -eq 0 ]; then
mkdir -p "${STAGING_DIR}/static/saved_model"
if gh release view "${MODEL_RELEASE_TAG}" -R "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then
echo "正在从 GitHub Release ${MODEL_RELEASE_TAG} 下载 ${MODEL_RELEASE_ASSET}"
gh release download "${MODEL_RELEASE_TAG}" \
-R "${GITHUB_REPOSITORY}" \
-p "${MODEL_RELEASE_ASSET}" \
-D "${STAGING_DIR}/static/saved_model" \
--clobber
if [ -f "${STAGING_DIR}/static/saved_model/${MODEL_RELEASE_ASSET}" ] && [ "${MODEL_RELEASE_ASSET}" != "BILSTM_Att.pt" ]; then
mv "${STAGING_DIR}/static/saved_model/${MODEL_RELEASE_ASSET}" "${MODEL_PATH}"
fi
if [ -f "${MODEL_PATH}" ]; then
downloaded_model=1
fi
else
echo "未找到 GitHub Release ${MODEL_RELEASE_TAG},保留 Hugging Face Space 仓库中已有模型。"
fi
fi
if [ "${downloaded_model}" -eq 0 ]; then
rm -rf "${STAGING_DIR}/static/saved_model"
fi
echo "部署包目录:${STAGING_DIR}"
find "${STAGING_DIR}" -maxdepth 3 -type d | sort
- name: 增量同步到 Hugging Face Space
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
HF_SPACE_ID: ${{ vars.HF_SPACE_ID || secrets.HF_SPACE_ID }}
run: |
set -euo pipefail
if [ -z "${HF_TOKEN}" ]; then
echo "缺少 GitHub Secret: HF_TOKEN"
exit 1
fi
if [ -z "${HF_SPACE_ID}" ]; then
echo "缺少 GitHub Variable 或 Secret: HF_SPACE_ID,例如 username/space-name"
exit 1
fi
STAGING_DIR="${RUNNER_TEMP}/hf-staging"
SPACE_DIR="${RUNNER_TEMP}/hf-space"
rm -rf "${SPACE_DIR}"
export GIT_LFS_SKIP_SMUDGE=1
git clone "https://hf:${HF_TOKEN}@huggingface.co/spaces/${HF_SPACE_ID}" "${SPACE_DIR}"
unset GIT_LFS_SKIP_SMUDGE
cd "${SPACE_DIR}"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git lfs install --local
git lfs track "*.png" "*.jpg" "*.jpeg" "*.webp" "*.ico" "*.woff" "*.woff2" "*.ttf" "*.otf" "*.pt"
LFS_PATTERNS=("*.png" "*.jpg" "*.jpeg" "*.webp" "*.ico" "*.woff" "*.woff2" "*.ttf" "*.otf" "*.pt")
rebuild_space_history() {
echo "Hugging Face 拒绝了历史中的普通二进制文件,开始重建 Space 部署分支并改用 LFS 指针。"
clean_branch="hf-clean-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}"
git checkout --orphan "${clean_branch}"
git rm -r --cached . >/dev/null 2>&1 || true
git lfs install --local
git lfs track "${LFS_PATTERNS[@]}"
git add -A
git commit -m "重建部署包:${GITHUB_SHA}"
for clean_attempt in 1 2 3 4; do
if git push origin HEAD:main --force-with-lease; then
echo "已重建 Hugging Face Space 部署分支。"
return 0
fi
sleep_seconds=$((clean_attempt * clean_attempt * 90))
echo "重建推送失败,可能仍在限流。第 ${clean_attempt}/4 次失败,等待 ${sleep_seconds}s 后重试。"
sleep "${sleep_seconds}"
done
return 1
}
RSYNC_EXCLUDES=(
"--exclude=.git/"
)
if [ ! -f "${STAGING_DIR}/static/saved_model/BILSTM_Att.pt" ]; then
RSYNC_EXCLUDES+=("--exclude=static/saved_model/")
fi
rsync -a --delete --checksum "${RSYNC_EXCLUDES[@]}" "${STAGING_DIR}/" "${SPACE_DIR}/"
git lfs track "${LFS_PATTERNS[@]}"
git add -A
if git diff --cached --quiet; then
echo "Hugging Face Space 已是最新,无需推送。"
exit 0
fi
echo "本次同步变更:"
git status --short
git commit -m "同步部署包:${GITHUB_SHA}"
for attempt in 1 2 3 4 5; do
push_log="${RUNNER_TEMP}/hf-push-${attempt}.log"
if git push origin HEAD:main 2>&1 | tee "${push_log}"; then
exit 0
fi
if grep -Eiq "contains binary files|xet|pre-receive hook declined" "${push_log}"; then
rebuild_space_history
exit $?
fi
sleep_seconds=$((attempt * attempt * 45))
echo "Hugging Face 推送失败,可能是 429 限流。第 ${attempt}/5 次失败,等待 ${sleep_seconds}s 后重试。"
sleep "${sleep_seconds}"
git pull --rebase origin main || true
done
echo "Hugging Face 推送重试耗尽。请稍后手动重新运行 workflow。"
exit 1