# syntax=docker/dockerfile:1.7 # # Eolas backend container — FastAPI + LanceDB + fastembed. # # Strategy: # - Python 3.11-slim (small base; CPython is enough — onnxruntime brings perf) # - Install pip deps in their own layer so source edits don't bust the cache # - Pre-warm the BGE ONNX model at build time → first request has no 120 MB download # - Ship the LanceDB index inside the image (31 MB) → no volume needed in v0.3.0 # - Run uvicorn on $PORT (Fly sets this; defaults to 8080) # FROM python:3.11-slim AS runtime WORKDIR /app # Runtime libs onnxruntime needs (libgomp1 is the OpenMP runtime; the rest is # wheels). curl is here for the container HEALTHCHECK only. RUN apt-get update && apt-get install -y --no-install-recommends \ libgomp1 \ curl \ && rm -rf /var/lib/apt/lists/* # ── Deps layer (cached unless pyproject.toml changes) ──────────────────────── COPY pyproject.toml ./ RUN pip install --no-cache-dir --upgrade pip \ && pip install --no-cache-dir \ "httpx>=0.27" \ "trafilatura>=1.12" \ "pymupdf>=1.24" \ "beautifulsoup4>=4.12" \ "lxml>=5.3" \ "tiktoken>=0.7" \ "lancedb>=0.13" \ "fastembed>=0.4" \ "rank-bm25>=0.2" \ "flashrank>=0.2" \ "fastapi>=0.111" \ "uvicorn[standard]>=0.30" \ "python-dotenv>=1.0" \ "sse-starlette>=2.1" \ "slowapi>=0.1.9" \ "google-genai>=0.3" \ "groq>=0.11" \ "openai>=1.40" \ "anthropic>=0.34" # ── Pre-warm the embedder + reranker models ───────────────────────────────── # bge-small-en-v1.5: ~120 MB ONNX. ms-marco-MiniLM-L-12-v2: ~22 MB ONNX. # Baked into the image so cold starts have no network fetch. RUN python -c "from fastembed import TextEmbedding; TextEmbedding('BAAI/bge-small-en-v1.5')" RUN python -c "from flashrank import Ranker; Ranker(model_name='ms-marco-MiniLM-L-12-v2')" # ── Application code + indexed corpus ──────────────────────────────────────── COPY app/ ./app/ COPY widget/ ./widget/ COPY data/lancedb/ ./data/lancedb/ # Runtime configuration ENV PYTHONUNBUFFERED=1 \ LOG_FORMAT=json \ LOG_LEVEL=INFO \ PORT=8080 \ LANCEDB_PATH=/app/data/lancedb \ LANCEDB_TABLE=chunks EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -fsS http://127.0.0.1:${PORT:-8080}/health || exit 1 # Single worker — the BGE model isn't cheap to load and one process saturates # a 1-core VM. Scale horizontally on Fly instead of forking workers. CMD ["sh", "-c", "uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-8080} --workers 1"]