Aller au contenu principal

Docling - Convertir PDF, Word, PowerPoint, Excel et HTML en Markdown, accéléré par GPU

Une image Docker batteries-included pour Docling, la bibliothèque de conversion de documents d'IBM : PDF, Word, PowerPoint, Excel et HTML transformés en Markdown propre, avec accélération GPU pour les machines qui ont de la VRAM en rab. Un complément à mon article Markitdown — même idée, un moteur plus lourd en dessous.

· 17 minutes de lecture
Voir la source
Christophe
Amoureux de Markdown, WSL et Docker ~ Curieux insatiable.
Claude Code
Assistant IA
Cet article existe aussi en anglais — lire la version originale.

Traduction automatique

Cette traduction a été produite par une IA. Elle peut contenir des contresens ou des maladresses, en particulier sur les termes techniques. En cas de doute, consultez l'article de référence en anglais — c'est lui qui fait foi.

Journal des modifications

Dernière
docling-convert is now a shell function for zsh and bash (~/.zsh/fns or ~/.bash/fns); the Dockerfile and the conversion script live in ~/tools/docling.

Docling - Convertir PDF, Word, PowerPoint, Excel et HTML en Markdown, accéléré par GPU

⚡
TL;DR

Cet article fait pour Docling exactement ce que mon article sur Markitdown faisait pour Markitdown : une image Docker batteries-included et une fonction shell docling-convert pour zsh ou bash, afin que convertir un document en Markdown propre tienne en une commande depuis n'importe quel dossier. La différence est sous le capot — Docling utilise des modèles dédiés de layout, de structure de tableaux et d'OCR plutôt que des parsers spécifiques à chaque format, tourne sur GPU si vous en avez un, et est conçu dès le départ exactement pour le scénario « document sensible, qui doit rester en local » auquel ce blog revient sans cesse.

Un ami qui lisait mon article sur Markitdown m'a suggéré d'essayer Docling à la place — projet open source, du côté d'IBM cette fois, même promesse « convertir des documents bureautiques en Markdown », mais construit autour de vrais modèles de compréhension de mise en page plutôt que de parsers par format. J'ai 24 Go de VRAM qui dorment sur mon serveur IA ; si un outil peut les mettre au travail pour transformer un PDF mal scanné en quelque chose de lisible, ça vaut dix minutes de test.

Convertir cinq formats​

Une fois l'image et la fonction docling-convert en place (on voit ça plus bas), convertir un document tient en une commande :

>user@machine: ~/yourproject

PDF, DOCX, PPTX, XLSX et HTML, cinq appels distincts à docling-convert, cinq fichiers .md propres posés à côté de leurs originaux — pas d'export-vers-Markdown manuel dans Word ou PowerPoint, pas de convertisseur en ligne à qui confier le contenu.

Ce que Docling fait différemment​

Même sortie, un moteur très différent

Pour tous les formats de cet article sauf le PDF — .docx, .xlsx, .pptx et .html — Docling fait ce que fait tout autre convertisseur : il lit le fichier avec une bibliothèque Python dédiée au format et parcourt le résultat. Rien d'exotique, aucun modèle chargé, et rien qui nécessite un GPU — --pipeline vlm est simplement ignoré sur ces quatre-là.

C'est sur le chemin PDF que ça diverge. Un PDF n'a aucune structure à parcourir : c'est un sac de glyphes à des coordonnées, et chaque convertisseur doit deviner où se trouvaient les paragraphes, les titres et les tableaux. Docling le déduit avec des modèles — un pour la mise en page, un pour la structure des tableaux, un pour l'OCR, et en option un modèle vision-langage qui lit la page rendue comme le ferait un humain. C'est ce dernier qui justifie la présence d'un GPU dans cet article.

Comme toujours, je vais d'abord construire une image Docker — pas de Python, pas de pip, rien d'installé globalement sur ma machine.

Installation​

Créer notre image Docker​

Deux fichiers obtiennent un emplacement permanent, ~/tools/docling, pour que l'image puisse être reconstruite à tout moment (nouvelle machine, docker image prune, nouvelle version de Docling) : le Dockerfile, et docling-convert.sh, le script qui pilote une conversion (détaillé plus bas) :

📦 Mise en place du projet : ~/tools/docling
Aide

Besoin d'aide ? Cliquez sur le bouton « Aide » ci-dessus pour les instructions de mise en place.

ARG DOCLING_VERSION fige la release exacte au lieu de laisser pip attraper la plus récente au moment du build — Docling sort une nouvelle version tous les quelques jours, et un build non figé donne une image différente à chaque reconstruction. Montez cet ARG quand vous voulez réellement la plus récente.

Un nom de package, toute une liste de courses derrière

Depuis le printemps 2026, docling sur PyPI est un metapackage léger : l'installer tire docling-slim[standard], et c'est ça qui amène les backends PDF, DOCX, PPTX, XLSX et HTML, PyTorch et les modèles de layout. Donc un simple pip install docling couvre toujours les cinq formats dont parle cet article, sans extras à retenir — mais c'est aussi pour ça que l'image est lourde. Si vous ne convertissez jamais que du .docx, par exemple, pip install "docling-slim[cli,format-docx,models-local]" vous donne une image beaucoup plus petite ; la liste complète des extras est sur la page PyPI du projet.

Construire l'image​

Pas de compose.yaml ici : les conversions passent par une fonction shell qui monte le répertoire dans lequel vous vous trouvez, ce qu'un fichier Compose posé dans un dossier fixe ne peut pas faire. Un simple build suffit donc :

>user@machine: ~/yourproject

Attendez-vous à ce que celui-ci soit nettement plus long que celui de Markitdown : PyTorch, ses bibliothèques CUDA embarquées et les quatre modèles intégrés montent à une image de 8,3 Go ici. Ces modèles sont la partie qui mérite l'attention — ils sont téléchargés une seule fois, au build, et ils vivent dans l'image, donc un container --rm démarre avec tout ce qu'il lui faut et ne télécharge rien.

Optionnellement, si vous voulez vérifier que l'image est correcte, lancez simplement docker run --rm docling --help — la documentation couvre chaque flag listé.

Rendre docling-convert disponible partout​

Même principe que md-convert, adapté à la forme réelle de la CLI de Docling. Le vrai travail est fait par ~/tools/docling/docling-convert.sh, le script que vous venez de créer à côté du Dockerfile :

#!/usr/bin/env bash
# Converts documents to Markdown using the isolated docling Docker image, with
# GPU acceleration when the NVIDIA container runtime is available. Unlike
# md-convert, docling writes "<basename>.md" directly into the current directory
# rather than to stdout — the source format is auto-detected from the extension.
#
# The image already carries its layout, table, OCR and VLM models, so there is
# nothing to download here and nothing to persist between runs.
#
# --pipeline vlm is the slow, accurate path: it reads the page the way a human
# would instead of stitching text fragments, which is what keeps paragraphs and
# titles intact. Pass "--pipeline standard" as an extra argument for the fast
# one. --pdf-backend only applies to the standard pipeline, where the default
# ("threaded_docling_parse") drops the last line of every paragraph; pypdfium2
# rebuilds the text correctly and gives the cleanest spacing of the backends.
#
# --image-export-mode referenced overrides docling's own default ("embedded"),
# which inlines every picture as a base64 data: URI and bloats the Markdown.
# "referenced" writes them as PNG files in "<basename>_artifacts/" instead, and
# the links stay relative because of "--output ." below.
set -euo pipefail
if [[ $# -eq 0 ]]; then
echo "Usage: docling-convert <file> [extra docling options]" >&2
exit 1
fi
# True when "$1" is already among the extra options, either bare or as "--opt=value".
has_arg() {
local needle="$1" arg
shift
for arg in "$@"; do
[[ "${arg}" == "${needle}" || "${arg}" == "${needle}="* ]] && return 0
done
return 1
}
# Printed under the result of every PDF conversion, because the moment you want
# the flag list is the moment you have just read a disappointing file and are
# about to run the command again. Options already on the command line drop off
# the list, so a second attempt never suggests what it is already doing. PDFs
# only: on the other four formats none of these flags changes anything.
print_tip() {
[[ "${DOCLING_CONVERT_NO_TIP:-}" == "1" ]] && return 0
[[ "${1,,}" == *.pdf ]] || return 0
local -a tips=()
has_arg --pipeline "${@:2}" || tips+=("--pipeline standard (faster, rougher on titles)")
has_arg --image-export-mode "${@:2}" || tips+=("--image-export-mode placeholder|embedded (drop the images, or inline them)")
has_arg -v "${@:2}" || tips+=("-v (the full log)")
((${#tips[@]} == 0)) && return 0
local joined
joined="$(printf '%s, ' "${tips[@]}")"
echo "💡 Not happy with the result? Run it again with ${joined%, }." >&2
echo "💡 Hide this hint with DOCLING_CONVERT_NO_TIP=1." >&2
}
# Without the NVIDIA container runtime, "docker run --gpus all" fails outright;
# skip the flag and let "--device auto" settle on the CPU instead.
gpu_args=()
if docker info --format '{{json .Runtimes}}' 2>/dev/null | grep -q '"nvidia"'; then
gpu_args+=(--gpus all)
else
echo "docling-convert: no NVIDIA container runtime detected, converting on CPU" >&2
fi
# Triton compiles a shared library on first use and then has to load it, which a
# noexec filesystem forbids. Rather than loosen /tmp, give it 256 MB of its own
# that allows execution — and nothing else.
#
# That tmpfs doubles as HOME. The container runs under the caller's UID, which
# has no entry in /etc/passwd, so HOME would otherwise be empty: PyTorch then
# resolves its kernel cache to "//.cache/torch/kernels", fails to create it, and
# recompiles its CUDA kernels on every single run.
#
# --quiet drops the two dozen INFO lines Docling logs per run, leaving warnings
# and errors. It is not a dead end: Docling ignores --quiet as soon as -v is
# given, so "docling-convert file.pdf -v" still brings the whole log back.
#
# The awk filter handles what --quiet cannot. In 2.127.0, VlmConvertModel.__del__
# logs through a module global that Python has already torn down by the time it
# runs, so every VLM conversion ends on an "Exception ignored in" traceback —
# after the Markdown has been written, and with the exit code still 0. It is
# noise, not a failure. The rule below drops that one block, keyed on its exact
# first line, and passes everything else through. Delete it when upstream fixes
# __del__; it is pinned to a version for exactly that reason.
start=${SECONDS}
set +e
docker run --rm \
"${gpu_args[@]}" \
-v "${PWD}:/workspace:cached" \
--read-only \
--tmpfs /tmp:size=512m,noexec,nosuid \
--tmpfs /run:size=16m \
--tmpfs /cache:size=256m,exec,nosuid \
-e HOME=/cache \
-e TRITON_CACHE_DIR=/cache/triton \
--cap-drop ALL \
--security-opt no-new-privileges:true \
-u "$(id -u):$(id -g)" \
docling convert "$1" \
--to md \
--device auto \
--pipeline vlm \
--pdf-backend pypdfium2 \
--image-export-mode referenced \
--output . \
--quiet \
"${@:2}" 2>&1 | awk '
/^Exception ignored in: <function VlmConvertModel\.__del__/ { skip = 1; n = 0; next }
skip { n++; if (/^AttributeError: / || n >= 8) skip = 0; next }
{ print }
' >&2
status=${PIPESTATUS[0]}
set -e
# In referenced mode docling creates "<basename>_artifacts/" for every run, even
# for a document without a single picture in it. rmdir only succeeds on an empty
# directory, so this clears the stray folders and can never touch one that holds
# actual images.
artifacts="$(basename "${1%.*}")_artifacts"
if [[ -d "${artifacts}" ]]; then
rmdir "${artifacts}" 2>/dev/null || true
fi
# Docling no longer announces what it produced, so the wrapper does — one line,
# with the elapsed time, because the whole point of the pipeline choice above is
# the trade it makes against the clock.
if [[ ${status} -eq 0 ]]; then
echo "docling-convert: $(basename "${1%.*}").md written in $((SECONDS - start))s" >&2
fi
print_tip "$@"
exit "${status}"

Ce script encapsule l'outil docling dans un conteneur Docker isolé pour convertir des documents en Markdown, en activant l'accélération GPU si disponible et en nettoyant les artefacts inutiles après la conversion. Il gère les options de conversion de manière intelligente, affiche des conseils contextuels pour améliorer les résultats, et filtre les messages de log parasites spécifiques à la version.

Il reste un script bash volontairement : votre shell ne charge qu'une courte fonction qui vérifie que le script et l'image sont là, puis lance le script avec bash, que votre propre shell soit zsh ou bash :

# docling-convert: convert a document of the current folder to Markdown with
# the docling Docker image. Works in zsh and bash: save it as
# ~/.zsh/fns/docling-convert.zsh or ~/.bash/fns/docling-convert.sh.
#
# docling-convert report.pdf -> report.md, next to report.pdf
#
# The real work (GPU probe, docling options, log filtering) is done by
# ~/tools/docling/docling-convert.sh, a bash script kept next to the
# Dockerfile; this function only checks that everything is in place.
docling-convert() {
local image="docling"
local build_dir="${HOME}/tools/docling"
# Shown as is in the messages, so the command can be copied for any user.
# shellcheck disable=SC2016
local build_dir_shown='${HOME}/tools/docling'
local script="${build_dir}/docling-convert.sh"
local script_shown="${build_dir_shown}/docling-convert.sh"
if ! command -v docker >/dev/null 2>&1; then
printf '\e[31mError: docker is not installed or not in your PATH.\e[0m\n' >&2
return 1
fi
if [[ ! -f "${script}" ]] || ! docker image inspect "${image}" >/dev/null 2>&1; then
if [[ ! -f "${script}" ]]; then
printf '\e[31mError: %s does not exist.\e[0m\n\n' "${script_shown}" >&2
else
printf '\e[31mError: the Docker image "%s" does not exist on this machine.\e[0m\n\n' "${image}" >&2
fi
printf 'How to continue:\n' >&2
if [[ -f "${build_dir}/Dockerfile" && -f "${script}" ]]; then
printf ' 1. docker build -t %s "%s"\n' "${image}" "${build_dir_shown}" >&2
printf ' 2. Run your docling-convert command again.\n' >&2
else
printf ' 1. Get the Dockerfile and docling-convert.sh from\n' >&2
printf ' https://www.avonture.be/blog/docling and save them in %s\n' "${build_dir_shown}" >&2
printf ' 2. docker build -t %s "%s"\n' "${image}" "${build_dir_shown}" >&2
printf ' 3. Run your docling-convert command again.\n' >&2
fi
return 1
fi
bash "${script}" "$@"
}

Cette fonction bash enveloppe l'outil docling en vérifiant d'abord que Docker est installé et que l'image Docker docling ainsi que le script de conversion existent sur la machine. Si tout est en place, elle exécute le vrai script de conversion; sinon, elle affiche les étapes pour configurer l'environnement.

1. Créez le fichier dans ~/.zsh/fns/ :

📦 Mise en place du projet : ~/.zsh/fns
Aide

Besoin d'aide ? Cliquez sur le bouton « Aide » ci-dessus pour les instructions de mise en place.

2. Chargez le dossier depuis ~/.zshrc. Déjà fait si vous avez suivi un de mes articles « Ollama au quotidien ». Sinon, ajoutez à la fin de ~/.zshrc :

~/.zshrc
for fn_file in ~/.zsh/fns/*.zsh; do
source "$fn_file"
done

3. Ouvrez un nouveau terminal (ou lancez exec zsh).

Vérifiez que le shell connaît la fonction : type docling-convert doit répondre docling-convert is a shell function.

Si l'image ou le script manque, docling-convert affiche la commande docker build exacte à lancer, ou renvoie vers cet article quand ~/tools/docling a disparu aussi.

Vous venez de la version précédente de cet article ?

Elle installait docling-convert comme script dans /usr/local/bin/. Supprimez-le (sudo rm /usr/local/bin/docling-convert) : la fonction prend le relais, et l'ancien script traînerait sinon sur votre disque.

Pourquoi un wrapper ?

Le script interroge docker info pour détecter le runtime NVIDIA avant d'ajouter --gpus all. Cette vérification n'est pas décorative : docker run --gpus all ne se dégrade pas poliment sur une machine sans le toolkit, il refuse carrément de démarrer le container. Avec la sonde en place, le même script fonctionne sur mon serveur GPU et sur mon portable — plus lentement sur le portable, c'est tout, et rien à configurer dans les deux cas. Mettre ce runtime en place est optionnel et arrive à la fin de cet article.

Laissé tranquille, Docling raconte chaque exécution — choix du moteur, chargement des modèles, comptage des tokens, une vingtaine de lignes INFO pour convertir une seule page — d'où le --quiet passé par le wrapper. Ce n'est pas une impasse : Docling ignore --quiet dès que -v est présent, donc docling-convert report.pdf -v ramène tout le log le jour où quelque chose tourne mal. Les deux variables TRANSFORMERS_* et HF_HUB_* du Dockerfile finissent le travail, en faisant taire la couche de modèles en dessous, qui a ses propres opinions sur les barres de progression.

Première conversion​

Il est temps de vérifier que toute la chaîne tient. Les cinq fichiers utilisés tout au long de cet article sont ici — un document, un court bon de livraison, exprimé de cinq façons, pour que vous voyiez ce que chaque format coûte sur le chemin du Markdown plutôt que de comparer cinq choses sans rapport :

samples.zip — les cinq fichiers

Vous préférez rester dans le terminal ? L'archive est à une URL fixe, donc curl la récupère directement dans un dossier temporaire, /tmp/docling, dézippée dans un sous-dossier samples :

>La première vraie conversion

report.md atterrit à côté de report.pdf, titre et paragraphes intacts — pas de dossier de sortie à nommer, pas de redirection à retenir.

Deux choses méritent attention ici. La première, c'est que docling-convert report.pdf a pris quatorze secondes. La seconde, c'est la liste de flags affichée sous le résultat : elle apparaît sous chaque conversion PDF, les options que vous avez déjà passées en disparaissent, les quatre autres formats n'ont droit à aucune suggestion, et DOCLING_CONVERT_NO_TIP=1 la coupe définitivement.

Reste la question évidente : qu'est-ce qu'on achète avec ces quatorze secondes ?

Pourquoi le pipeline lent est celui par défaut​

Docling peut lire un PDF de deux manières. Le pipeline standard détecte les régions, en extrait le texte, puis réassemble le tout. Le pipeline vlm confie la page rendue à un petit modèle vision-langage — GraniteDocling, 258M de paramètres — et lui demande d'en décrire la structure, comme le ferait une personne qui lit la page. C'est celui qu'utilise le wrapper, et voici report.pdf — quatre paragraphes justifiés sous un titre en police display — passé par les deux :

>Standard pipeline vs VLM, same file
$ export DOCLING_CONVERT_NO_TIP=1

$ docling-convert report.pdf --pipeline standard
docling-convert: report.md written in 8s

$ cat report.md

## Quarterly Delivery Note d titiitl iltil

y y
Scope, milestones and termination — internal circulation only
Following the quarterly review held on 3 September, this note records the agreed
scope, [...] the payment schedule set out in section three,
which is intended to replace it entirely.
The supplier shall deliver the first increment within six weeks of signature, [...]

$ docling-convert report.pdf
docling-convert: report.md written in 14s

$ cat report.md

## Quarterly Delivery Note

Scope, milestones and termination - internal circulation only
Following the quarterly review held on 3 September, this note records the agreed
scope, [...] the payment schedule set out in section three, which is intended to
replace it entirely.
The supplier shall deliver the first increment within six weeks of signature, [...]

Regardez la première ligne du pipeline standard. Quarterly Delivery Note d titiitl iltil, suivi d'un yy égaré — l'étape OCR s'est déclenchée sur le grand titre et a halluciné des lettres qui n'existent dans aucune version de ce document. Puis elle a coupé la première proposition en deux, laissant which is intended to replace it entirely. seule sur sa ligne. Le VLM n'a produit ni le texte inventé ni l'orpheline. Quatorze secondes contre huit, c'est le prix, et ça achète un fichier que vous pouvez transmettre à quelqu'un sans l'avoir relu.

Le chemin rapide n'échoue pas bruyamment : il invente, et le texte inventé ne se détecte qu'en relisant la sortie.

Une vraie différence avec md-convert

Markitdown écrit le Markdown sur stdout, donc md-convert file.docx > file.md est la façon de le capturer. La CLI de Docling écrit au contraire <basename>.md directement dans le répertoire de sortie — il n'y a pas de mode stdout. docling-convert file.docx produit file.md juste à côté ; aucune redirection > n'est nécessaire, et aucune ne fonctionnera.

Un mot sur les images​

Docling rend tout ce que le modèle de layout classe comme image — et sur un titre composé dans une police display, ça peut être le titre lui-même. Laissé tranquille, il intègre ensuite chacune d'elles dans le Markdown sous forme d'URI data: en base64, ce qui garde le fichier autonome et le gonfle énormément. Le wrapper passe --image-export-mode referenced à la place : les images atterrissent en vrais fichiers PNG dans un dossier budget_artifacts/ à côté de budget.md, liées en relatif, pour que les deux voyagent ensemble.

Les deux autres modes sont à un flag de distance. --image-export-mode placeholder supprime les images et laisse un marqueur <!-- image --> à la place de chacune — le bon choix quand le Markdown va alimenter un modèle plutôt qu'une personne. --image-export-mode embedded ramène le base64, quand vous voulez un document unique et autonome. Une chose à savoir si vous appelez un jour Docling sans le wrapper : ces liens sont relatifs grâce à --output ., et un --output absolu écrit les chemins internes au container, qui ne résolvent vers rien à l'extérieur.

Optionnel — Mettre un GPU derrière le pipeline PDF​

Tout ce qui précède fonctionne sans GPU, et cette section est sautable — deux fois plutôt qu'une :

  • Vous ne convertissez que du .docx, .xlsx, .pptx ou .html ? Alors ça ne vous apporte strictement rien. Ces quatre formats ne chargent jamais de modèle, il n'y a donc rien à accélérer ; --gpus ne change ni la vitesse ni la sortie.
  • Vous convertissez des PDF sur une machine sans carte NVIDIA ? Alors ça fonctionne quand même. --device auto se rabat sur le CPU, le même pipeline VLM tourne, et le même Markdown en sort — c'est juste plus long. Le wrapper affiche le temps écoulé à chaque exécution, votre propre matériel vous dira donc de combien.

Recommandé pour les PDF, inutile pour les quatre autres, obligatoire pour personne.

Pourquoi un toolkit est nécessaire​

Un container ne voit pas votre carte graphique. La carte, sa VRAM et le driver NVIDIA vivent sur l'host ; un container n'obtient ni /dev/nvidia* dans sa liste de périphériques, ni les bibliothèques du driver dans son système de fichiers. Les bibliothèques CUDA que pip a installées dans notre image — la wheel torch embarque les siennes, raison pour laquelle le Dockerfile part d'un simple python:3.12-slim-trixie et non d'une base nvidia/cuda — ne sont que la moitié supérieure de cette pile : elles parlent au driver, elles ne le remplacent pas. La moitié inférieure manquant, PyTorch ne signale aucun périphérique CUDA et calcule sur le CPU.

Le NVIDIA Container Toolkit est la pièce qui réunit les deux moitiés : il enregistre un hook dans le daemon Docker qui, à chaque démarrage de container avec --gpus, y injecte les nœuds de périphériques GPU et les bibliothèques du driver de l'host. C'est toute la raison de sa présence dans cet article — pas de toolkit, pas de VRAM. Installez-le sur l'host Docker, jamais dans l'image, puis confirmez que le GPU est visible depuis l'intérieur d'un container :

>Verifying GPU passthrough

Ce tableau, c'est la carte de l'host lue depuis l'intérieur d'un container : 24 Go de VRAM, version du driver, ce qui l'utilise actuellement. L'image nvidia/cuda n'est là que comme véhicule pratique pour nvidia-smi — notre propre image n'en a pas besoin.

Si ce tableau n'apparaît pas​

Rien n'est cassé : docling-convert continue de convertir, sur le CPU, exactement comme il l'a fait tout au long de l'article. Si vous voulez vraiment le GPU, trois pannes couvrent quasiment tous les cas :

Ce que vous obtenez à la placeCe que ça veut direQuoi faire
could not select device driver "" with capabilities: [[gpu]]Docker n'a pas de hook GPU : le toolkit n'est pas installé, ou bien installé mais jamais branché au daemonInstallez le toolkit depuis le dépôt de packages NVIDIA, puis lancez les deux commandes ci-dessous
nvidia-smi échoue sur l'host aussi, en dehors de tout containerLe driver lui-même manque ou est cassé — Docker n'est pas encore en jeuInstallez le driver et redémarrez jusqu'à ce que nvidia-smi fonctionne sur l'host. Sous WSL2, ce driver est un driver Windows : installez-le sur Windows, jamais dans la distribution
Failed to initialize NVML: Unknown ErrorLe hook s'est exécuté, mais le périphérique a été refusé au container — un daemon qui tourne encore avec sa configuration d'avant le toolkitLes deux commandes ci-dessous

Deux de ces trois cas ont le même correctif, parce que le package ne fait que poser le hook sur le disque — il faut encore en informer le daemon :

>Wiring the toolkit into Docker
$ sudo nvidia-ctk runtime configure --runtime=docker
$ sudo systemctl restart docker

$ docker info --format '{{json .Runtimes}}'
{"io.containerd.runc.v2":{"path":"runc"},"nvidia":{"path":"nvidia-container-runtime"},"runc":{"path":"runc"}}

Cette dernière commande est exactement la sonde que le script wrapper exécute avant d'ajouter --gpus all : dès que nvidia apparaît parmi les runtimes de Docker, le prochain PDF passe par le GPU sans rien d'autre à changer.

Ce que coûtent les cinq fichiers​

Chaque chiffre de cet article a été mesuré sur les fichiers que vous avez dézippés plus haut, et les cinq commandes du tout premier terminal tournent dessus telles quelles. Sur ma machine, les quatre formats bureautiques tiennent en quatre à cinq secondes chacun, presque entièrement du démarrage de processus, et report.pdf prend quatorze secondes avec le GPU en jeu. Cet écart résume tout : seul le PDF a besoin des modèles.

Ce que montre réellement le tableur

Les cellules fusionnées ne sont pas réduites, elles sont répétées : le titre ressort une fois par colonne qu'il couvrait, et chaque ligne de section aussi. Rien n'est perdu, mais n'attendez pas du Markdown qu'il reproduise la fusion visuelle. Et Docling lit les formules, pas leurs résultats — un tableur écrit par un script et jamais ouvert dans Excel se convertit avec tous les totaux vides. C'est pour cette raison que budget.xlsx stocke les valeurs calculées.

À retenir​

docling-convert en bref

  • Le GPU est optionnel — --device auto retombe proprement sur le CPU si le passthrough n'est pas configuré
  • Un package, cinq formats — pip install docling tire docling-slim[standard], qui couvre PDF, DOCX, PPTX, XLSX et HTML
  • Les modèles sont intégrés — téléchargés au build, donc un container non privilégié en lecture seule n'a jamais rien à récupérer
  • Écrit des fichiers, pas sur stdout — docling-convert file.pdf produit file.md directement, pas de redirection >
  • Lent volontairement — --pipeline vlm garde paragraphes et titres intacts ; ajoutez --pipeline standard quand la vitesse compte plus
  • Seuls les PDF ont besoin des modèles — .docx/.xlsx/.pptx/.html passent par un simple parser, sans GPU ni modèle

Conclusion​

Entre celui-ci et Markitdown, j'ai maintenant deux images Docker qui transforment des documents bureautiques en Markdown sans qu'un seul octet ne quitte ma machine — une légère que j'utilise par réflexe, et celle-ci, plus lourde, pour quand la structure d'un PDF mérite qu'on y passe vingt secondes et un GPU. Et comme les deux produisent du Markdown brut, l'une comme l'autre s'intègre directement dans le genre de pipeline que je décrivais dans Discutez avec vos documents grâce à AnythingLLM — ou dans le prochain article de la série « Ollama au quotidien », où ce Markdown devient l'entrée d'un pipeline local de traduction et de résumé pour des documents qui n'ont jamais eu vocation à toucher le cloud.


Cet article vous a-t-il été utile ?
Avez-vous suivi les étapes de cet article ?