# nyora-doc-api — Guide d'usage pour Hermes (v3 Premium) Service : `http://nyora-doc-api:8000` (interne réseau `n8n`) ou `http://172.17.0.1:3050` (depuis un container hors réseau n8n). Auth : header `x-api-key: nyora-doc-2026`. Endpoint unique : `POST /v1/generate` (multipart/form-data). ## Formats disponibles sans aucun fichier joint (mode "données pures") XLSX, PPTX, DOCX et PDF peuvent tous être générés à partir de JSON seul, sans template Word/Excel préexistant. C'est le mode à utiliser par défaut pour tout Hermes qui génère un rapport, une note ou un tableau à la volée. Champs de formulaire communs : - `format` : `xlsx` | `docx` | `pptx` | `pdf` - `data` : JSON (voir schémas ci-dessous) - `options` : JSON, ex. `{"theme": "nyora"}` (ou `"tt"` pour la palette Tunisie Telecom) - `output_name` : nom de fichier sans extension ## Schéma unifié DOCX / PDF ("sections") Le même JSON produit un DOCX ou un PDF selon le `format` demandé — pas besoin de réécrire le contenu deux fois. ```json { "title": "Titre du document", "subtitle": "Sous-titre optionnel", "date": "01/07/2026", "sections": [ {"heading": "Titre de section", "level": 1, "text": "Paragraphe.\n\nDeuxième paragraphe (séparer par une ligne vide)."}, {"bullet_list": ["Point 1", "Point 2"]}, {"numbered_list": ["Étape 1", "Étape 2"]}, {"table": { "headers": ["Region", "Budget", "Réalisé"], "rows": [["Sfax", 1250000, 987654.321]], "totals": true }} ] } ``` ## Schéma XLSX ("sheets") ```json { "title": "Titre optionnel (affiché en en-tête fusionné de la feuille)", "sheets": [ { "name": "Budget", "totals": true, "headers": ["Region", "Budget", "Réalisé", "Ecart %"], "rows": [["Sfax", 1250000, 987654.321, -21.048]] } ] } ``` ## Schéma PPTX ("slides") ```json { "title": "Titre (génère une slide de couverture automatique)", "subtitle": "Sous-titre optionnel", "cover": true, "slides": [ {"title": "Titre de slide", "kpis": [{"label": "Budget", "value": 1250000}]}, {"title": "Détail", "table": {"headers": [...], "rows": [...], "totals": true}}, {"title": "Texte", "content": "Paragraphe de contenu libre."} ] } ``` ## Formatage numérique automatique Toute valeur numérique dans un tableau ou un KPI est automatiquement formatée en convention française premium : séparateur de milliers (espace insécable) + 3 décimales, ex. `1 250 000,000`. Si l'en-tête de colonne contient `%`, `pourcent` ou `taux`, un suffixe `%` est ajouté automatiquement : `-21,048 %`. Pas besoin de pré-formater les nombres côté Hermes — envoyer les valeurs brutes (int ou float). Pour XLSX, le format Excel natif est appliqué (`#,##0.000`), donc le séparateur affiché suit la langue d'Excel de l'utilisateur — c'est le comportement standard et correct. ## Totaux automatiques Ajouter `"totals": true` sur un `sheet` (xlsx), un `table` (docx/pdf/pptx) calcule et affiche automatiquement la somme de chaque colonne numérique, avec un style visuellement distinct (fond gris-or, gras). ## Mode template (documents officiels TT) Pour les documents avec en-tête officiel (lettre TT, note interne), utiliser `template_name` au lieu de laisser DOCX en mode données : - `template_name=papier-entete-tt` - `template_name=note-tt-template` Dans ce cas, `data` doit correspondre aux variables Jinja du template (`{{ destinataire }}`, `{{ objet }}`, etc. — voir le contenu du template pour la liste exacte), pas au schéma "sections" ci-dessus. ## Exemple d'appel curl (référence pour construire l'appel HTTP depuis n8n/Hermes) ```bash curl -X POST http://nyora-doc-api:8000/v1/generate \ -H "x-api-key: nyora-doc-2026" \ -F "format=pdf" \ -F 'data={"title":"Note","sections":[{"heading":"Contexte","text":"..."}]}' \ -F "output_name=ma_note" \ -o ma_note.pdf ``` ## Limitations connues (non bloquantes) - `generate_csv` a une signature incompatible avec l'appel générique dans `main.py` (`GENERATORS[fmt](template_path, ...)` passe 4 arguments à une fonction qui n'en attend que 3) — le format `csv` échoue actuellement. Non corrigé à ce stade (hors périmètre de la mise à niveau premium du 01/07/2026), à traiter séparément si `csv` devient nécessaire. - Mode template DOCX/PPTX (fichier Word/PPTX existant) : le restyle de police ne s'applique qu'aux styles de paragraphe, pas au formatage direct des runs déjà présents dans le template (limitation structurelle de Word/PowerPoint, déjà documentée en mémoire depuis le 30/06/2026). --- *Document créé le 01/07/2026 lors de la mise à niveau premium v3 de nyora-doc-api.* ## Contrôle qualité automatique (QC) — PPTX Depuis le 01/07/2026 (commit `cbe8cf1`), toute génération PPTX est auto-vérifiée en fin de rendu : `validate_pptx_layout()` relit la présentation générée et détecte les zones de texte dont le contenu dépasse probablement la hauteur disponible du conteneur (titre, KPI, contenu libre). C'est un correctif direct au bug historique du bandeau de titre à hauteur fixe (1.1in) qui débordait sur le contenu dès qu'un titre passait sur deux lignes — le bandeau se dimensionne maintenant dynamiquement (`estimate_wrapped_lines()` dans `formatting.py`) et le reste de la slide suit. Le contrôle est **non bloquant** : le fichier part toujours. Les avertissements éventuels arrivent dans les en-têtes HTTP de la réponse : ``` X-QC-Status: ok | warning X-QC-Warnings: ["Diapo 2 — texte probablement en debordement (\"...\") : besoin estime ~1.42\" pour 3 ligne(s), zone disponible 1.30\"."] ``` Hermes/n8n qui appellent `/v1/generate` en PPTX devraient lire ces deux en-têtes sur la réponse et, si `X-QC-Status: warning`, le signaler à l'utilisateur (ex. message Telegram) plutôt que livrer silencieusement un document potentiellement en débordement — le fichier reste utilisable, mais mérite une relecture rapide côté PowerPoint. Limite connue de ce QC : il porte uniquement sur le mode données (JSON), pas sur le mode template — cohérent avec la limitation de restyle déjà documentée ci-dessus. ## Panne corrigée le 03/07/2026 — clé absente du runtime Hermes-TT **Symptôme** : Hermes-TT échouait à appeler `nyora-doc-api` (401), malgré cette documentation mentionnant correctement le header `x-api-key` et sa valeur. **Cause réelle** : la variable `NYORA_DOC_API_KEY` n'existait ni dans `/volume1/docker/hermes-platform/.env`, ni — surtout — dans le bloc `environment:` des 3 services (`hermes-agent-tt/nyora/perso`) du `docker-compose.yml` d'hermes-platform. Ce fichier whiteliste explicitement chaque variable transmise au container : `NYORA_DOC_API_URL` y était bien présente, mais `NYORA_DOC_API_KEY` n'avait jamais été ajoutée. Résultat : même avec un `.env` correct, la clé n'atteignait jamais le container. **Correctif appliqué** : 1. Ajout de `NYORA_DOC_API_URL` + `NYORA_DOC_API_KEY=nyora-doc-2026` au `.env` (section "Services NAS"), suppression au passage des lignes mortes `PANDOC_URL`, `CARBONE_URL`, `GOTENBERG_URL`, `PPTX_API_URL`, `DOCUMENT_FACTORY_URL`, `TIKA_URL` (services désinstallés). 2. Ajout de `NYORA_DOC_API_KEY: ${NYORA_DOC_API_KEY}` dans le bloc `environment:` des 3 services du `docker-compose.yml`. 3. `docker compose up -d hermes-agent-tt hermes-agent-nyora hermes-agent-perso` pour recréer les 3 containers. 4. Vérifié : `env | grep NYORA_DOC_API_KEY` dans les 3 containers, puis test `curl -H "x-api-key: $NYORA_DOC_API_KEY" $NYORA_DOC_API_URL/v1/templates` depuis `hermes-agent-tt` → `200`. **Leçon** : dans ce projet, ajouter une variable au `.env` ne suffit **pas** — elle doit aussi être déclarée explicitement dans le bloc `environment:` de chaque service du `docker-compose.yml` d'hermes-platform. Réflexe à avoir pour toute nouvelle intégration (vérifier les 2 fichiers, pas un seul). Skill `hermes-tt/data/skills/achats/email-html-marches/references/nyora-doc-api.md` corrigé en parallèle (il indiquait un header incertain `X-API-Key`/`api-key` et une clé "non trouvée" — remplacé par le header exact `x-api-key` et un renvoi à la variable d'environnement plutôt qu'une valeur en clair).