FROM python:3.12-slim ENV PYTHONUNBUFFERED=1 \ UV_SYSTEM_PYTHON=1 \ APP_DATA_DIR=/data \ VIDEO_ARCHIVE=/videos # ffmpeg does the trimming and frame extraction; libgl1/libglib2.0-0 are what # OpenCV needs once ultralytics pulls in the non-headless build. RUN apt-get update && apt-get install -y --no-install-recommends \ ffmpeg libgl1 libglib2.0-0 \ && rm -rf /var/lib/apt/lists/* # uv comes from PyPI rather than `COPY --from=ghcr.io/astral-sh/uv`: pulling it # from a second registry made every build fail whenever ghcr.io was unreachable, # even with all the dependency layers already cached. This is the only pip call # in the project — bootstrapping the tool that installs everything else. RUN pip install --no-cache-dir uv WORKDIR /app # Dependencies first so code edits don't re-download ~3 GB of CUDA wheels. COPY requirements.txt ./ RUN uv pip install -r requirements.txt # The vendored SAM3 declares timm/ftfy/regex/tqdm itself, so this install keeps # its dependencies (unlike einops + pycocotools, which it needs but never # declares — those are pinned in requirements.txt). COPY sam3/ ./sam3/ RUN uv pip install -e ./sam3 # The counting pipeline (tracker, stabiliser, line counter) lives in # algoritma-batch and imports itself as `src.*`. Copied to /app/src so those # imports resolve unchanged rather than being duplicated into backend/. COPY algoritma-batch/src/ ./src/ # tracking.py resolves its ByteTrack tuning as ../cfg/tracker.yaml relative to # src/, so the two directories have to keep that shape inside the image. COPY algoritma-batch/cfg/ ./cfg/ COPY backend/ ./backend/ EXPOSE 8000 CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "8000"]