Files
privateGPT/Dockerfile
Javier Martinez 21d42fd97a feat: code execution v4 (#2295)
* feat: add bundle to remove

* fix: spaces

* feat: add xml render as skill spec

* feat: add skill volume root to cache

* fix: deduplicate values

* fix: change the mount path to skill_id

* fix: use different paths

* feat: add principal

(cherry picked from commit 5db64fe721d5706440ce9f342b1388ffe742bc16)

# Conflicts:
#	private_gpt/components/code_execution/base.py
#	private_gpt/components/code_execution/code_execution_component.py
#	private_gpt/components/code_execution/local.py
#	private_gpt/components/environment/manager.py
#	private_gpt/components/tools/builders/bash_tool_builder.py
#	private_gpt/components/tools/builders/text_editor_tool_builder.py
#	private_gpt/components/tools/processors/bash_processor.py

* fix: mypy

...

* fix: config

* fix: sandbox config

* feat: add forward cookies

* fix: loop

* feat: add present server

* feat: add feature flag for tools

* refactor: move principal to another better place

* feat: add api key principal

* docs: fix docs

* docs: add present server

* fix: principal

* fix: mypy

* fix: avoid to block the loop

* fix: blocks in expansion

* fix: remove maximum concurrent users

...

* fix: multiplexer

* fix: readers

* fix: more fixes

...

* fix: impl

* feat: tool scheduler

* feat: add adaptative

* feat: add chat worker

* fix: config

* fix: max

* feat: add chat/tools workers

* fix: mypy

* feat: add generic scheduler

* fix: get result

* feat: do serializable the tool executor

* fix: tools

* fix: config

* fix: config

* fix: args

* fix: config

* fix: serializer

* Revert "fix: blocks in expansion"

This reverts commit a2110f94a8.

* fix: unify all logic

* feat: add ingestion scheduler

* fix: settings

* fix: config

* feat: add arq worker to chat

* fix: arq worker

* fix: add nest

* fix: mypy

* fix: await

* fix: script stress

* fix: tokenizer

* fix: chat scheduler

* fix: mypy

* fix: add async tokenizer

* fix: improve condense

* fix: tool scheduler

* feat: add initial real async chat worker

* fix: mypy

* fix: do resumable local executor

...

...

...

fix: revert usleess changes

fix: remove parent chat job

fix: refactor

fix: loop

ref: rename models

fix: chat engine

fix: mypy

...

...

...

fix: fix deps

* fix: tests

* fix: tests

* ...

* fix: stream

* fix: config

* fix: scheduler

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Handle PGPT_WORKER_MODE=celery in health check worker status

* fix: cancel

* fix: arch

* fix: test ingestion

* fix: deserialization of chat messages

* fix: broken results

* fix: mypy

* fix: test

* fix: config

* fix: remove arq tool worker

* fix: output cls

* fix: preserve early resumable tool callbacks

* fix: preserve async tool result order

* refactor: address worker PR review comments

* fix: mypy

* test: colocate ARQ chat enqueue coverage

* fix: remove redis from tests

* fix: mypy

* fix: tests

* test: isolate chat mocks and cancellation timing

* fix: tests

* fix: tests

* fix: test

(cherry picked from commit f8ee460af2)

* fix: worker config

* test: remove flaky chat cancellation assertion

(cherry picked from commit 1115ff2349)

# Conflicts:
#	tests/server/chat/test_chat_routes.py

* fix: emit chat pings from stream listeners

* fix: don't duplciate the output

* fix: rss memory

...

* fix: pass the args

* fix: threads

* fix: websearch

---------

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-07-15 13:05:23 +02:00

222 lines
8.7 KiB
Docker

ARG EXTRAS="core"
ARG PLAYWRIGHT_VERSION="1.60.0"
FROM python:3.11.10-slim-bookworm AS base
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
ENV PATH="/usr/local/bin:${PATH}"
ENV UV_LINK_MODE=copy \
UV_CACHE_DIR=/root/.cache/uv
FROM base AS os-deps
ARG EXTRAS
RUN rm -f /etc/apt/apt.conf.d/docker-clean
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
set -eu; \
ENABLE_DOCUMENTS=0; \
ENABLE_MEDIA=0; \
ENABLE_WEB_SCRAPING=0; \
ENABLE_DATABASE=0; \
for extra in $EXTRAS; do \
case "$extra" in core|ingest|ingest-core|ingest-documents|ingest-markitdown|ingest-markup) ENABLE_DOCUMENTS=1 ;; esac; \
case "$extra" in core|media|media-core|media-image|media-audio|media-video) ENABLE_MEDIA=1 ;; esac; \
case "$extra" in core|tools|tool-web-scraping) ENABLE_WEB_SCRAPING=1 ;; esac; \
case "$extra" in core|tools|tool-database|database|database-core|database-postgres|database-mysql|database-mssql|database-db2) ENABLE_DATABASE=1 ;; esac; \
done; \
apt update; \
apt install -yqq --no-install-recommends \
curl \
ca-certificates; \
if [ "$ENABLE_DOCUMENTS" = "1" ]; then \
apt install -yqq --no-install-recommends \
libmagic1 \
libxml2 \
libxslt1.1 \
poppler-utils \
libreoffice \
pandoc \
ghostscript; \
fi; \
if [ "$ENABLE_MEDIA" = "1" ]; then \
apt install -yqq --no-install-recommends \
ffmpeg \
libavcodec-extra; \
fi; \
if [ "$ENABLE_WEB_SCRAPING" = "1" ]; then \
apt install -yqq --no-install-recommends \
libglib2.0-0 \
libnss3 \
libnspr4 \
libdbus-1-3 \
libatk1.0-0 \
libatk-bridge2.0-0 \
libatspi2.0-0 \
libcups2 \
libx11-6 \
libxcomposite1 \
libxdamage1 \
libxext6 \
libxfixes3 \
libxrandr2 \
libgbm1 \
libxcb1 \
libxkbcommon0 \
libpango-1.0-0 \
libcairo2 \
libasound2 \
libxfont2 \
x11-xkb-utils \
xserver-common; \
fi; \
if [ "$ENABLE_DATABASE" = "1" ]; then \
apt install -yqq --no-install-recommends libmariadb3; \
curl -sSL -O https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb; \
dpkg -i packages-microsoft-prod.deb; \
rm packages-microsoft-prod.deb; \
apt update; \
ACCEPT_EULA=Y apt install -yqq --no-install-recommends msodbcsql18; \
fi; \
rm -rf /var/lib/apt/lists/*
FROM base AS dependencies
WORKDIR /home/worker/app
ARG EXTRAS
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
set -eu; \
apt update; \
apt install -yqq --no-install-recommends \
build-essential \
pkg-config; \
rm -rf /var/lib/apt/lists/*
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
set -eu; \
extra_flags=""; \
for extra in $EXTRAS; do \
extra_flags="$extra_flags --extra $extra"; \
done; \
uv sync --no-dev --frozen --no-install-project $extra_flags
# remove hf_xet, it does not support custom CA which
# makes them fail in some corporate environments.
# The fallback is hf-transfer, which uses HTTPS properly (with certificate validation)
RUN uv pip uninstall hf-xet
FROM base AS build
WORKDIR /home/worker/app
COPY private_gpt/ private_gpt
COPY ui/ ui
# New download stage for caching model files
FROM base AS downloads
WORKDIR /home/worker/app
ARG EXTRAS
ARG PLAYWRIGHT_VERSION
ARG PGPT_DOWNLOAD_NLTK
ARG PGPT_DOWNLOAD_TIKTOKEN_CACHE
ARG PGPT_DOWNLOAD_TIKTOKEN_ENCODINGS
ARG PGPT_DOWNLOAD_PLAYWRIGHT
COPY pyproject.toml uv.lock ./
ENV PGPT_HOME=/home/worker/app
ENV HF_HOME=/home/worker/app/local_data
ENV PLAYWRIGHT_BROWSERS_PATH=/home/worker/app/.local-browsers
ENV TIKTOKEN_CACHE_DIR=/home/worker/app/tiktoken_cache
ENV TIKTOKEN_ENCODINGS_BASE=/home/worker/app/encodings
ENV TIKTOKEN_RS_CACHE_DIR=/home/worker/app/encodings
RUN mkdir -p models/nltk_cache .local-browsers tiktoken_cache encodings local_data
RUN --mount=type=cache,target=/root/.cache/uv \
set -eu; \
has_web_scraping=0; \
for extra in $EXTRAS; do \
if [ "$extra" = "tools" ] || [ "$extra" = "tool-web-scraping" ] || [ "$extra" = "core" ]; then \
has_web_scraping=1; \
break; \
fi; \
done; \
resolved_download_nltk="${PGPT_DOWNLOAD_NLTK:-1}"; \
resolved_download_tiktoken_cache="${PGPT_DOWNLOAD_TIKTOKEN_CACHE:-1}"; \
resolved_download_tiktoken_encodings="${PGPT_DOWNLOAD_TIKTOKEN_ENCODINGS:-1}"; \
resolved_download_playwright="${PGPT_DOWNLOAD_PLAYWRIGHT:-$has_web_scraping}"; \
requested_packages=""; \
if [ "$resolved_download_nltk" = "1" ]; then \
requested_packages="$requested_packages nltk"; \
fi; \
if [ "$resolved_download_tiktoken_cache" = "1" ] || [ "$resolved_download_tiktoken_encodings" = "1" ]; then \
requested_packages="$requested_packages tiktoken"; \
fi; \
if [ -n "$requested_packages" ]; then \
export REQUESTED_PACKAGES="$requested_packages"; \
locked_packages="$(python3 -c 'import os, sys, tomllib; requested = [pkg for pkg in os.environ.get("REQUESTED_PACKAGES", "").split() if pkg]; lock = tomllib.load(open("uv.lock", "rb")); versions = {pkg["name"]: pkg["version"] for pkg in lock.get("package", []) if pkg.get("name") in requested and "version" in pkg}; missing = [pkg for pkg in requested if pkg not in versions]; sys.exit("Missing locked version(s) in uv.lock for: " + ", ".join(missing)) if missing else print(" ".join(f"{pkg}=={versions[pkg]}" for pkg in requested))')"; \
uv pip install --system $locked_packages; \
fi; \
if [ "$resolved_download_playwright" = "1" ]; then \
uv pip install --system "playwright==$PLAYWRIGHT_VERSION"; \
fi; \
if [ "$resolved_download_nltk" = "1" ]; then \
python3 -c "import nltk, zipfile; from pathlib import Path; download_dir=Path('models/nltk_cache'); packages=('punkt_tab', 'punkt', 'averaged_perceptron_tagger_eng', 'averaged_perceptron_tagger', 'stopwords', 'wordnet'); [nltk.download(p, download_dir=str(download_dir), raise_on_error=True) for p in packages]; [(lambda path: (lambda zf: (zf.extractall(path.parent), zf.close()))(zipfile.ZipFile(path)))(path) for path in download_dir.rglob('*.zip')]"; \
fi; \
if [ "$resolved_download_tiktoken_cache" = "1" ]; then \
python3 -c "import tiktoken; tiktoken.get_encoding('cl100k_base')"; \
fi; \
if [ "$resolved_download_tiktoken_encodings" = "1" ]; then \
python3 -c "import urllib.request; from pathlib import Path; d = Path('encodings'); d.mkdir(exist_ok=True); [urllib.request.urlretrieve(f'https://openaipublic.blob.core.windows.net/encodings/{name}', d / name) for name in ('o200k_base.tiktoken', 'cl100k_base.tiktoken')]"; \
fi; \
if [ "$resolved_download_playwright" = "1" ]; then \
playwright install chromium; \
fi
FROM os-deps AS final
ENV PYTHONUNBUFFERED=1
ENV PORT=8080
EXPOSE 8080
RUN adduser worker
WORKDIR /home/worker/app
RUN mkdir -p /home/worker/app /home/worker/app/local_data /home/worker/app/models /home/worker/app/scripts /home/worker/app/ui \
&& chown -R worker /home/worker/app
# Copy virtual environment
COPY --chown=worker --from=dependencies /home/worker/app/pyproject.toml /home/worker/app/pyproject.toml
COPY --chown=worker --from=dependencies /home/worker/app/uv.lock /home/worker/app/uv.lock
COPY --chown=worker --from=dependencies /home/worker/app/.venv/ /home/worker/app/.venv/
# Copy application code
COPY --chown=worker --from=build /home/worker/app/ /home/worker/app/
# Copy downloaded model files
COPY --chown=worker --from=downloads /home/worker/app/models/nltk_cache/ models/nltk_cache/
COPY --chown=worker --from=downloads /home/worker/app/.local-browsers/ .local-browsers/
COPY --chown=worker --from=downloads /home/worker/app/tiktoken_cache/ tiktoken_cache/
COPY --chown=worker --from=downloads /home/worker/app/encodings/ encodings/
# Copy additional files
COPY --chown=worker scripts/worker_entrypoint scripts/worker_entrypoint
RUN chmod +x scripts/worker_entrypoint
COPY --chown=worker version.txt version.txt
COPY --chown=worker settings.yaml settings.yaml
RUN --mount=type=cache,target=/root/.cache/uv uv pip install --python /home/worker/app/.venv/bin/python --no-deps .
ENV PATH="/home/worker/app/.venv/bin:/usr/local/bin:${PATH}"
ENV PGPT_HOME=/home/worker/app
ENV HF_HOME=/home/worker/app/local_data
ENV PYTHONPATH="$PYTHONPATH:/private_gpt/"
ENV SETUPTOOLS_USE_DISTUTILS=stdlib
ENV PLAYWRIGHT_BROWSERS_PATH=/home/worker/app/.local-browsers
ENV TIKTOKEN_CACHE_DIR=/home/worker/app/tiktoken_cache
ENV TIKTOKEN_ENCODINGS_BASE=/home/worker/app/encodings
ENV TIKTOKEN_RS_CACHE_DIR=/home/worker/app/encodings
ENTRYPOINT ["private-gpt"]
CMD ["serve"]