# Copyright (c) 2025, NVIDIA CORPORATION.  All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Bootstrap: docker
From: python:3.13-bookworm

%labels
    Author NVIDIA NeMo-Gym
    Description GDPVal Apptainer container with all document generation dependencies

%post
    set -ex

    # System packages.  The previous version chained these with ``&&`` and let
    # ``pip install`` run on a separate line, so an apt failure (e.g. a build
    # host with no DNS, or an ARM-only Debian variant where one package isn't
    # in the default mirrors) silently skipped to the pip block — producing a
    # sif missing libreoffice/tesseract/etc. while still appearing to build.
    # ``set -ex`` aborts on the first failure, and the ``command -v`` checks
    # below fail loud if any binary we expect didn't actually install.
    export DEBIAN_FRONTEND=noninteractive
    # Under apptainer's unprivileged (fakeroot) build, apt cannot drop to its
    # _apt sandbox user ("Could not switch group"; the http method dies with
    # error 112). Disable the sandbox so apt runs as root. Harmless for a
    # privileged/root build too.
    echo 'APT::Sandbox::User "root";' > /etc/apt/apt.conf.d/99-disable-sandbox
    apt-get update
    apt-get install -y --no-install-recommends \
        git \
        build-essential \
        gcc \
        g++ \
        cmake \
        swig \
        pkg-config \
        make \
        coreutils \
        libpango1.0-dev \
        libcairo2-dev \
        libgdk-pixbuf2.0-dev \
        libreoffice-core \
        libreoffice-writer \
        libreoffice-calc \
        libreoffice-impress \
        fonts-dejavu-core \
        fonts-liberation \
        tesseract-ocr \
        pandoc \
        poppler-utils \
        ghostscript \
        ffmpeg \
        graphviz \
        imagemagick \
        chromium \
        jq \
        texlive-latex-base \
        texlive-latex-recommended \
        texlive-latex-extra \
        texlive-fonts-recommended \
        texlive-fonts-extra \
        texlive-xetex \
        texlive-luatex \
        texlive-pictures \
        texlive-science \
        texlive-plain-generic \
        texlive-pstricks \
        texlive-lang-greek \
        latexmk \
        biber \
        default-jre-headless \
        gdal-bin \
        libgdal-dev \
        proj-bin \
        libproj-dev \
        libgeos-dev \
        libgl1 \
        libglib2.0-0 \
        libsndfile1 \
        espeak-ng \
        libzbar0 \
        unzip \
        unar \
        curl \
        wget
    rm -rf /var/lib/apt/lists/*

    command -v libreoffice
    command -v tesseract
    command -v pandoc
    command -v pdftotext
    command -v gs
    command -v ffmpeg
    command -v dot
    command -v convert
    command -v pdflatex
    command -v xelatex
    command -v lualatex
    command -v latexmk
    command -v biber
    command -v java
    command -v gdalinfo
    command -v jq
    command -v unzip
    command -v chromium || command -v chromium-browser
    # Style files from the curated TeX Live set (texlive-pictures / -science /
    # -pstricks) must resolve, else figure/equation-heavy docs fail at runtime.
    kpsewhich tikz.sty
    kpsewhich siunitx.sty
    kpsewhich pst-plot.sty

    python -m pip install --no-cache-dir --upgrade pip

    # NOTE: deliberately NO PyTorch. Neither the AA prompt nor the apt/python
    # reference snapshots include torch/torchvision/torchaudio; the reference ML
    # stack is scikit-learn/xgboost/catboost/lightgbm + onnxruntime. Installing
    # torch would bloat the sif by multiple GB for nothing.

    # Python stack aligned to the GDPval AA sandbox reference (the agent's
    # advertised runtime).  Versions left unpinned so the resolver picks
    # Python 3.13-compatible wheels.  This block MUST fully succeed: a missing
    # wheel aborts the build rather than silently shipping a degraded sif.
    pip install --no-cache-dir \
        jupyterlab notebook jupyter-server \
        aiohttp hypercorn fastapi websockets pydantic gradio \
        numpy numpy-financial scipy pandas polars duckdb pyarrow xarray \
        matplotlib matplotlib-venn seaborn plotly plotnine bokeh \
        statsmodels scikit-learn scikit-image xgboost catboost lightgbm imbalanced-learn shap \
        nltk gensim spacy textblob onnxruntime \
        opencv-python Pillow pytesseract qrcode pyzbar playwright \
        ffmpeg-python pydub moviepy av soundfile librosa mutagen gtts pyttsx3 pedalboard pyloudnorm mne SpeechRecognition \
        python-docx python-pptx openpyxl xlrd xlsxwriter pymupdf pdf2image pdfplumber pypandoc docx2txt odfpy pyxlsb tabula-py camelot-py \
        mammoth markitdown magika \
        fpdf2 reportlab weasyprint pdfrw pypdf pypdfium2 pdfminer.six scour \
        graphviz pydot networkx svgwrite svglib cairosvg trimesh wordcloud \
        shapely fiona geopandas geopy rasterio contextily folium \
        sympy pymc casadi h5py tables \
        rdkit biopython ezdxf \
        markdownify anytree rarfile chardet srt youtube-transcript-api \
        tqdm tabulate faker loguru rapidfuzz einops pycountry countryinfo pronouncing exchange-calendars \
        nashpy rdflib \
        cryptography pyopenssl requests httpx \
        boto3 azure-ai-documentintelligence azure-identity \
        snowflake-connector-python databricks-sql-connector \
        pytest pytest-cov pytest-json-report coverage pytest-asyncio ddtrace datadog \
        beautifulsoup4 lxml typing-extensions

    # Architecture-specific / fragile extras that need heavy native builds or
    # whose wheels are not on every target platform. Best-effort: never fail the
    # build if a target-platform wheel is missing.
    pip install --no-cache-dir \
        cadquery cadquery-ocp aspose-words kerykeion nlopt \
        || echo "[gdpval.def] some architecture-specific extras were skipped"

    # Fail loud if the AA-advertised Python stack didn't actually install.
    python - <<'PYCHECK'
import importlib
mods = [
    "numpy", "pandas", "polars", "scipy", "matplotlib", "plotly", "sklearn",
    "docx", "pptx", "openpyxl", "fitz", "pdfplumber", "reportlab", "weasyprint",
    "PIL", "cv2", "playwright",
]
missing = []
for m in mods:
    try:
        importlib.import_module(m)
    except Exception as exc:  # noqa: BLE001
        missing.append(f"{m}: {exc}")
if missing:
    raise SystemExit("[gdpval.def] missing/broken AA python deps:\n  " + "\n  ".join(missing))
print("[gdpval.def] AA python import smoke check OK")
PYCHECK

    mkdir -p /workspace

%environment
    export HOME=/root
    export PATH=/usr/local/bin:$PATH
    export DEBIAN_FRONTEND=noninteractive

%runscript
    exec /bin/bash "$@"
