Kalli
Server

Parsing & Document Processor

Parsing & document-processor

Le parsing des documents est délégué au microservice apps/document-processor (FastAPI, Docling). Le serveur l'appelle en HTTP depuis apps/server/src/utils/document-processor-client.ts. Ce service ne stocke rien dans les tables métier : il renvoie les chunks, et c'est le serveur qui les insère.

Ingestion d'un document

processUploadedFile (admin) appelle processRegularFile (utils/regular-processing.ts) :

  1. Valide le contenu (non vide) et la taille des blocs (chunkSize > overlap).
  2. Insère une ligne dans files (type: regular, classification_status: pending).
  3. Soumet un job : POST /jobs sur document-processor, avec pipeline: "regular" et extract_tables: true. Le serveur renvoie { success: true, fileId, jobId } sans attendre le résultat.
  4. En tâche de fond, interroge GET /jobs/{jobId} toutes les 10 secondes, pendant 30 minutes au maximum.
  5. Si le job est terminé avec des chunks :
    • enregistre files.processing_metadata (format d'origine, taille, parseur, version, nombre de chunks, tables, images) ;
    • insère chaque chunk dans chunks, avec le contenu nettoyé, sa catégorie (category du parseur, sinon dynamic) et ses metadata ;
    • crée les tags et rôles absents, puis associe les tags aux chunks ;
    • passe classification_status à completed.
  6. Si le job renvoie zéro chunk ou un échec interne, le fichier est supprimé.

Les procédures getDocumentProcessorJobStatus, getDocumentProcessorJobStatusBatch et cancelDocumentProcessorJob permettent de suivre un job ou de l'annuler.

Points d'attention

  • Si le job passe en failed, waitForJob lève une erreur. Le code de repli passe alors classification_status à completed sans supprimer le fichier : un fichier sans chunks peut rester en base. À vérifier avant de compter sur ce statut.
  • Les tâches de fond ne sont pas reprises après un redémarrage du serveur : l'attente est en mémoire du processus.
  • Les paramètres chunkSize et overlap sont validés côté serveur, mais le parseur Docling les ignore : le découpage est fait par tokens (voir plus bas).

Q&A (processUploadedQA)

processQAcsv (utils/qa-processing.ts) suit le même schéma avec pipeline: "qa" et extract_qa_pairs: true. Le fichier est une ligne de files de type qa. Les paires extraites sont insérées dans qa_pair (question, réponse, catégorie reprise du parseur, sinon not categorized). Le statut du fichier est calculé selon le nombre de paires déjà catégorisées.

Microservice document-processor

Lancé par uvicorn src.main:app --port 8001 (port 8001 dans docker-compose).

Endpoints

Méthode et routeUsageRéponse
GET /healthSanté{ status: "healthy", timestamp }
POST /processParsing synchrone, utilisé hors des jobsProcessingResult (200) ; 400 base64 invalide, 413 fichier trop gros, 415 type non supporté
POST /jobsSoumission asynchrone202 avec { job_id, status: "pending" } ; 503 si la persistance des jobs n'est pas disponible
POST /jobs/batchSoumission de plusieurs fichiers202 avec la liste des jobs
GET /jobs/{job_id}Statut et résultatpending, processing, completed ou failed ; 404 si le job a expiré
DELETE /jobs/{job_id}Annulation204

Une erreur interne pendant POST /process renvoie 200 avec success: false et un champ error, et non un code 500.

Requête (ProcessingRequest)

{
  file_content: string;        // base64, data URL, ou texte brut (text/plain, text/markdown, text/csv, application/json)
  file_name: string;
  file_type: string;           // type MIME ; prioritaire sur l'extension
  chunk_size?: number;         // défaut 1000 ; ignoré pour Docling
  overlap?: number;            // défaut 0 ; déprécié
  extract_qa_pairs?: boolean;  // défaut false
  extract_tables?: boolean;    // défaut false ; le serveur l'envoie à true pour les documents
  extract_images?: boolean;    // défaut false
  pipeline?: "regular" | "qa";
  diagnostic?: boolean;        // ajoute les éléments retirés par le nettoyage
}

Réponse (ProcessingResult)

{
  success: boolean;
  chunks: Chunk[];
  qa_pairs: QAPair[];
  tables: Table[];
  images: Image[];
  metadata: Record<string, any>;
  processing_time_ms?: number;
  error?: string;
}

type Chunk = {
  rank: number;
  content: string;
  category?: string;           // catégorie posée par le parseur
  page_number?: number;
  section_title?: string;
  section_path?: string[];
  token_count?: number;
  source_type?: "text" | "table" | "picture" | "heading" | "list" | "ocr";
  has_table: boolean;
  has_image: boolean;
  metadata: Record<string, any>;
  tags: string[];              // tags issus des annotations Markdown
  roles: string[];             // rôles issus des annotations Markdown
};

Voir Rôles & tags pour la syntaxe des annotations.

Formats

Les formats sont listés dans le registre (src/registry.py) et activés par DOCLING_ENABLED_FORMATS. Ils couvrent :

  • PDF, Word, PowerPoint, Excel (y compris les formats anciens .doc, .ppt, .xls) ;
  • OpenDocument (texte, tableur, présentation) ;
  • HTML, XML, AsciiDoc, LaTeX, EPUB, VTT, EML ;
  • CSV, Markdown, texte brut ;
  • images (PNG, JPEG, TIFF, BMP, WebP), traitées par Docling avec OCR si activé ;
  • JSON, traité par un parseur dédié.

Le type MIME est prioritaire sur l'extension.

Découpage

Pour Docling, le découpage utilise HybridChunker avec une limite en tokens (DOCLING_MAX_TOKENS, 512 par défaut). Le tokenizer est DOCLING_TOKENIZER_MODEL, openai-community/gpt2 par défaut dans le code. Un repli sans tokenizer découpe par caractères (max_tokens * 4).

Quand la fusion native de Docling est désactivée, les chunks consécutifs de même section et de mêmes tags ou rôles sont refusionnés, dans la limite de tokens (_tag_aware_merge_chunks).

Configuration

Serveur

VariableRôle
DOCUMENT_PROCESSOR_URLURL du microservice (défaut dans le code : http://localhost:8001)

Microservice

VariableDéfaut dans le codeRôle
DATABASE_URLnon définiPersistance des jobs dans la table processing_jobs (créée au démarrage). Sans elle, POST /jobs renvoie 503.
MAX_FILE_SIZE_MB50Taille maximale ; au-delà, 413
DOC_PROCESSOR_WORKERS2Nombre de workers de la file
JOB_TIMEOUT_SECONDS1800Durée maximale d'un job
JOB_RESULT_TTL_HOURS24Durée de conservation d'un résultat
DOCLING_MAX_TOKENS512Taille maximale d'un chunk, en tokens
DOCLING_TOKENIZER_MODELopenai-community/gpt2Tokenizer du découpage
DOCLING_ENABLE_OCRtrueActive l'OCR
DOCLING_OCR_ENGINErapidocreasyocr, rapidocr, tesseract-cli ou tesserocr
DOCLING_OCR_LANGUAGESen,frLangues OCR (RapidOCR ne garde que la première)
DOCLING_TABLE_MODEaccuratefast ou accurate
DOCLING_LAYOUT_MODELheronheron, egret_large ou egret_xlarge
DOCLING_DEVICEautoauto, cpu ou cuda
DOCLING_ENABLE_PICTURE_DESCRIPTIONfalseDescription des images par un modèle de vision (coûteux)
DOCLING_ENABLED_FORMATSliste complèteFormats acceptés

Les enrichissements (code, formules) sont désactivés par défaut. tesseract-cli et tesserocr exigent l'installation de tesseract-ocr sur le système.

Le fichier .env.example à la racine liste ces variables avec des valeurs d'exemple. Certaines valeurs d'exemple diffèrent des défauts du code : par exemple DOCLING_TOKENIZER_MODEL.