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,37 @@
# Session du 2026-08-29 (3ᵉ passe) — « Fais tout » : quick wins + items médiums livrés
> Décision produit de la session : **aucune intégration DeepL** (refus explicite). Formalité et variantes régionales passent exclusivement par les prompts LLM.
## Livré dans cette session (tout testé — 23 nouveaux tests + 1 mis à jour)
| # | Fonctionnalité | Implémentation | Tests |
|---|---|---|---|
| 1 | **Formalité (formel/informel)** | Nouveau paramètre `formality` sur `POST /api/v1/translate` → directive `TONE:` ajoutée au prompt de tous les moteurs LLM (openai/deepseek/minimax/legacy) via `build_full_prompt` | 3 |
| 2 | **Variantes régionales automatiques** | `target_lang` régional (pt-BR, fr-CA, zh-CN…) → directive `REGIONAL VARIANT: write in <nom complet>` dans le prompt | 2 |
| 3 | **Bug corrigé : prompt personnalisé qui remplaçait les instructions** | Les 3 providers LLM incluent TOUJOURS le prompt de base ; glossaire/ton/contexte s'y ajoutent (`ADDITIONAL CONTEXT AND INSTRUCTIONS`) — avant, un glossaire seul produisait un prompt sans instruction de traduction | 1 (+ openai) |
| 4 | **Mémoire de traduction (TM) activée** | `services/translation_tm.py` branche le cache Redis existant (`translation_cache.py`, TTL 24 h, fallback LRU sans Redis) dans Word/Excel/PPTX. **Périmètre par utilisateur** (jamais de partage inter-clients) + hash du contexte (glossaire/ton) pour invalidation. Les traductions identiques à la source ne sont jamais stockées (anti-poison). Repli silencieux si le provider échoue | 5 |
| 5 | **Sortie bilingue (docx)** | Paramètre `output_mode=bilingual` : chaque paragraphe traduit est précédé de sa source (gris, italique, 9 pt) — `translators/bilingual.py`. Repli propre si structure divergente | 2 |
| 6 | **Rapport QA + score de confiance** | `services/quality/qa_report.py` : fidélité des nombres (séparateurs décimaux normalisés), ratio non-traduit, **score 0-100** exposé dans `GET /api/v1/translations/{id}` (champ `quality`) et le statut de complétion. Jamais bloquant | 5 |
| 7 | **Batch JSON pour LLM** | `openai_provider.translate_batch` envoie un chunk entier en **1 requête** (liste JSON numérotée) au lieu de 15 requêtes isolées — ~15× moins d'appels, cohérence contextuelle entre segments voisins. Repli automatique par item si la réponse est non conforme | 3 |
| 8 | **Qualité L0 par défaut ON** | `QUALITY_L0_ENABLED=true` par défaut (observabilité pure, ne bloque jamais) | — |
| 9 | **Polices CJK/arabe** | Word : hints `w:eastAsia` (SimSun/Yu Mincho/Batang) et `w:cs` sur les runs ; PPTX : `<a:ea>` typeface ; PDF : chemins Noto CJK (Linux) + simsun/msgothic (Windows) ajoutés | 2 |
**Exemples d'appel :**
```bash
# Ton formel + portugais brésilien
curl -F file=@doc.docx -F target_lang=pt-BR -F formality=formal .../api/v1/translate
# Sortie bilingue
curl -F file=@doc.docx -F target_lang=en -F output_mode=bilingual .../api/v1/translate
```
## Vérifications
- Suite complète : voir ligne finale ci-dessous (6 tests réseau Google désélectionnés — endpoint gratuit momentanément bloqué depuis cette machine, sans lien avec le code).
- `tsc --noEmit` OK sur les deux frontends.
## Non livré (justifié)
- **Éditeur de relecture côte à côte** : nécessite la persistance des segments par job (schéma BDD + UI d'édition) — chantier à part entière, il ouvre la voie au XLIFF.
- **Espaces de travail équipes (rôles, glossaires partagés)** : migrations + facturation multi-sièges.
- **XLIFF export/import** : dépend de la persistance des segments (même chantier que l'éditeur).
- **IDML/DITA** : nouveaux parseurs de formats — à chiffrer séparément.
- **DeepL natif (glossaires/formalité API)** : refusé par le propriétaire — la formalité LLM couvre le besoin sans DeepL.