# ════════════════════════════════════════════════════════════════ # Stage 1: Build the React frontend # ════════════════════════════════════════════════════════════════ FROM node:20-alpine AS frontend-builder WORKDIR /app/frontend COPY frontend/package*.json ./ RUN npm ci --prefer-offline && npm cache clean --force COPY frontend . RUN npm run build # ════════════════════════════════════════════════════════════════ # Stage 2: Build the FastAPI backend (HybridRAG) # ════════════════════════════════════════════════════════════════ FROM python:3.10-slim AS backend WORKDIR /app RUN apt-get update && apt-get install -y \ build-essential \ curl \ git \ git-lfs \ && rm -rf /var/lib/apt/lists/* \ && git lfs install --skip-repo RUN addgroup --system appgroup && \ adduser --system --ingroup appgroup --no-create-home appuser RUN pip install --no-cache-dir \ torch==2.2.2+cpu \ --index-url https://download.pytorch.org/whl/cpu COPY backend/requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY backend ./backend RUN find /app/backend/data -type f \( -name "*.pdf" -o -name "*.docx" -o -name "*.xlsx" \) | \ while read f; do \ size=$(stat -c%s "$f"); \ if [ "$size" -lt 500 ]; then \ echo "WARNING: $f is an LFS pointer stub ($size bytes) - RAG will be empty!"; \ fi; \ done RUN mkdir -p ./backend/static COPY --from=frontend-builder /app/frontend/dist ./backend/static RUN mkdir -p /app/backend/data/chroma_db /app/backend/storage/chroma_db /app/backend/storage/chat_db && \ chown -R appuser:appgroup /app USER appuser RUN mkdir -p /tmp/huggingface /tmp/sentence-transformers /tmp/transformers /tmp/.cache && \ chown -R appuser:appgroup /tmp/huggingface /tmp/sentence-transformers /tmp/transformers /tmp/.cache ENV PYTHONPATH=/app/backend \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ HF_HOME=/tmp/huggingface \ HUGGINGFACE_HUB_CACHE=/tmp/huggingface/hub \ SENTENCE_TRANSFORMERS_HOME=/tmp/sentence-transformers \ TRANSFORMERS_CACHE=/tmp/transformers \ XDG_CACHE_HOME=/tmp/.cache EXPOSE 7860 HEALTHCHECK --interval=30s --timeout=15s --start-period=600s --retries=3 \ CMD curl -f http://localhost:7860/api/v1/health || exit 1 CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", \ "--workers", "1", "--log-level", "info"]