优化:记录预测模型来源路径 #26
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |