| name: Sync to Hugging Face hub |
| on: |
| push: |
| branches: [deployment] |
|
|
| workflow_dispatch: |
|
|
| jobs: |
| sync-to-hub: |
| runs-on: ubuntu-latest |
| steps: |
| - uses: actions/checkout@v4 |
| with: |
| fetch-depth: 0 |
| lfs: true |
|
|
| - name: Validate Hugging Face token |
| id: hf_auth |
| env: |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} |
| run: | |
| if [ -z "$HF_TOKEN" ]; then |
| echo "::error::GitHub secret HF_TOKEN is not set." |
| echo "Create a Hugging Face token with WRITE access to SolutionChallenge/solution_challenge_backend," |
| echo "then add it at GitHub β Settings β Secrets and variables β Actions β HF_TOKEN." |
| exit 1 |
| fi |
| pip install -q "huggingface_hub>=0.23.0" |
| python <<'PY' |
| import os, sys |
| from huggingface_hub import HfApi |
| token = os.environ["HF_TOKEN"] |
| api = HfApi(token=token) |
| try: |
| who = api.whoami(cache=True) |
| except Exception as exc: |
| print(f"::error::HF_TOKEN is invalid or expired: {exc}", file=sys.stderr) |
| sys.exit(1) |
| username = who.get("name") or who.get("fullname") or "" |
| if not username: |
| print("::error::Could not resolve Hugging Face username from token.", file=sys.stderr) |
| sys.exit(1) |
| print(f"Authenticated as Hugging Face user: {username}") |
| space_id = "SolutionChallenge/solution_challenge_backend" |
| try: |
| info = api.space_info(space_id, token=token) |
| print(f"Space found: {info.id}") |
| except Exception as exc: |
| print( |
| f"::error::Token for '{username}' cannot access {space_id}. " |
| "Accept the Solution Challenge org invite, then use a WRITE token from a member with push access.", |
| file=sys.stderr, |
| ) |
| print(f"Hub response: {exc}", file=sys.stderr) |
| sys.exit(1) |
| github_output = os.environ.get("GITHUB_OUTPUT", "") |
| if github_output: |
| with open(github_output, "a", encoding="utf-8") as out: |
| out.write(f"username={username}\n") |
| PY |
| |
| - name: Push to hub |
| env: |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} |
| HF_USER: ${{ steps.hf_auth.outputs.username }} |
| HF_SPACE: SolutionChallenge/solution_challenge_backend |
| run: | |
| git config --global user.name "github-actions" |
| git config --global user.email "github-actions@github.com" |
| git checkout --orphan hf-deploy |
| rm -rf cepheus guest-app scripts firebase.json |
| # HF Picklescan blocks .npy β ensure pickle-free .f32emb, then strip .npy |
| python3 backend/Face_Recognition/export_hf_embeddings.py || true |
| find backend/Face_Recognition -name '*.npy' -delete |
| # HF git rejects binary images via regular push β ship .f32emb only |
| find backend/Face_Recognition -name '*.jpg' -delete |
| find backend/Face_Recognition -name '*.jpeg' -delete |
| find backend/Face_Recognition -name '*.png' -delete |
| find backend/Face_Recognition -name '*.webp' -delete |
| find backend/Face_Recognition/face_database -type d -name 'unknown_*' -exec rm -rf {} + 2>/dev/null || true |
| mkdir -p backend/Face_Recognition/faces_db backend/Face_Recognition/temp_faces_db backend/Face_Recognition/face_database |
| touch backend/Face_Recognition/face_database/.gitkeep |
| find backend -name "*.pt" -delete |
| find backend -name "*.mp4" -delete |
| # Drop other large/binary artifacts not needed on the Space |
| rm -f backend/Face_Recognition/test.jpg backend/Face_Recognition/input.mp4 2>/dev/null || true |
| git add -A |
| git commit -m "Deploy to Hugging Face" |
| ENCODED_TOKEN=$(python3 -c "import os, urllib.parse; print(urllib.parse.quote(os.environ['HF_TOKEN'], safe=''))") |
| git push --force "https://SolutionChallenge:${ENCODED_TOKEN}@huggingface.co/spaces/SolutionChallenge/solution_challenge_backend" hf-deploy:main |
| |