File size: 4,758 Bytes
8eaa451 f3d50d7 8eaa451 f3d50d7 8eaa451 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | # ════════════════════════════════════════════════════════════════
# Stage 1: Build the React frontend
# ════════════════════════════════════════════════════════════════
FROM node:20-alpine AS frontend-builder
WORKDIR /app/frontend
# Install dependencies first (better layer caching)
COPY frontend/package*.json ./
RUN npm ci --prefer-offline && npm cache clean --force
# Build
COPY frontend .
RUN npm run build
# ════════════════════════════════════════════════════════════════
# Stage 2: Build the FastAPI backend (HybridRAG)
# ════════════════════════════════════════════════════════════════
FROM python:3.10-slim AS backend
WORKDIR /app
# ── System dependencies ────────────────────────────────────────
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
# ── Non-root user (security best practice) ────────────────────
RUN addgroup --system appgroup && \
adduser --system --ingroup appgroup --no-create-home appuser
# ── CPU-only PyTorch FIRST (saves ~1.8GB vs full CUDA package) ─
RUN pip install --no-cache-dir \
torch==2.2.2+cpu \
--index-url https://download.pytorch.org/whl/cpu
# ── Python production dependencies ────────────────────────────
COPY backend/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# ── Application code ──────────────────────────────────────────
COPY backend ./backend
# ── Validate data files are real content (not LFS pointers) ───
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
# ── React frontend static files ───────────────────────────────
RUN mkdir -p ./backend/static
COPY --from=frontend-builder /app/frontend/dist ./backend/static
# ── Permissions ───────────────────────────────────────────────
# ChromaDB will be downloaded at startup from HF Dataset into data/chroma_db
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
# ── Tạo thư mục cache /tmp (writable bởi 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
# ── Environment ───────────────────────────────────────────────
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
# ── HuggingFace Spaces port ───────────────────────────────────
EXPOSE 7860
# ── Health check ──────────────────────────────────────────────
HEALTHCHECK --interval=30s --timeout=15s --start-period=600s --retries=3 \
CMD curl -f http://localhost:7860/api/v1/health || exit 1
# ── Run app ───────────────────────────────────────────────────
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", \
"--workers", "1", "--log-level", "info"]
|