File size: 2,955 Bytes
69e310f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# AlphaBrief API — FastAPI + LangGraph + the MCP tool server in one container.
#
# One image serves three things that are usually three deployments: the HTTP
# surface, the agent orchestrator, and the MCP server the agents call (spawned
# in-container over stdio). That is what makes the free tiers viable — a single
# container on Cloud Run's always-free allowance, or a Hugging Face Docker Space
# on port 7860 with no card at all.
#
# Built from the REPOSITORY ROOT, not from apps/api. Hugging Face Spaces builds
# `./Dockerfile` with the repository as its context and offers no way to point it
# elsewhere, so the paths below are root-relative and `make docker` uses the same
# context. One Dockerfile, built identically everywhere — a second, host-specific
# copy would drift, and it would drift silently until a deploy failed.
#
#   docker build -t alphabrief-api -f apps/api/Dockerfile .
#   docker run --rm -p 7860:7860 --env-file .env alphabrief-api

FROM python:3.12-slim-bookworm AS base

ENV PYTHONDONTWRITEBYTECODE=1 \
    PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    PIP_DISABLE_PIP_VERSION_CHECK=1

# curl is used by the container healthcheck only.
RUN apt-get update \
 && apt-get install -y --no-install-recommends curl \
 && rm -rf /var/lib/apt/lists/*

# ---------------------------------------------------------------- deps ------
FROM base AS deps
WORKDIR /build
COPY apps/api/pyproject.toml apps/api/README.md ./
COPY apps/api/app ./app
# --root-user-action=ignore: this is a throwaway build stage, so installing as
# root is correct here and pip's "use a virtualenv" advice does not apply. The
# flag silences the warning instead of leaving it in every build log.
RUN pip install --no-cache-dir --root-user-action=ignore .

# --------------------------------------------------------------- runtime ----
FROM base AS runtime

# Run as a fixed non-root uid 1000. Several hosts (Koyeb, Cloud Run, and
# container platforms that refuse root) either require this or behave better
# with it, so the same image deploys anywhere without a rebuild.
RUN useradd --create-home --uid 1000 alphabrief

COPY --from=deps /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=deps /usr/local/bin /usr/local/bin

WORKDIR /home/alphabrief/app
COPY --chown=alphabrief:alphabrief apps/api/pyproject.toml apps/api/README.md ./
COPY --chown=alphabrief:alphabrief apps/api/app ./app

USER alphabrief

ENV PORT=7860 \
    PYTHONPATH=/home/alphabrief/app \
    HOME=/home/alphabrief \
    MCP_TRANSPORT=stdio \
    DATABASE_URL=sqlite:////home/alphabrief/alphabrief.db

EXPOSE 7860

HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
  CMD curl -fsS "http://127.0.0.1:${PORT}/health" || exit 1

# Cloud Run injects $PORT; Spaces expects 7860. Honour whichever is set.
CMD ["sh", "-c", "exec uvicorn app.main:app --host 0.0.0.0 --port ${PORT:-7860} --workers 1 --timeout-keep-alive 75"]