Mayan EDMS intègre un moteur OCR (Optical Character Recognition) qui extrait le texte des pages de documents sous forme d'images. Ce texte est ensuite indexé dans le moteur de recherche full-text, permettant de retrouver des documents par leur contenu même lorsqu'ils sont des scans ou des images.
Mayan dispose de deux mécanismes distincts pour extraire du texte :
| Caractéristique | OCR | Document Parsing |
|---|---|---|
| Opère sur | DocumentVersion (converti en image) |
DocumentFile (format natif) |
| Formats | Tous (image, PDF scan, etc.) | PDF natif, formats Office |
| Déclencheur | signal_post_document_version_remap |
signal_post_document_file_upload |
| Stockage | DocumentVersionPageOCRContent |
DocumentFilePageContent |
| Worker Celery | worker_d (queue ocr) |
worker_b (queue parsing) |
| Backend | Tesseract | Poppler (pdftotext) |
Règle pratique :
Le seul backend fourni est Tesseract OCR :
mayan.apps.ocr.backends.tesseract.Tesseract
La classe Tesseract hérite de OCRBackendBase et appelle le binaire tesseract en sous-processus. Avant d'envoyer une page à Tesseract, le système utilise le moteur de conversion de Mayan pour transformer la page en image (via ImageMagick/Pillow).
Configurés via le paramètre OCR_BACKEND_ARGUMENTS :
| Paramètre | Type | Défaut | Description |
|---|---|---|---|
tesseract_path |
str | /usr/bin/tesseract (Linux) |
Chemin vers le binaire Tesseract |
timeout |
int | 600 |
Timeout en secondes par page |
environment |
dict | {'OMP_THREAD_LIMIT': '1'} |
Variables d'environnement pour le processus |
tesseract_arguments_extra |
dict | {} |
Arguments supplémentaires passés à Tesseract |
OMP_THREAD_LIMIT: '1'est défini par défaut pour éviter que Tesseract ne crée plusieurs threads OpenMP par page, ce qui causerait une surcharge sur les workers Celery multi-processus.
# config.yml ou variables d'environnement
OCR_BACKEND: mayan.apps.ocr.backends.tesseract.Tesseract
OCR_BACKEND_ARGUMENTS:
timeout: 300
environment:
OMP_THREAD_LIMIT: "1"
tesseract_arguments_extra:
l: fra+eng # langue prioritaire
oem: "1" # moteur LSTM uniquement
Via variables d'environnement Docker :
MAYAN_OCR_BACKEND=mayan.apps.ocr.backends.tesseract.Tesseract
MAYAN_OCR_BACKEND_ARGUMENTS="{timeout: 300, environment: {OMP_THREAD_LIMIT: '1'}}"
La langue utilisée pour l'OCR provient du champ language du document (au niveau du modèle Document). Ce champ est défini lors de la création du document ou lors de l'upload.
Valeurs courantes :
| Code | Langue |
|---|---|
fra |
Français |
eng |
Anglais |
deu |
Allemand |
spa |
Espagnol |
ara |
Arabe |
chi_sim |
Chinois simplifié |
Tesseract supporte plus de 100 langues. Les packs de langues s'installent avec
tesseract-ocr-<lang>(ex.tesseract-ocr-fra).
Tesseract supporte l'OCR multilingue en séparant les codes par + :
# Depuis tesseract CLI
tesseract image.tiff output -l fra+eng
# Depuis Mayan : modifier le champ language du document
# Exemple : "fra+eng"
# Sur le serveur / dans le conteneur Docker
tesseract --list-langs
# Sortie typique :
# List of available languages (3):
# eng
# fra
# osd
Au démarrage du backend Tesseract, Mayan exécute automatiquement tesseract --list-langs pour stocker la liste des langues disponibles. Si la langue demandée n'est pas installée, une OCRError est levée.
# Dans docker-compose.yml via MAYAN_APT_INSTALLS
environment:
MAYAN_APT_INSTALLS: "tesseract-ocr-fra tesseract-ocr-deu tesseract-ocr-ara"
Ou dans config.yml :
APT_INSTALLS:
- tesseract-ocr-fra
- tesseract-ocr-deu
L'OCR automatique est activé par type de document via le paramètre auto_ocr du modèle DocumentTypeOCRSettings.
Flux automatique :
Upload fichier
→ DocumentFile créé
→ DocumentVersion créée / remappée
→ Signal signal_post_document_version_remap
→ Handler handler_ocr_document_version()
→ Vérifie document_type.ocr_settings.auto_ocr
→ Si True : soumet task_document_version_ocr_process à Celery
Paramètre global par défaut :
# Défaut global (True = auto OCR activé pour tous les nouveaux types)
OCR_AUTO_OCR: true
Ce paramètre s'applique uniquement lors de la création d'un nouveau type de document. Il initialise la valeur de DocumentTypeOCRSettings.auto_ocr pour ce type. Les types existants conservent leur configuration individuelle.
Via l'interface web :
Via l'API REST :
# Voir le paramètre actuel
curl -H "Authorization: Token <token>" \
https://mayan.example.com/api/v4/document_types/1/ocr/settings/
# Désactiver l'auto OCR pour un type
curl -X PATCH \
-H "Authorization: Token <token>" \
-H "Content-Type: application/json" \
-d '{"auto_ocr": false}' \
https://mayan.example.com/api/v4/document_types/1/ocr/settings/
| Action | Portée | Navigation |
|---|---|---|
| Soumettre pour OCR | Document unique | Document → Actions → Soumettre pour OCR |
| Soumettre pour OCR | Type de document entier | Admin → Types de docs → Soumettre pour OCR |
| Éditer le texte OCR | Page individuelle | Document → Version → Page → Éditer texte OCR |
# Soumettre un document entier (dernière version active)
curl -X POST \
-H "Authorization: Token <token>" \
https://mayan.example.com/api/v4/documents/42/ocr/submit/
# → 202 Accepted
# Soumettre une version spécifique
curl -X POST \
-H "Authorization: Token <token>" \
https://mayan.example.com/api/v4/documents/42/versions/7/ocr/submit/
# → 202 Accepted
from mayan.apps.documents.models import Document
doc = Document.objects.get(pk=42)
doc.submit_for_ocr(user=None) # user optionnel pour les événements
# Ou via la version directement
version = doc.versions.filter(active=True).first()
version.submit_for_ocr(user=None)
L'OCR est traité de manière asynchrone via Celery. Les tâches s'exécutent dans le worker_d (priorité basse, concurrence=1 pour éviter la surcharge CPU).
task_document_version_ocr_process (document_version_id)
│
├── Crée un chord Celery :
│ ├── task_document_version_page_ocr_process (page 1)
│ ├── task_document_version_page_ocr_process (page 2)
│ └── task_document_version_page_ocr_process (page N)
│
└── Callback : task_document_version_ocr_finished
└── Tire event_ocr_document_version_finished
task_document_version_page_ocr_process (par page) :
DocumentVersionPageOCRContentTimeout total calculé :
timeout = (600s + image_generation_timeout × 2) × nombre_de_pages
Gestion des erreurs et retries :
CachePartitionFile.DoesNotExist → retry automatiqueLockError → retry automatiqueOperationalError → retry automatiqueLe worker_d traite l'OCR avec une concurrence de 1 pour les tâches intensives :
# supervisord.conf
[program:mayan-worker-d]
command=celery -A mayan worker -Q ocr,file_metadata,signatures_slow,storage_periodic
--concurrency=1 --loglevel=WARNING -n worker_d@%%h
Pour des documents volumineux, augmenter la concurrence peut accélérer le traitement si le CPU le permet, mais attention à la mémoire.
DocumentVersion
└── DocumentVersionPage (une par page)
└── DocumentVersionPageOCRContent (1:1)
└── content (TextField) ← texte extrait
DocumentVersionPageOCRContent :
DocumentVersionPagecontent (TextField, peut être vide)Via l'API REST :
# Lire le texte OCR d'une page spécifique
curl -H "Authorization: Token <token>" \
"https://mayan.example.com/api/v4/documents/42/versions/7/pages/3/ocr/"
# Réponse :
{
"content": "Le texte extrait par Tesseract...",
"document_version_page_url": "..."
}
Éditer le texte OCR (correction manuelle) :
curl -X PATCH \
-H "Authorization: Token <token>" \
-H "Content-Type: application/json" \
-d '{"content": "Texte corrigé manuellement"}' \
"https://mayan.example.com/api/v4/documents/42/versions/7/pages/3/ocr/"
Via le shell Django :
from mayan.apps.documents.models import DocumentVersionPage
page = DocumentVersionPage.objects.get(pk=15)
# Lire
if hasattr(page, 'ocr_content'):
print(page.ocr_content.content)
# Modifier
page.ocr_content.content = "Nouveau texte"
page.ocr_content.save()
Le texte extrait par OCR est automatiquement indexé dans le moteur de recherche (Elasticsearch, Whoosh, etc.).
| Contexte de recherche | Champ indexé | Label affiché |
|---|---|---|
| Documents | versions__version_pages__ocr_content__content |
"Document version OCR" |
| Document versions | version_pages__ocr_content__content |
"OCR" |
| Document version pages | ocr_content__content |
"Document version OCR" |
Le texte OCR est indexé automatiquement lorsque :
DocumentVersionPageOCRContent est sauvegardé (nouveau texte OCR)L'indexation est déclenchée via l'événement event_ocr_document_version_page_content_edited, capté par le système de recherche.
Dans la barre de recherche globale de Mayan, une requête cherche dans :
# Rechercher des documents par texte OCR
curl -H "Authorization: Token <token>" \
"https://mayan.example.com/api/v4/search/advanced/?q=facture+2024&scope=documents"
| Méthode | URL | Permission requise | Description |
|---|---|---|---|
GET |
/api/v4/document_types/{id}/ocr/settings/ |
ocr_document_type_setup |
Lire config OCR du type |
PATCH |
/api/v4/document_types/{id}/ocr/settings/ |
ocr_document_type_setup |
Modifier config OCR |
POST |
/api/v4/documents/{id}/ocr/submit/ |
ocr_document |
Soumettre pour OCR |
POST |
/api/v4/documents/{id}/versions/{vid}/ocr/submit/ |
ocr_document |
Soumettre une version |
GET |
/api/v4/documents/{id}/versions/{vid}/pages/{pid}/ocr/ |
ocr_content_view |
Lire texte OCR d'une page |
PATCH |
/api/v4/documents/{id}/versions/{vid}/pages/{pid}/ocr/ |
ocr_content_edit |
Éditer texte OCR |
PUT |
/api/v4/documents/{id}/versions/{vid}/pages/{pid}/ocr/ |
ocr_content_edit |
Remplacer texte OCR |
Namespace : ocr
| Permission | Nom interne | Description |
|---|---|---|
permission_document_version_ocr |
ocr_document |
Soumettre des documents pour OCR |
permission_document_version_ocr_content_edit |
ocr_content_edit |
Éditer le texte transcrit |
permission_document_version_ocr_content_view |
ocr_content_view |
Voir le texte transcrit |
permission_document_type_ocr_setup |
ocr_document_type_setup |
Modifier les paramètres OCR d'un type |
Rôle "Opérateur OCR" (peut soumettre et voir les résultats) :
ocr_documentocr_content_viewRôle "Correcteur OCR" (peut éditer le texte) :
ocr_content_viewocr_content_editRôle "Administrateur documentaire" :
ocr_document_type_setup (configurer les types)| Événement | Nom interne | Quand |
|---|---|---|
event_ocr_document_version_submitted |
document_version_submit |
Soumission pour OCR |
event_ocr_document_version_page_content_edited |
document_version_page_content_edited |
Texte OCR créé ou modifié |
event_ocr_document_version_finished |
document_version_finish |
Toutes les pages traitées |
event_ocr_document_version_content_deleted |
document_content_deleted |
Contenu OCR supprimé |
Les événements sont enregistrés sur les modèles Document, DocumentVersion et DocumentVersionPage. Ils sont visibles dans l'historique du document.
| Paramètre | Défaut | Description |
|---|---|---|
OCR_AUTO_OCR |
True |
Activer l'auto OCR pour les nouveaux types de document |
OCR_BACKEND |
mayan.apps.ocr.backends.tesseract.Tesseract |
Classe du backend OCR |
OCR_BACKEND_ARGUMENTS |
{'environment': {'OMP_THREAD_LIMIT': '1'}} |
Arguments passés au constructeur du backend |
Variables d'environnement Docker (préfixe MAYAN_) :
MAYAN_OCR_AUTO_OCR=true
MAYAN_OCR_BACKEND=mayan.apps.ocr.backends.tesseract.Tesseract
MAYAN_OCR_BACKEND_ARGUMENTS="{environment: {OMP_THREAD_LIMIT: '1'}, timeout: 600}"
# Via l'interface : Admin → Types de documents → [type] → Soumettre pour OCR
# Via l'API :
curl -X POST \
-H "Authorization: Token <token>" \
"https://mayan.example.com/api/v4/document_types/3/ocr/submit/"
from mayan.apps.documents.models import Document
# Tous les documents d'un type spécifique
docs = Document.objects.filter(document_type__label='Factures')
for doc in docs:
doc.submit_for_ocr(user=None)
print(f"Submitted: {doc.pk}")
from mayan.apps.ocr.models import DocumentVersionPageOCRContent
from mayan.apps.documents.models import DocumentVersion
version = DocumentVersion.objects.get(pk=7)
DocumentVersionPageOCRContent.objects.filter(
document_version_page__document_version=version
).delete()
# Voir les tâches OCR en attente
celery -A mayan inspect active -d worker_d@hostname
# Voir les tâches programmées
celery -A mayan inspect scheduled -d worker_d@hostname
auto_ocr est activé pour le type de documentocrjournalctl -u mayan-worker-dtesseract image.tiff stdout -l fraoem: 1) pour de meilleurs résultats sur les polices modernesAugmenter le timeout dans OCR_BACKEND_ARGUMENTS :
OCR_BACKEND_ARGUMENTS:
timeout: 1800 # 30 minutes par page
Ou augmenter TASK_DOCUMENT_VERSION_PAGE_OCR_TIMEOUT dans les settings de production.
# Installer la langue manquante
apt-get install tesseract-ocr-fra
# Ou via Docker (MAYAN_APT_INSTALLS)
MAYAN_APT_INSTALLS="tesseract-ocr-fra tesseract-ocr-eng"
Dans l'interface : Document → Actions → Journal d'erreurs
Via API :
curl -H "Authorization: Token <token>" \
"https://mayan.example.com/api/v4/documents/42/error_logs/"
| Fichier | Rôle |
|---|---|
mayan/apps/ocr/backends/tesseract.py |
Backend Tesseract |
mayan/apps/ocr/classes.py |
Classe de base OCRBackendBase |
mayan/apps/ocr/models.py |
DocumentTypeOCRSettings, DocumentVersionPageOCRContent |
mayan/apps/ocr/tasks.py |
Tâches Celery |
mayan/apps/ocr/handlers.py |
Handler signal auto-OCR |
mayan/apps/ocr/settings.py |
Paramètres configurables |
mayan/apps/ocr/search.py |
Intégration moteur de recherche |
mayan/apps/ocr/permissions.py |
Définition des permissions |
mayan/apps/ocr/events.py |
Définition des événements |