Rishabh2095's picture
Stop tracking job_writer.log
45de167
# syntax=docker/dockerfile:1.4
FROM langchain/langgraph-api:3.12
# Set Python environment variables (best practice)
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
PORT=7860 \
LANGGRAPH_PORT=7860
# Create user with UID 1000 for HuggingFace Spaces compatibility
RUN useradd -m -u 1000 hf_user
ENV LANGSERVE_GRAPHS='{"job_app_graph": "/deps/job_writer/src/job_writing_agent/graph/agent_workflow_graph.py:job_app_graph", "research_workflow": "/deps/job_writer/src/job_writing_agent/nodes/research_workflow.py:research_workflow", "data_loading_workflow": "/deps/job_writer/src/job_writing_agent/nodes/data_loading_workflow.py:data_loading_workflow"}'
# Copy package metadata and structure files (needed for editable install)
COPY --chown=hf_user:hf_user pyproject.toml langgraph.json README.md /deps/job_writer/
# Create src directory structure (needed for setuptools to find packages)
RUN mkdir -p /deps/job_writer/src
# Copy source code (required for editable install)
COPY --chown=hf_user:hf_user src/ /deps/job_writer/src/
# Install Python dependencies as ROOT using --system flag
# Using cache mount for faster rebuilds
RUN --mount=type=cache,target=/root/.cache/uv \
for dep in /deps/*; do \
if [ -d "$dep" ]; then \
echo "Installing $dep"; \
(cd "$dep" && uv pip install --system --no-cache-dir -c /api/constraints.txt -e .); \
fi; \
done
# Install Playwright system dependencies (after playwright package is installed)
RUN playwright install-deps chromium
# Create user's cache directory for Playwright browsers (BEFORE installing browsers)
# This ensures browsers are installed to the correct location that persists in the image
RUN mkdir -p /home/hf_user/.cache/ms-playwright && \
chown -R hf_user:hf_user /home/hf_user/.cache
# Install Playwright browser binaries to user's home directory
# Set PLAYWRIGHT_BROWSERS_PATH to ensure browsers are installed to the right location
# Use cache mount ONLY for the download cache, but install to persistent location
RUN --mount=type=cache,target=/root/.cache/ms-playwright \
PLAYWRIGHT_BROWSERS_PATH=/home/hf_user/.cache/ms-playwright \
playwright install chromium && \
# Fix ownership after installation (browsers are installed as root)
chown -R hf_user:hf_user /home/hf_user/.cache/ms-playwright
# Create API directories and install langgraph-api as ROOT
RUN mkdir -p /api/langgraph_api /api/langgraph_runtime /api/langgraph_license && \
touch /api/langgraph_api/__init__.py /api/langgraph_runtime/__init__.py /api/langgraph_license/__init__.py && \
uv pip install --system --no-cache-dir --no-deps -e /api
# Fix permissions for packages that write to their own directories
# Make ONLY the specific directories writable (not entire site-packages)
RUN mkdir -p /usr/local/lib/python3.12/site-packages/litellm/litellm_core_utils/tokenizers && \
chown -R hf_user:hf_user /usr/local/lib/python3.12/site-packages/litellm/litellm_core_utils/tokenizers && \
chmod -R u+w /usr/local/lib/python3.12/site-packages/litellm/litellm_core_utils/tokenizers
# Create user cache directories with proper permissions (BEFORE switching user)
# Following XDG Base Directory Specification: https://specifications.freedesktop.org/basedir-spec/
RUN mkdir -p /home/hf_user/.cache/tiktoken \
/home/hf_user/.cache/litellm \
/home/hf_user/.cache/huggingface \
/home/hf_user/.cache/torch \
/home/hf_user/.local/share && \
chown -R hf_user:hf_user /home/hf_user/.cache /home/hf_user/.local
# Switch to hf_user for runtime (after all root operations)
USER hf_user
# Set environment variables following XDG Base Directory Specification
# This ensures all packages respect standard cache locations
ENV HOME=/home/hf_user \
PATH="/home/hf_user/.local/bin:$PATH" \
XDG_CACHE_HOME=/home/hf_user/.cache \
XDG_DATA_HOME=/home/hf_user/.local/share \
XDG_CONFIG_HOME=/home/hf_user/.config \
# Package-specific cache directories (for packages that don't fully respect XDG)
TIKTOKEN_CACHE_DIR=/home/hf_user/.cache/tiktoken \
HF_HOME=/home/hf_user/.cache/huggingface \
TORCH_HOME=/home/hf_user/.cache/torch \
# Playwright browsers path (so it knows where to find browsers at runtime)
PLAYWRIGHT_BROWSERS_PATH=/home/hf_user/.cache/ms-playwright
WORKDIR /deps/job_writer
# Expose port for HuggingFace Spaces
EXPOSE 7860
# Healthcheck (LangGraph API typically has /ok endpoint)
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:7860/ok')" || exit 1