File size: 4,547 Bytes
8349858
046508a
 
c7be661
 
 
 
 
 
 
 
046508a
45de167
046508a
c7be661
 
 
 
 
 
 
 
046508a
c7be661
 
 
 
8349858
 
c7be661
8349858
 
046508a
c7be661
 
 
ea10140
 
 
 
 
 
 
 
8349858
ea10140
 
 
 
046508a
c7be661
8349858
 
c7be661
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ea10140
 
 
45de167
046508a
8349858
046508a
8349858
c7be661
 
 
 
 
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
93
94
95
96
# 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