| # Etymology Graph Explorer | |
| # Multi-stage build: uv for building, plain Python for runtime | |
| FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder | |
| WORKDIR /app | |
| # Copy dependency files first for layer caching | |
| COPY pyproject.toml uv.lock ./ | |
| # Install production dependencies only (no dev, no project yet) | |
| RUN uv sync --locked --no-install-project --no-dev | |
| # Copy application code | |
| COPY backend/ backend/ | |
| COPY frontend/ frontend/ | |
| # Production stage - plain Python, no uv needed at runtime | |
| FROM python:3.12-slim-bookworm | |
| WORKDIR /app | |
| # Install zstd for decompression (only needed if DB is compressed) | |
| RUN apt-get update && apt-get install -y --no-install-recommends zstd && rm -rf /var/lib/apt/lists/* | |
| # Copy only what we need from builder | |
| COPY --from=builder /app/.venv /app/.venv | |
| COPY --from=builder /app/backend /app/backend | |
| COPY --from=builder /app/frontend /app/frontend | |
| COPY --from=builder /app/pyproject.toml /app/pyproject.toml | |
| # Copy database (compressed or uncompressed) and decompress if needed | |
| COPY backend/data/etymdb.duckdb* /app/backend/data/ | |
| RUN if [ -f /app/backend/data/etymdb.duckdb.zst ]; then \ | |
| echo "Decompressing database..." && \ | |
| zstd -d /app/backend/data/etymdb.duckdb.zst -o /app/backend/data/etymdb.duckdb && \ | |
| rm /app/backend/data/etymdb.duckdb.zst; \ | |
| fi | |
| # Use the virtual environment | |
| ENV PATH="/app/.venv/bin:$PATH" | |
| # Port configuration (HF Spaces uses 7860) | |
| ENV PORT=7860 | |
| EXPOSE ${PORT} | |
| # Health check | |
| HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ | |
| CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:${PORT}/health')" || exit 1 | |
| CMD uvicorn backend.main:app --host 0.0.0.0 --port ${PORT} | |