FROM python:3.10.14-slim # Prevent Python from buffering stdout/stderr (important for logging) ENV PYTHONUNBUFFERED=1 ENV PYTHONDONTWRITEBYTECODE=1 WORKDIR /app # System dependencies required by librosa / soundfile / audioread. # - libsndfile1 → WAV / FLAC / OGG decoding # - ffmpeg → AAC / MP4 / M4A decoding (Apple Music previews, iTunes, # and m4a mic recordings from iOS — REQUIRED) # Note: HF Spaces ignores packages.txt when a Dockerfile is present, so # every system package must be declared here. RUN apt-get update && apt-get install -y --no-install-recommends \ libsndfile1 \ ffmpeg \ && rm -rf /var/lib/apt/lists/* # Install Python dependencies COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # Copy application code COPY . . # Create non-root user (HF Spaces best practice) RUN useradd --create-home --shell /bin/bash appuser \ && chown -R appuser:appuser /app USER appuser # Expose the HF Spaces port EXPOSE 7860 # Health check — hit the /health endpoint every 30s HEALTHCHECK --interval=30s --timeout=10s --start-period=120s --retries=3 \ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:7860/health')" || exit 1 # Uvicorn flags — set explicitly because the defaults are unsafe for SSE. # # --timeout-keep-alive 120 # Default is 5 seconds. The /analyze endpoint downloads up to 5 MB # from Apple Music CDNs with a 10-second client-side timeout, and # SSE streams may not emit their first event for ~30 seconds on a # cold-start container. With keep-alive=5 the connection is closed # before the first event reaches the client — exactly the # "backend never finalises" symptom Apple cited. # # --limit-concurrency 32 # Connection-level cap. Lets uvicorn 503 incoming connections it # cannot serve instead of accepting them and parking them. # Complements the application-level Semaphore(2) — that handles # inference fairness; this handles socket-level backpressure. CMD ["uvicorn", "main:app", \ "--host", "0.0.0.0", \ "--port", "7860", \ "--timeout-keep-alive", "120", \ "--limit-concurrency", "32"]