# ================================================================ # PVD System — HuggingFace Spaces Dockerfile # CPU only — HuggingFace free tier # ================================================================ FROM python:3.10-slim # ── Environment ─────────────────────────────────────────────── ENV PYTHONDONTWRITEBYTECODE=1 ENV PYTHONUNBUFFERED=1 ENV PYTHONPATH=/app:/app/src:/app/backend WORKDIR /app # ── Step 1: System dependencies ─────────────────────────────── RUN apt-get update && apt-get install -y \ git \ wget \ curl \ ffmpeg \ libsm6 \ libxext6 \ libgl1 \ libglib2.0-0 \ libxrender-dev \ libgomp1 \ build-essential \ gcc \ g++ \ && rm -rf /var/lib/apt/lists/* # ── Step 2: Fix pip + setuptools (pkg_resources fix) ────────── RUN pip install --upgrade pip RUN pip install "setuptools==69.5.1" wheel --force-reinstall # ── Step 3: NumPy FIRST before everything ───────────────────── RUN pip install "numpy<2.0.0" # ── Step 4: PyTorch CPU ─────────────────────────────────────── RUN pip install \ torch==2.2.2+cpu \ torchvision==0.17.2+cpu \ --index-url https://download.pytorch.org/whl/cpu # ── Step 5: Force numpy back after torch ────────────────────── # torch sometimes pulls numpy 2.x — force it back to 1.x RUN pip install "numpy<2.0.0" --force-reinstall # ── Step 6: Verify numpy is correct ─────────────────────────── RUN python -c "import numpy; print('numpy version:', numpy.__version__); assert numpy.__version__ < '2', 'NumPy 2.x detected!'" # ── Step 7: OpenMIM ─────────────────────────────────────────── RUN pip install openmim==0.3.9 # ── Step 8: mmengine first ──────────────────────────────────── RUN mim install mmengine==0.10.4 # ── Step 9: Full mmcv with C++ extensions ───────────────────── # Use pip with find-links to get pre-built wheel (no source build) # This avoids pkg_resources error from building from source RUN pip install mmcv==2.1.0 \ -f https://download.openmmlab.com/mmcv/dist/cpu/torch2.2/index.html \ --no-build-isolation # ── Step 10: Verify mmcv._ext is available ──────────────────── RUN python -c "from mmcv.ops import roi_align; print('mmcv._ext loaded successfully ✅')" # ── Step 11: mmdet ──────────────────────────────────────────── RUN mim install mmdet==3.3.0 # ── Step 12: chumpy fix then mmpose ─────────────────────────── RUN pip install chumpy --no-build-isolation RUN mim install mmpose==1.3.1 # ── Step 13: OpenCV headless ────────────────────────────────── RUN pip install opencv-python-headless==4.8.1.78 # ── Step 15: Install remaining pip packages ─────────────────── COPY requirements.txt . RUN grep -viE \ "torch|torchvision|mmcv|mmpose|mmdet|mmengine|opencv|insightface|facenet|numpy|gdown" \ requirements.txt > requirements_clean.txt && \ pip install -r requirements_clean.txt # ── Step 16: gdown for Google Drive ─────────────────────────── RUN pip install gdown # ── Step 17: Copy all project files ────────────────────────── COPY artifacts/ ./artifacts/ COPY backend/ ./backend/ COPY configs/ ./configs/ COPY scripts/ ./scripts/ COPY src/ ./src/ # ── Step 18: Download large model from Google Drive ─────────── RUN gdown "https://drive.google.com/uc?id=1P9KxRKiJ-_bX5b_IGsYOmwEPXIgyPUbV" \ -O ./artifacts/posture_classifier/weights/best_posture_model.pth && \ echo "best_posture_model.pth downloaded successfully ✅" # ── Step 19: Verify all model files exist ──────────────────── RUN python -c "\ import os; \ models = [ \ 'artifacts/mmpose/checkpoints/rtmdet_nano_8xb32-100e_coco-obj365-person-05d8511e.pth', \ 'artifacts/mmpose/checkpoints/rtmpose-tiny_simcc-aic-coco_pt-aic-coco_420e-256x192-cfc8f33d_20230126.pth', \ 'artifacts/phone_detector/pretrained/yolo11n.pt', \ 'artifacts/phone_detector/weights/best.pt', \ 'artifacts/posture_classifier/weights/best_posture_model.pth', \ ]; \ [print(f'✅ {m}') if os.path.exists(m) else print(f'❌ MISSING: {m}') for m in models]" WORKDIR /app/backend EXPOSE 7860 HEALTHCHECK --interval=30s --timeout=15s --start-period=120s --retries=3 \ CMD curl -f http://localhost:7860/health || exit 1 CMD ["python", "-m", "uvicorn", "app.main:app", \ "--host", "0.0.0.0", \ "--port", "7860", \ "--workers", "1"]