# ============================================================ # Arabic Nativity Classifier — Multi-stage Docker Build # ============================================================ # Stage 1: Install Python deps (cached unless requirements change) # Stage 2: Copy app code + models → slim runtime image # ============================================================ FROM python:3.11-slim AS base # Avoid interactive prompts, set locale ENV DEBIAN_FRONTEND=noninteractive \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PIP_NO_CACHE_DIR=1 \ PIP_DISABLE_PIP_VERSION_CHECK=1 # System deps for librosa (libsndfile), soundfile, and general audio RUN apt-get update && apt-get install -y --no-install-recommends \ libsndfile1 \ ffmpeg \ libgomp1 \ curl \ && rm -rf /var/lib/apt/lists/* WORKDIR /app # ---- Stage: deps (cached layer) ---- FROM base AS deps COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt && \ pip install --no-cache-dir gunicorn # Pre-download the HuggingFace Wav2Vec2 model so it's baked into the image # (avoids ~1.2GB download on every container start) # MUST match extract_embeddings.py model used for training embeddings RUN python -c "\ from transformers import Wav2Vec2Model, AutoFeatureExtractor; \ AutoFeatureExtractor.from_pretrained('facebook/wav2vec2-lv-60-espeak-cv-ft'); \ Wav2Vec2Model.from_pretrained('facebook/wav2vec2-lv-60-espeak-cv-ft'); \ print('Wav2Vec2 lv-60-espeak-cv-ft cached.')" # ---- Stage: runtime ---- FROM deps AS runtime WORKDIR /app # Copy application code COPY scripts/ ./scripts/ COPY webapp/ ./webapp/ COPY manifests/embedding_dim.txt ./manifests/embedding_dim.txt COPY manifests/test_data.csv ./manifests/test_data.csv # Copy trained models (these must exist locally — they're gitignored) COPY models/nativity_model.pth ./models/nativity_model.pth COPY models/best_threshold.txt ./models/best_threshold.txt COPY models/lgbm_nativity.txt ./models/lgbm_nativity.txt COPY models/pca_transform.pkl ./models/pca_transform.pkl # Create uploads dir for audio temp files RUN mkdir -p /app/webapp/uploads # Expose Flask port (7860 for Hugging Face Spaces) EXPOSE 7860 # Health check — hit the /api/health endpoint HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:7860/api/health || exit 1 # Run with gunicorn for production (2 workers, 600s timeout for long audio) CMD ["gunicorn", \ "--bind", "0.0.0.0:7860", \ "--workers", "2", \ "--threads", "4", \ "--timeout", "600", \ "--access-logfile", "-", \ "--error-logfile", "-", \ "webapp.app:app"]