Le Document Parsing extrait le texte directement depuis les fichiers natifs (PDF avec texte embarqué, documents Office) sans passer par la reconnaissance optique de caractères. C'est plus rapide et plus précis que l'OCR pour les documents numériques.
| Critère | Document Parsing | OCR |
|---|---|---|
| Opère sur | DocumentFile (fichier natif) |
DocumentVersion (converti en image) |
| Formats | PDF natif, Word, Excel, Calc, Impress | Tous (y compris PDF scanné) |
| Qualité | Excellente (texte intact) | Variable (dépend de la qualité du scan) |
| Vitesse | Rapide (extraction directe) | Lente (rendu image + analyse) |
| Backend | pdftotext (Poppler) |
Tesseract |
| Signal déclencheur | signal_post_document_file_upload |
signal_post_document_version_remap |
| Contenu éditable | Non | Oui (correction manuelle possible) |
Règle pratique :
Classe : PopplerParser
MIME type : application/pdf
Dépendance : binaire pdftotext du paquet système poppler-utils
# Installation
apt-get install poppler-utils
# Vérification
pdftotext -v
Fonctionnement :
pdftotext -f <page> -l <page> fichier.pdf - pour chaque pageChemin du binaire :
| Plateforme | Chemin par défaut |
|---|---|
| Linux/Unix | /usr/bin/pdftotext |
| BSD/macOS | /usr/local/bin/pdftotext |
Configurable via DOCUMENT_PARSING_PDFTOTEXT_PATH.
Classe : OfficePopplerParser
MIME types : tous les formats Office (.docx, .xlsx, .pptx, .odt, .ods, .odp, .doc, .xls, .ppt, etc.)
Dépendances : LibreOffice + pdftotext
Fonctionnement :
PopplerParserUpload fichier
→ DocumentFile._introspect() (checksum, MIME, taille, pages)
→ DocumentFile.upload_complete()
→ signal_post_document_file_upload (émis)
→ handler_parse_document_file()
→ vérifie document_type.parsing_settings.auto_parsing
→ Si True : document_file.submit_for_parsing()
→ task_parse_document_file (Celery, queue "parsing")
Chaque type de document a un paramètre auto_parsing indépendant.
Via l'interface web :
Administration → Types de documents → [Type] → Actions → Paramètres de parsing
Cocher/décocher "Parsing automatique".
Via l'API REST :
# Voir le paramètre actuel
curl -H "Authorization: Token <token>" \
"https://mayan.example.com/api/v4/document_types/1/parsing/settings/"
# → {"auto_parsing": true}
# Désactiver pour un type
curl -X PATCH \
-H "Authorization: Token <token>" \
-H "Content-Type: application/json" \
-d '{"auto_parsing": false}' \
"https://mayan.example.com/api/v4/document_types/1/parsing/settings/"
Paramètre global (pour les nouveaux types) :
# config.yml
DOCUMENT_PARSING_AUTO_PARSING: true
Ce paramètre initialise auto_parsing lors de la création de chaque nouveau type de document. Les types existants conservent leur configuration.
| Action | Portée | Navigation |
|---|---|---|
| Soumettre pour parsing | Fichier unique | Document → Fichier → Actions → Soumettre pour parsing |
| Soumettre pour parsing | Plusieurs fichiers | Liste → sélection → Soumettre pour parsing |
| Soumettre pour parsing | Type de document entier | Administration → Outils → Soumettre type pour parsing |
| Voir le contenu parsé | Fichier | Document → Fichier → Contenu |
| Voir le contenu parsé | Page individuelle | Document → Fichier → Pages → [page] → Contenu |
| Télécharger le contenu | Fichier | Document → Fichier → Contenu → Télécharger |
| Supprimer le contenu | Fichier | Document → Fichier → Contenu → Supprimer |
from mayan.apps.documents.models import Document, DocumentFile
# Parser un fichier
doc_file = DocumentFile.objects.get(pk=7)
doc_file.submit_for_parsing(user=None)
# Parser le fichier actif d'un document
doc = Document.objects.get(pk=42)
doc.submit_for_parsing(user=None)
# Parser tous les documents d'un type
from mayan.apps.documents.models import DocumentType
doc_type = DocumentType.objects.get(label='Factures')
for doc in doc_type.documents.all():
doc.submit_for_parsing()
print(f"Soumis: {doc.pk}")
Il n'existe pas d'endpoint REST dédié pour déclencher le parsing. Utiliser le shell Django ou l'interface web.
Queue : parsing
Worker : worker_b (nice=2, concurrence=4)
task_parse_document_file (paramètres : document_file_pk, user_id)
DocumentFile par son PKuser_id fourni)DocumentFilePageContent.objects.process_document_file(document_file, user)La tâche est fire-and-forget (ignore_result=True). Les erreurs sont enregistrées dans le journal d'erreurs du document.
DocumentFile
└── DocumentFilePage (une par page)
└── DocumentFilePageContent (1:1, optionnel)
└── content (TextField) ← texte extrait
DocumentFilePageContent :
OneToOneField avec DocumentFilePagecontent (TextField, peut être vide)Via l'API REST :
# Contenu d'une page spécifique
curl -H "Authorization: Token <token>" \
"https://mayan.example.com/api/v4/documents/42/files/7/pages/3/content/"
# → {"content": "Le texte extrait de la page 3..."}
Via le shell Django :
from mayan.apps.documents.models import DocumentFilePage
from mayan.apps.document_parsing.models import DocumentFilePageContent
page = DocumentFilePage.objects.get(pk=15)
try:
print(page.content.content)
except DocumentFilePageContent.DoesNotExist:
print("Page non parsée")
# Tout le contenu d'un fichier
doc_file = DocumentFile.objects.get(pk=7)
for page in doc_file.pages.all():
try:
print(f"--- Page {page.page_number} ---")
print(page.content.content)
except DocumentFilePageContent.DoesNotExist:
print(f"Page {page.page_number} : non parsée")
Le texte parsé est automatiquement indexé dans le moteur de recherche.
| Contexte | Champ ORM indexé | Label |
|---|---|---|
| Documents | files__file_pages__content__content |
"Document file content" |
| Document files | file_pages__content__content |
"Content" |
| Document file pages | content__content |
"Document file page content" |
L'indexation est déclenchée automatiquement à la sauvegarde d'un DocumentFilePageContent. Une recherche plein texte dans Mayan cherche simultanément dans :
| Méthode | URL | Permission | Description |
|---|---|---|---|
GET |
/api/v4/document_types/{id}/parsing/settings/ |
document_type_parsing_setup |
Lire config parsing du type |
PATCH |
/api/v4/document_types/{id}/parsing/settings/ |
document_type_parsing_setup |
Modifier config parsing |
GET |
/api/v4/documents/{id}/files/{fid}/pages/{pid}/content/ |
document_file_content_view |
Lire le contenu parsé d'une page |
| Permission | Nom interne | Description |
|---|---|---|
permission_document_file_content_view |
content_view |
Voir le contenu parsé |
permission_document_file_parse |
parse_document |
Soumettre pour parsing / supprimer le contenu |
permission_document_type_parsing_setup |
document_type_setup |
Configurer le parsing par type |
| Événement | Quand |
|---|---|
event_parsing_document_file_submitted |
Soumission pour parsing |
event_parsing_document_file_finished |
Parsing terminé avec succès |
event_parsing_document_file_content_deleted |
Contenu parsé supprimé |
| Paramètre | Défaut | Description |
|---|---|---|
DOCUMENT_PARSING_AUTO_PARSING |
True |
Auto-parsing pour les nouveaux types de document |
DOCUMENT_PARSING_PDFTOTEXT_PATH |
/usr/bin/pdftotext |
Chemin vers le binaire pdftotext |
Variables d'environnement Docker :
MAYAN_DOCUMENT_PARSING_AUTO_PARSING=true
MAYAN_DOCUMENT_PARSING_PDFTOTEXT_PATH=/usr/bin/pdftotext
auto_parsing est activé pour le type de documentpoppler-utils est installé (pdftotext -v)parsingLe PDF est probablement scanné (image), pas un PDF natif. Utiliser l'OCR à la place.
# Tester directement
pdftotext /chemin/vers/document.pdf -
# Si la sortie est vide → pas de texte natif → OCR nécessaire
# Si la sortie contient du texte → le parsing devrait fonctionner
# Vérifier que LibreOffice est installé
libreoffice --version
# Dans Docker
MAYAN_APT_INSTALLS="libreoffice"
from mayan.apps.documents.models import DocumentType
from mayan.apps.document_parsing.models import DocumentFilePageContent
doc_type = DocumentType.objects.get(label='Factures')
for doc in doc_type.documents.all():
for doc_file in doc.files.all():
# Supprimer l'ancien contenu
DocumentFilePageContent.objects.filter(
document_file_page__document_file=doc_file
).delete()
# Relancer le parsing
doc_file.submit_for_parsing()
print(f"Soumis : {doc_file.pk}")
| Fichier | Rôle |
|---|---|
parsers.py |
PopplerParser, OfficePopplerParser, registre |
models.py |
DocumentFilePageContent, DocumentTypeSettings |
tasks.py |
Tâche Celery task_parse_document_file |
handlers.py |
Handler signal auto-parsing |
managers.py |
Logique métier du parsing |
settings.py |
Paramètres configurables |
search.py |
Intégration moteur de recherche |
permissions.py |
Permissions |
events.py |
Événements |