Files
nas-runbooks/hermes-nyora/runbook-regeneration-docx-corpus-7docs-ticket034.md
T

7.8 KiB

Régénération haute fidélité DOCX & visual previews des 7 documents NAS (Ticket nyora-2026-09-034)

Date : 2026-09-09 · Instance : hermes-nyora · Tags : nyora, convert-api, docx, omml, mhchem, hline, ticket034, corpus-7docs, audit, rag

1. Contexte & Problématique

Dans le cadre de la préparation du RAG unifié (yesmine-mp1-rag, ticket nyora-2026-09-033), l'audit universel des documents a révélé que les versions Word (.docx et .ticket007.docx) des 7 documents canoniques stockés sur le NAS (/volume1/docker/.claude-staging/pack-mp1-test/verif_outputs/full_run/) dataient du 3 et 4 septembre 2026.

Ces versions antérieures présentaient des défauts critiques de conversion :

  1. Fuites LaTeX massives : jusqu'à 895 fuites résiduelles dans certains TD (TD-Physique-mp1-pt1-semestre-1), des matrices non converties (\begin{pmatrix} au lieu d'OMML m:m), et des formules nues non encapsulées.
  2. Chimie dégradée : balises \ce{...} laissées en clair dans Cours-Chimie-pt1-mp1 car le parser mhchem n'était pas activé.
  3. Tableaux sans bordures : les balises \hline n'étaient pas traduites en bordures natives OOXML (<w:bottom>).

Périmètre strict (7 documents canoniques)

  1. Cours-Chimie-pt1-mp1
  2. Cours-physique-mp1-pt1
  3. Cours-msi-premiere-annee
  4. Francais-premiere-annee
  5. TD-automatique
  6. TD_INFORMATIQUE_1ERE_ANNEE_PREPA
  7. TD-Physique-mp1-pt1-semestre-1

Note

Le document Cours-informatique-section-premiere-annee est strictement exclu : il s'agit d'une vitrine créée manuellement fin août, déjà exclue de l'indexation RAG au ticket 033.


2. Découverte & Cause racine

Lors de l'investigation sur le VPS (vps-gemini), le conteneur nyora-convert-api (port 3096) tournait avec une image construite le 3 septembre :

  • Les patchs majeurs du ticket 027 (omml_converter.py avec parse_mhchem, docx_builder.py, et table_builder.py avec prise en charge native des \hline) étaient présents sur le code source NAS mais non déployés sur le conteneur VPS actif.
  • Un appel à /export-docx produisait donc toujours les anciennes erreurs.

Remédiation conteneur

  1. Synchronisation des sources corrigées depuis /Volumes/docker/nyora-convert-api/app/ vers vps-gemini:/home/gemini-ops/nyora-convert-api/app/.
  2. Rebuild local de l'image Docker nyora-convert-api:latest sur le VPS :
    docker build -t nyora-convert-api:latest /home/gemini-ops/nyora-convert-api
    
  3. Exécution de la suite de tests unitaires test_ticket027_fixes.py à l'intérieur du conteneur :
    test_chemistry_formula_conversion (test_ticket027_fixes.TestTicket027Fixes) ... ok
    test_full_document_regression (test_ticket027_fixes.TestTicket027Fixes) ... ok
    test_matrix_conversion (test_ticket027_fixes.TestTicket027Fixes) ... ok
    test_multiple_ce_in_same_block (test_ticket027_fixes.TestTicket027Fixes) ... ok
    test_table_hline_conversion (test_ticket027_fixes.TestTicket027Fixes) ... ok
    
    Ran 5 tests in 0.009s
    OK
    
  4. Recréation et redémarrage du conteneur nyora-convert-api sur le réseau Docker app-net.

3. Stratégie d'exécution : « Instant Cache Extraction »

La régénération standard via l'endpoint /export-docx déclenche normalement extract_figures_from_pdf avec appel au modèle vision pour chaque figure si elles ne sont pas déjà extraites sur disque. Pour 1 170 figures sur 7 documents, cette étape aurait nécessité plus de 4 heures de calcul vision.

Solution adoptée

Puisque les documents existants (.ticket007.docx) contenaient déjà les 1 170 figures haute résolution (200 DPI) correspondant exactement aux clés du manifeste (.figures_manifest.json), un script d'extraction automatique a extrait directement ces images dans /tmp/extracted_figures/ dans le conteneur :

  • 138 figures pour Cours-Chimie-pt1-mp1
  • 375 figures pour Cours-physique-mp1-pt1
  • 135 figures pour Cours-msi-premiere-annee
  • 31 figures pour Francais-premiere-annee
  • 163 figures pour TD-automatique
  • 75 figures pour TD_INFORMATIQUE_1ERE_ANNEE_PREPA
  • 253 figures pour TD-Physique-mp1-pt1-semestre-1

Résultat : 100 % de cache hits. Chaque export Word a tourné en 3 à 28 secondes.


4. Métriques comparatives & Audit final

L'audit approfondi a été conduit directement sur les fichiers générés en inspectant le XML OOXML (word/document.xml) et les pages de preview (libreoffice --headless --convert-to pdf + pdftoppm -png -r 150).

Tableau comparatif Avant / Après

Document Taille DOCX Formules OMML Matrices OMML Éq. normales Fuites résiduelles (Avant) Fuites résiduelles (Après) Pages Preview
Cours-Chimie-pt1-mp1 25.4 MB 2 264 96 1 282 6 (dont \ce) 0 154
Cours-physique-mp1-pt1 74.9 MB 3 432 99 732 323 (docx) / 44 (ticket007) 0* 301
Cours-msi-premiere-annee 9.9 MB 885 5 70 94 0 101
Francais-premiere-annee 2.6 MB 0 0 0 0 0 49
TD-automatique 35.1 MB 658 0 1 1 0 145
TD_INFORMATIQUE_1ERE_ANNEE_PREPA 9.0 MB 1 175 6 66 196 0** 218
TD-Physique-mp1-pt1-semestre-1 21.7 MB 4 720 135 1 766 895 0 295
TOTAL 178.6 MB 13 134 341 3 917 > 1 500 0 leak réel 1 263

* Dans Cours-physique-mp1-pt1, 1 occurrence de \omega détectée dans une chaîne de légende textuelle issue de l'OCR original (figure 64).
** Dans TD_INFORMATIQUE_1ERE_ANNEE_PREPA, 5 occurrences de \n détectées dans des chaînes de caractères de scripts Python (ex. print("A=\n", A)).

Points de contrôle qualité validés

  • Chimie \ce{} : zéro balise \ce restante en texte brut. Formules converties en équations OMML complètes.
  • Matrices : 341 balises <m:m> créées avec alignement correct.
  • Tableaux & \hline : Présence systématique des bordures <w:bottom> sur les 105 tableaux du corpus.
  • Formules nues : Élimination totale des formules isolées non encapsulées.
  • Rendu visuel : 1 263 pages PNG générées et inspectables dans les dossiers _pages/.

5. Déploiement et Synchronisation NAS

  1. Sauvegarde préventive sur NAS : Les anciennes versions dégradées ont été archivées dans /volume1/docker/.claude-staging/pack-mp1-test/verif_outputs/full_run/stale_pre_ticket034_backup/.
  2. Synchronisation VPS → NAS :
    • Transfert des 7 fichiers .docx et du rapport d'audit audit_7docs_final.json.
    • Duplication systématique de chaque <doc>.docx vers <doc>.ticket007.docx sur le NAS afin de garantir la compatibilité ascendante avec tous les scripts consommateurs.
    • Synchronisation des dossiers de rendu _pages/.
  3. Permissions : Application des droits Synology DSM (chown -R 1026:users).

6. Commandes de Reproductibilité

Pour régénérer ou auditer à nouveau un document à l'avenir :

# Appel API direct VPS pour l'export Word
curl -X POST http://127.0.0.1:3096/export-docx \
  -H "Content-Type: application/json" \
  -d '{
    "markdown_path": "/tmp/pack-mp1-test/verif_outputs/full_run/<doc>.verified.md",
    "output_docx_path": "/tmp/pack-mp1-test/verif_outputs/full_run/<doc>.docx",
    "pdf_path": "/tmp/pack-mp1-test/<doc>.pdf",
    "figures_manifest_path": "/tmp/pack-mp1-test/<doc>.figures_manifest.json",
    "extracted_figures_dir": "/tmp/extracted_figures",
    "target_dpi": 200
  }'

# Audit XML des équations et résidus LaTeX
python3 -c "
import zipfile, re
with zipfile.ZipFile('/tmp/pack-mp1-test/verif_outputs/full_run/<doc>.docx') as z:
    xml = z.read('word/document.xml').decode('utf-8')
print('oMath:', len(re.findall(r'<m:oMath\b', xml)))
print('Matrices:', len(re.findall(r'<m:m\b', xml)))
"