| # Stage 1: Build React frontend | |
| FROM node:20-slim AS frontend-build | |
| WORKDIR /frontend | |
| COPY frontend/package*.json ./ | |
| RUN npm ci | |
| COPY frontend/ ./ | |
| RUN npm run build | |
| # Stage 2: Python runtime | |
| FROM python:3.11-slim | |
| WORKDIR /app | |
| RUN apt-get update && apt-get install -y --no-install-recommends git && rm -rf /var/lib/apt/lists/* | |
| # CPU-only torch + torchaudio — MUST use CPU index; CUDA torchaudio needs libcudart which doesn't exist on free tier | |
| RUN pip install --no-cache-dir torch torchaudio --index-url https://download.pytorch.org/whl/cpu | |
| # Core deps | |
| RUN pip install --no-cache-dir \ | |
| "transformers>=4.39.0,<4.46.0" \ | |
| soundfile numpy \ | |
| fastapi "uvicorn[standard]" \ | |
| python-dotenv \ | |
| "huggingface_hub>=0.20.0,<1.0.0" \ | |
| "pydantic-settings>=2.0.0,<3.0.0" \ | |
| aiofiles | |
| # parler-tts deps — --no-deps prevents dac/audiotools from downgrading torch | |
| RUN pip install --no-cache-dir --no-deps descript-audio-codec descript-audiotools | |
| RUN pip install --no-cache-dir flatten_dict julius argbind | |
| RUN pip install --no-cache-dir git+https://github.com/huggingface/parler-tts.git | |
| # Copy source | |
| COPY backend/ /app/backend/ | |
| COPY --from=frontend-build /frontend/dist /app/frontend/dist | |
| # HF Spaces defaults — override via Space Secrets | |
| ENV WARMUP_ON_START=false | |
| ENV GENERATION_TIMEOUT=600 | |
| ENV WARMUP_TIMEOUT=600 | |
| ENV CORS_ORIGIN=* | |
| # Cache model in HF Spaces persistent storage so it survives restarts | |
| ENV HF_HOME=/data/hf_cache | |
| EXPOSE 7860 | |
| WORKDIR /app/backend | |
| CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"] | |