# media-analyzer: JoyCaption (via vLLM, OpenAI-compatible) + GPU face # detection/embedding (InsightFace buffalo_l on onnxruntime-gpu), fronted by # one FastAPI gateway owning bearer auth and instrumentation. # # Patterns follow ~/huggingface-engines (tts-dialogue-engine-moss), the # proven docker-Space template: uid-1000 user (HF chowns /data to 1000), # HF_HOME on LOCAL disk (mmap from the network-backed /data volume hangs # mid-load), PYTHONUNBUFFERED, app_port 7860. # # Base: the official vLLM image — its torch/vllm/CUDA/cuDNN are aligned, # which is exactly the versioning we don't want to hand-roll. onnxruntime-gpu # >=1.19 targets the same CUDA 12 / cuDNN 9 family. FROM vllm/vllm-openai:latest RUN apt-get update && apt-get install -y --no-install-recommends \ unzip curl \ && rm -rf /var/lib/apt/lists/* # The vllm image's python is pip-managed; PIP_BREAK_SYSTEM_PACKAGES covers # newer Debian/Ubuntu externally-managed setups either way. ENV PIP_BREAK_SYSTEM_PACKAGES=1 # insightface depends on plain `onnxruntime` (the CPU wheel), and both ORT # packages unpack into the SAME `onnxruntime` module directory — whichever # installs last wins file-by-file. So: install insightface (and friends) # first, then purge every ORT flavor, then force-reinstall the GPU wheel # LAST so all module files belong to it. RUN pip install --no-cache-dir \ insightface \ "fastapi>=0.115" \ "uvicorn>=0.30" \ "httpx>=0.27" \ opencv-python-headless \ hf_transfer RUN pip uninstall -y onnxruntime onnxruntime-gpu 2>/dev/null || true RUN pip install --no-cache-dir --force-reinstall --no-deps onnxruntime-gpu \ # numpy/protobuf etc. are already present via insightface; --no-deps keeps # this step from dragging anything else in. Then PROVE the CUDA provider # is at least available in the installed package at build time. && python3 -c "import onnxruntime as ort; assert 'CUDAExecutionProvider' in ort.get_available_providers(), ort.get_available_providers()" # Pre-bake buffalo_l (SCRFD detector + ArcFace w600k) so the face endpoint is # ready at container start. FaceAnalysis(root=/opt/insightface) resolves # {root}/models/buffalo_l. RUN mkdir -p /opt/insightface/models/buffalo_l \ && curl -L -o /tmp/buffalo_l.zip \ https://github.com/deepinsight/insightface/releases/download/v0.7/buffalo_l.zip \ && unzip -o /tmp/buffalo_l.zip -d /opt/insightface/models/buffalo_l \ && rm /tmp/buffalo_l.zip \ # fail the BUILD if the zip layout ever changes — a missing file here # would otherwise surface as a runtime re-download attempt into a # read-only path && test -f /opt/insightface/models/buffalo_l/det_10g.onnx \ && test -f /opt/insightface/models/buffalo_l/w600k_r50.onnx \ && chmod -R a+rX /opt/insightface # Claim uid 1000 — the uid HF Spaces chowns the persistent /data volume to. RUN userdel -r ubuntu 2>/dev/null || true \ && useradd -m -u 1000 user WORKDIR /app COPY gateway.py start.sh ./ RUN chmod +x start.sh && chown -R user:user /app USER user # Reduce VRAM fragmentation (set before CUDA init). vLLM and the ONNX face # session share the GPU; vLLM's slice is bounded by GPU_MEM_UTIL below. ENV PYTORCH_CUDA_ALLOC_CONF="expandable_segments:True" ENV PYTHONUNBUFFERED=1 # HF_HOME must be LOCAL disk (weights are mmap'd from here). If the Space has # persistent storage, start.sh restores a previously saved cache from # HF_PERSIST_DIR before downloading. ENV HF_HOME=/app/.hf-cache \ HF_PERSIST_DIR=/model-storage/huggingface \ HF_HUB_ENABLE_HF_TRANSFER=1 \ MODEL_ID=fancyfeast/llama-joycaption-beta-one-hf-llava \ SERVED_MODEL_NAME=joycaption-beta-one \ VLLM_PORT=8001 \ GPU_MEM_UTIL=0.85 \ VLLM_ENFORCE_EAGER=0 \ MAX_MODEL_LEN=4096 \ PORT=7860 EXPOSE 7860 ENTRYPOINT ["./start.sh"]