Spaces:
Running
Running
| FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim | |
| ARG GBABELDOCUI_REF=main | |
| ARG BABELDOC_VERSION=0.6.3 | |
| ARG PYMUPDF_MIN_VERSION=1.26.7 | |
| ENV PDF2ZH_WEB_UI=1 \ | |
| PYTHONUNBUFFERED=1 \ | |
| GRADIO_SERVER_NAME=0.0.0.0 \ | |
| GRADIO_SERVER_PORT=7860 \ | |
| BABELDOC_VERSION=${BABELDOC_VERSION} \ | |
| PYMUPDF_MIN_VERSION=${PYMUPDF_MIN_VERSION} | |
| WORKDIR /app | |
| EXPOSE 7860 | |
| RUN apt-get update && \ | |
| apt-get install --no-install-recommends -y \ | |
| ca-certificates \ | |
| curl \ | |
| build-essential \ | |
| libgl1 \ | |
| libglib2.0-0 \ | |
| libxext6 \ | |
| libsm6 \ | |
| libxrender1 && \ | |
| rm -rf /var/lib/apt/lists/* | |
| # Keep the GBabelDocUI frontend, but rebuild it from source so the BabelDOC | |
| # runtime is not trapped inside the stale eaiu/gbabeldocwebui:latest image. | |
| RUN curl -fsSL "https://github.com/eaiu/GBabelDocUI/archive/${GBABELDOCUI_REF}.tar.gz" \ | |
| -o /tmp/gbabeldocui.tar.gz && \ | |
| tar -xzf /tmp/gbabeldocui.tar.gz --strip-components=1 -C /app && \ | |
| rm /tmp/gbabeldocui.tar.gz | |
| # GBabelDocUI still declares the old BabelDOC 0.5 line. Patch only the package | |
| # constraints, then let the normal project install build the same UI entrypoints. | |
| RUN python - <<'PY' | |
| from pathlib import Path | |
| import os | |
| pyproject = Path("pyproject.toml") | |
| text = pyproject.read_text() | |
| replacements = { | |
| '"pymupdf<1.25.3"': f'"pymupdf>={os.environ["PYMUPDF_MIN_VERSION"]}"', | |
| '"babeldoc>=0.5.20,<0.6.0"': f'"babeldoc=={os.environ["BABELDOC_VERSION"]}"', | |
| } | |
| for old, new in replacements.items(): | |
| if old not in text: | |
| raise SystemExit(f"Expected dependency constraint not found: {old}") | |
| text = text.replace(old, new) | |
| pyproject.write_text(text) | |
| PY | |
| RUN uv pip install --system --no-cache --compile-bytecode . | |
| # Build-time proof: fail the Space build if the deployed kernel is not the | |
| # requested BabelDOC line or if PyMuPDF is still on the old incompatible line. | |
| RUN python - <<'PY' | |
| from importlib.metadata import version, PackageNotFoundError | |
| import os | |
| def parse_version(value: str) -> tuple[int, ...]: | |
| parts = [] | |
| for token in value.replace('-', '.').split('.'): | |
| if token.isdigit(): | |
| parts.append(int(token)) | |
| else: | |
| digits = ''.join(ch for ch in token if ch.isdigit()) | |
| if digits: | |
| parts.append(int(digits)) | |
| break | |
| return tuple(parts) | |
| required = os.environ["BABELDOC_VERSION"] | |
| actual = version("babeldoc") | |
| if actual != required: | |
| raise SystemExit(f"BabelDOC mismatch: expected {required}, got {actual}") | |
| pymupdf_actual = version("pymupdf") | |
| pymupdf_min = os.environ["PYMUPDF_MIN_VERSION"] | |
| if parse_version(pymupdf_actual) < parse_version(pymupdf_min): | |
| raise SystemExit(f"PyMuPDF too old: expected >= {pymupdf_min}, got {pymupdf_actual}") | |
| for pkg in ["pdf2zh-gbabeldocui", "babeldoc", "pymupdf", "cryptography", "onnx"]: | |
| try: | |
| print(f"{pkg}=={version(pkg)}") | |
| except PackageNotFoundError: | |
| print(f"{pkg}=not-installed") | |
| PY | |
| RUN babeldoc --version && babeldoc --warmup && pdf2zh --version | |
| CMD ["pdf2zh", "--gui"] | |