# 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 (``). ### 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 : ```bash 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 : ```text 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 - [x] **Chimie `\ce{}`** : zéro balise `\ce` restante en texte brut. Formules converties en équations OMML complètes. - [x] **Matrices** : 341 balises `` créées avec alignement correct. - [x] **Tableaux & `\hline`** : Présence systématique des bordures `` sur les 105 tableaux du corpus. - [x] **Formules nues** : Élimination totale des formules isolées non encapsulées. - [x] **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 `.docx` vers `.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 : ```bash # 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/.verified.md", "output_docx_path": "/tmp/pack-mp1-test/verif_outputs/full_run/.docx", "pdf_path": "/tmp/pack-mp1-test/.pdf", "figures_manifest_path": "/tmp/pack-mp1-test/.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/.docx') as z: xml = z.read('word/document.xml').decode('utf-8') print('oMath:', len(re.findall(r'