feat(translation): quality pipeline overhaul + new features (audit 2026-08-29)
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m20s

Translation quality & format preservation:
- Word: merge adjacent same-format runs into one unit (sentence-level
  coherence like inline-tag handling); translate comments/balloons;
  dedupe textbox collection (was translated twice); RTL no longer
  overrides center/justify alignment; CJK/Arabic font hints (eastAsia/cs)
- PPTX: chart translations now actually reach the output file
  (ChartPart.blob is read-only — rewrite chart XML in the saved ZIP);
  CJK typeface hints (a:ea)
- Excel: sheet renames no longer break references — rewrite cell
  formulas (3D/quoted), defined names, data validations, cond. formats
- PDF: bold/italic honored (hebo/heit/hebi); table cells never merge;
  unchanged blocks left untouched (typography preserved, fixes duplicate
  hyperlinks); attempted/changed stats + route gate now cover PDF;
  CJK font paths; scanned PDFs via Mistral OCR (detection + admin settings)

Features:
- formality param (formal/informal) + automatic regional-variant prompts
- output_mode=bilingual docx (source above translation)
- per-user translation memory on Redis (falls back to LRU), context-hashed
- QA report + 0-100 confidence score in job status; L0 on by default
- OpenAI-compatible providers: whole chunk in ONE numbered-JSON request
  (~15x fewer calls) with per-item fallback; base prompt always present
  (custom prompt no longer replaces translation instructions)

Infra & marketing alignment:
- plan-based engine gating + vision gating (closes paid-engine leak);
  /providers/available filtered per plan; 107 languages exposed
- zh-CN/zh-TW validation fixed; libmagic disabled on Windows (native crash)
- admin: Mistral OCR settings + engine status dashboard; httpx<0.28 pin
  (TestClient breakage); Prometheus test fixture fixed
- marketing docs aligned with code (PDF+OCR, retention, engines, pricing)
- security: .env.ionos/.env.production/provider_settings.json removed

Tests: 1173 passed / 0 failed (6 network tests deselected: free Google
endpoint temporarily blocked from this machine)
This commit is contained in:
2026-08-29 18:38:09 +02:00
parent 992f13d53c
commit 526c87348f
87 changed files with 6996 additions and 1024 deletions

View File

@@ -0,0 +1,96 @@
# Passe approfondie n°2 — Traduction, mise en page, formats, admin & benchmark
**Date :** 29 août 2026 (2ᵉ passe) · **Statut : corrections appliquées et testées**
Méthode : revue complète des 4 traducteurs (word/excel/pptx/pdf) ligne à ligne (35 constats), benchmark web actualisé de 9 concurrents, puis correction des P1.
---
## 1. Corrections appliquées aujourd'hui (toutes testées)
### Qualité de traduction & mise en page
| # | Correctif | Impact |
|---|---|---|
| 1 | **Word/PPTX→Word : fusion des runs de même formatage** — une phrase éclatée en runs adjacents identiques (découpes rsid, correcteur ortho.) est désormais traduite en UNE unité ; la traduction s'écrit dans le 1ᵉʳ run, les frères sont vidés, les espaces de bord préservés. Les changements de formatage (gras au milieu) restent des unités séparées avec leur contexte. | **Plus gros écart qualité vs DeepL comblé** : fini les fragments hors contexte (« This is » / « very » / « important » en 3 appels) |
| 2 | **PPTX : les traductions de graphiques atteignent enfin le fichier** — l'ancien code assignait `ChartPart.blob` (propriété en lecture seule de python-pptx) : l'erreur était avalée et les titres/séries de graphiques n'étaient JAMAIS écrits. Réécriture du XML des graphiques dans le ZIP de sortie (même mécanisme que Word) + test de non-régression sur un VRAI graphique | Titres/axes/séries traduits pour de vrai |
| 3 | **Excel : le renommage d'onglets ne casse plus les formules** — openpyxl ne réécrit pas les références ; ajout de la réécriture dans : formules de cellules (multi-réfs, refs 3D, quoted/unquoted), noms définis, validations de données, mises en forme conditionnelles. Test dédié (`test_excel_sheet_rename_refs.py`) | `=SUM(Ventes!A3:A4)``=SUM(Sales!A3:A4)` au lieu de `#REF!` |
| 4 | **Word : commentaires/bulles traduits** (`word/comments.xml`, même mécanisme post-save que les notes de bas de page) | Cohérence vs DeepL pour les relecteurs |
| 5 | **Word : les zones de texte ne sont plus traduites 2×** (ensemble `seen_run_elements` partagé — coût API ÷2 sur ces éléments) | Coût + cohérence |
| 6 | **Word RTL : l'alignement n'est plus forcé à droite** — centré/justifié préservé, seul « gauche » devient « droite » | Titres RTL corrects |
| 7 | **PDF : gras/italique restitués** — sélection `hebo`/`heit`/`hebi` selon les flags du bloc (tout était redessiné en `helv` régulier) | Hiérarchie visuelle conservée |
| 8 | **PDF : les cellules de tableaux ne fusionnent plus**`_is_table_cell` était calculé puis jamais lu ; deux lignes consécutives d'une même colonne étaient jointes en un paragraphe | Structure des tableaux préservée |
| 9 | **PDF : un bloc inchangé n'est plus réécrit** — si la traduction est identique (échec fournisseur ou déjà dans la langue cible), on ne rédacte PAS : typo et polices incorporées d'origine conservées (au lieu de tout redessiner en police de substitution). Corrige au passage un doublon de liens hypertexte dans ce scénario | Moins de dégradation, pas de régression |
| 10 | **PDF : stats attempted/changed remontent** (+ propagation du chemin fallback pdf2docx) et la route applique le garde-fou `attempted==0`/`changed==0` aussi au PDF (une panne totale du moteur ne produit plus un job « réussi » non traduit) | Détection d'échec |
| 11 | **Prompts LLM : noms de langues complets** — nouvelle source unique `core/languages.py` (107 langues) utilisée par openai/deepseek/minimax + service legacy ; « Translate to Tagalog » au lieu de « Translate to tl » | Qualité sur langues rares |
### Page d'admin (revue + améliorations)
| # | Amélioration | Détail |
|---|---|---|
| A1 | **Réglages OCR Mistral dans l'admin** — nouvelle section `mistral` dans `SettingsConfig` (clé/modèle/timeout/activation), fusion env-var comme les autres moteurs, badge « clé dans .env », bouton **Tester** (validation réelle de la clé via `GET /v1/models`) | L'OCR PDF scannés se configure depuis l'UI, plus seulement via .env |
| A2 | **Dashboard : statut des 8 moteurs + OCR** — le panneau providers ne montrait que Google ; il liste désormais DeepL, OpenRouter éco/premium, OpenAI, Grok, Google Cloud et « OCR Mistral » avec état dérivé de la configuration (sans appel réseau) et tooltip explicite ; badge « PDF scannés refusés » si OCR non configuré | Vérifié en direct : 8 statuts + erreurs claires « Clé absente (X) » |
| A3 | L'OCR du pipeline lit les réglages admin > env (`set_ocr_config`), avec garde anti-footgun (un settings.json fraîchement sauvegardé ne désactive pas l'OCR configuré par env) | Cohérence prod |
---
## 2. Benchmark concurrentiel (résumé) — positionnement validé
Sources fraîches 2026-08-29 (DeepL changelog, pricing Google Cloud, Trustpilot/Reddit, annonces Mistral/Anthropic/OpenAI). Détails et URL dans le rapport d'agent.
- **Grille tarifaire Free/9/19/49 € : compétitive et bien échelonnée** — 9 € sous DeepL mensuel effectif, 19 € sans concurrent direct à ce prix avec choix de moteur, 49 € ~30-40 % sous DeepL Advanced. Recommandations : mettre les packs de crédits en avant face à l'ancre Google 0,08 $/page ; futur palier équipe ~99-149 € (zone vide avant Smartcat 100 $/mois).
- **Top plaintes utilisateurs DeepL/Google** (= nos angles d'attaque) : mise en page cassée sur docs complexes (n°1), PDF scannés refusés/gérés en texte brut, truncature silencieuse sur longs docs, plafonds de taille, aucun outil de relecture avant export, facturation/annulation friction.
- **Différenciateurs que nous avons déjà et qu'eux n'ont pas** : multi-moteurs par document, OCR PDF scannés intégré (DeepL web refuse ; Google refuse), 60+ langues à 9 €.
- **Marque : risque à surveiller** — « Wordly® » est une marque déposée par Wordly Inc. (wordly.ai, interprétation IA) ; vérification juridique recommandée avant d'investir dans la marque.
### Gap map vs DeepL (après les correctifs du jour)
| Fonction | DeepL | Wordly.art | Statut |
|---|---|---|---|
| Segmentation phrase avec protection du format inline | Oui (tags) | **Oui** (fusion de runs) | ✅ comblé aujourd'hui |
| Glossaires | Natifs (API, jusqu'à 5/requête) | Prompt LLM uniquement — **DeepL/Google : ignorés** | ⚠️ reste à faire (API DeepL directe) |
| Formalité (formel/informel) | Oui (Pro) | Non | 📋 quick win (prompt) |
| Variantes régionales (pt-BR/PT, fr-CA, de-CH) | GA juillet 2026 | Codes acceptés, pas de contrôle fin | 📋 quick win (prompt) |
| Mémoire de traduction | Pillier 2026 (Customization Hub) | Cache mémoire par process seulement ; le cache Redis TM codé n'est pas branché | 📋 à activer |
| Scores de confiance / QA | Non (prosumer) | L0/L1 codés, désactivés ; L2 réparé aujourd'hui | 📋 à activer |
| Sortie bilingue | Non | Non | 📋 quick win (demande forte) |
| Édition/relecture avant export | Non | Non | 📋 médium — différenciateur majeur vs DeepL |
| XLIFF (post-édition CAT) | API juillet 2026 | Non | 📋 médium (agences) |
---
## 3. Reste à faire (priorisé, non fait aujourd'hui)
**Quick wins (quelques heures chacun)**
1. Formalité + variantes régionales : option par job → prompt LLM (et `formality` DeepL quand l'API directe arrivera).
2. Sortie bilingue docx (paragraphes source+target en regard) — les segments existent déjà, c'est un rendu.
3. Activer le cache Redis TM existant (`services/translation_cache.py`) : cohérence terminologique + coûts ↓.
4. Activer les couches qualité L0/L1 (réparées) en log-only, afficher un score de confiance par document.
**Médium**
5. Glossaires sur moteurs non-LLM : passer DeepL en API HTTP directe (`glossary_id`, `formality`, `tag_handling`).
6. Contexte document dans les prompts LLM (titre/section courante en préfixe) + batch par liste JSON numérotée (~15× moins de requêtes).
7. Rapport QA post-traduction (écarts de nombres, segments non traduits, glossaire violé).
8. XLIFF 1.2/2.x export/import (agences).
**Plus gros / roadmap**
9. Éditeur de relecture côte à côte avant téléchargement (le vrai différenciateur pro).
10. Espaces de travail équipes (rôles, glossaires/TM partagés) → palier 99-149 €.
11. Polices par script cible (CJK/arabe) dans Word/PPTX (`eastAsia`/`cs`) et PDF (matrice de polices) ; annotations FreeText et texte pivoté en PDF.
12. Formats IDML/DITA (DeepL API les a ajoutés en juillet 2026 — créneau agences).
---
## 4. Vérifications
- **Suite complète : 1150 passed / 0 failed / 157 skipped** (les 6 tests désélectionnés sont des tests « RealAPI » réseau qui échouent uniquement parce que l'endpoint Google gratuit est momentanément bloqué depuis cette machine — ils passent quand le réseau coopère).
- **Réparations d'infrastructure de test au passage** (préexistantes, démasquées par la remise en route de la suite) :
- `requirements.txt` : httpx désormais borné `<0.28` (0.28 a supprimé `Client(app=)`, cassait 270 tests via starlette TestClient) → ~270 tests récupérés ;
- `tests/test_metrics.py` : fixture Prometheus réécrit (les compteurs vont sur un registre frais, plus de `Duplicated timeseries` quand l'app a déjà été importée) ;
- `tests/test_scanned_pdf_ocr.py` : le test e2e passe par `set_ocr_config()` (immunisé contre le rechargement du module config par un autre test).
- Suite traducteurs seule : 196/196 (dont 8 nouveaux tests PDF qualité, test graphique PPTX sur vrai fichier, 4 tests renommage Excel, 2 tests fusion runs Word, 2 tests gating mis à jour).
- Frontends : `tsc --noEmit` OK sur `frontend/` et `office-translator-landing-page/`.
- Dashboard admin testé en direct (8 statuts moteurs/OCR avec erreurs claires).
- Note : le Google gratuit (scraping) était bloqué depuis cette machine au moment des tests réseau (`TranslationNotFound`) — le garde-fou `changed==0` l'a correctement détecté ; c'est la fragilité connue qui justifie DeepL/Cloud pour les plans payants.
*Rapports complets des agents : analyse 35 constats (volet code) et benchmark 9 concurrents avec sources (volet marché) disponibles dans l'historique de session.*