From 19713f22d68ab96db5982e9dc0bf625d92f4c938 Mon Sep 17 00:00:00 2001 From: David Blanc Brioir Date: Tue, 30 Dec 2025 22:34:28 +0100 Subject: [PATCH] =?UTF-8?q?Fix:=20Pipeline=20Word=20+=20UI=20simplifi?= =?UTF-8?q?=C3=A9e=20pour=20upload?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Corrections word_pipeline.py: - Gestion robuste des erreurs LLM (fallback vers métadonnées Word) - Correction: s["section_type"] -> s.get("type") pour classification - Correction: "section_type" -> "type" dans fallback (use_llm=False) - Ajout try/except pour extract_metadata avec fallback automatique - Métadonnées Word utilisées si LLM échoue ou retourne None Refonte upload.html (interface simplifiée): - UI claire avec 2 options principales (LLM + Weaviate) - Options PDF masquées automatiquement pour Word/Markdown - Encart vert "Fichier Word détecté" s'affiche automatiquement - Encart orange "Fichier Markdown détecté" ajouté - Options avancées repliables (
) - Pipeline adaptatif selon le type de fichier - Support .md ajouté (oublié dans version précédente) Problème résolu: ❌ AVANT: Trop d'options partout, confus pour l'utilisateur ✅ APRÈS: Interface simple, 2 cases à cocher, reste pré-configuré Usage recommandé: 1. Sélectionner fichier (.pdf, .docx, .md) 2. Les options s'adaptent automatiquement 3. Cliquer sur "🚀 Analyser le document" 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- generations/library_rag/templates/upload.html | 332 +++++++++++------- .../library_rag/utils/word_pipeline.py | 57 ++- 2 files changed, 243 insertions(+), 146 deletions(-) diff --git a/generations/library_rag/templates/upload.html b/generations/library_rag/templates/upload.html index 87d87b8..665696e 100644 --- a/generations/library_rag/templates/upload.html +++ b/generations/library_rag/templates/upload.html @@ -5,7 +5,7 @@ {% block content %}

📄 Parser PDF/Word/Markdown

-

Uploadez un fichier PDF, Word (.docx) ou Markdown pour l'analyser et structurer son contenu

+

Uploadez un document pour l'analyser et l'indexer dans Weaviate

{% if error %}
@@ -15,8 +15,9 @@
-
@@ -148,39 +156,99 @@
+

📋 Pipeline de traitement

-

PDF:

-

1. OCR Mistral — Extraction du texte et des images via l'API Mistral

-

2. Markdown — Construction du document Markdown avec images

-

3. Hiérarchie — Analyse des titres pour créer une structure arborescente

-

4. LLM (optionnel) — Amélioration de la structure via Ollama/Mistral

+
+

PDF:

+

1. OCR Mistral — Extraction du texte et des images

+

2. Markdown — Construction du document structuré

+

3. LLM — Extraction métadonnées, TOC, classification

+

4. Chunking — Découpage sémantique intelligent

+

5. Weaviate — Vectorisation et indexation

+
-

Word (.docx):

-

1. Extraction Word — Lecture directe du contenu (pas d'OCR)

-

2. Markdown — Construction du document Markdown à partir des paragraphes

-

3. TOC — Extraction de la hiérarchie depuis les styles Heading 1-9

-

4. LLM — Structuration sémantique et enrichissement

-
-
+ -
-

📁 Fichiers générés

-
-
    -
  • document.md Texte Markdown OCR
  • -
  • document_chunks.json Chunks hiérarchiques
  • -
  • document_structured.json Structure LLM
  • -
  • document_ocr.json Réponse OCR brute
  • -
  • images/ Images extraites
  • -
+
- Voir les documents traités + 📚 Voir les documents traités
-{% endblock %} + +{% endblock %} diff --git a/generations/library_rag/utils/word_pipeline.py b/generations/library_rag/utils/word_pipeline.py index 9beba61..e8e1956 100644 --- a/generations/library_rag/utils/word_pipeline.py +++ b/generations/library_rag/utils/word_pipeline.py @@ -249,18 +249,46 @@ def process_word( callback("Metadata Extraction", "running", "Extracting metadata with LLM...") - metadata = extract_metadata( - markdown_text, - provider=llm_provider, - ) + try: + metadata_llm = extract_metadata( + markdown_text, + provider=llm_provider, + ) - # Note: extract_metadata doesn't return cost directly - - callback( - "Metadata Extraction", - "completed", - f"Title: {metadata['title'][:50]}..., Author: {metadata['author']}", - ) + # Fallback to Word properties if LLM returns None + if metadata_llm is None: + callback( + "Metadata Extraction", + "completed", + "LLM extraction failed, using Word properties", + ) + raw_meta = content["metadata_raw"] + metadata = Metadata( + title=raw_meta.get("title", doc_name), + author=raw_meta.get("author", "Unknown"), + year=raw_meta.get("created").year if raw_meta.get("created") else None, + language=raw_meta.get("language", "unknown"), + ) + else: + metadata = metadata_llm + callback( + "Metadata Extraction", + "completed", + f"Title: {metadata.get('title', '')[:50]}..., Author: {metadata.get('author', '')}", + ) + except Exception as e: + callback( + "Metadata Extraction", + "completed", + f"LLM error ({str(e)}), using Word properties", + ) + raw_meta = content["metadata_raw"] + metadata = Metadata( + title=raw_meta.get("title", doc_name), + author=raw_meta.get("author", "Unknown"), + year=raw_meta.get("created").year if raw_meta.get("created") else None, + language=raw_meta.get("language", "unknown"), + ) else: # Use metadata from Word properties raw_meta = content["metadata_raw"] @@ -303,7 +331,7 @@ def process_word( main_sections = [ s for s in classified_sections - if s["section_type"] == "main_content" + if s.get("type") == "main_content" ] callback( @@ -316,8 +344,9 @@ def process_word( classified_sections = [ { "section_path": entry["sectionPath"], - "section_type": "main_content", - "reason": "No LLM classification", + "type": "main_content", + "should_index": True, + "classification_reason": "No LLM classification", } for entry in toc_flat ]