Files
nas-runbooks/common/hermes-nabil-images-flyers-navigateur.md
T

7.3 KiB

hermes-nabil (VPS Contabo) — images, flyers et rendu navigateur

Prototype du futur hermes-desktop (Mac). Complete common/hermes-nabil-vps-deploiement.md.

1. Toolset navigateur : hermes postinstall doit etre BAKE dans l'image

hermes postinstall installe Node, ffmpeg, ripgrep, agent-browser + Chromium (/root/.agent-browser/browsers/chrome-<version>/chrome, ~390 Mo). Tout cela vit dans le filesystem du conteneur : un docker compose up -d qui recree le conteneur le perd.

Piege vecu

Ajouter simplement RUN hermes postinstall a un FROM python:3.11-slim echoue en silence (build exit 0, image sans navigateur) :

  • listes apt vides -> Unable to locate package ripgrep / ffmpeg
  • Node.js not found — Could not find Node.js 22 binary for linux-x64

Dockerfile correct

FROM python:3.11-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
      curl ca-certificates xz-utils nodejs npm ffmpeg ripgrep \
      fonts-dejavu-core fonts-liberation \
      libnss3 libnspr4 libdbus-1-3 libatk1.0-0 libatk-bridge2.0-0 libcups2 \
      libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
      libgbm1 libpango-1.0-0 libcairo2 libasound2 libatspi2.0-0 libx11-6 \
      libxcb1 libxext6 libexpat1 libuuid1 \
 && rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir hermes-agent \
    python-docx python-pptx openpyxl XlsxWriter reportlab pypdf pillow markdown requests
ENV HERMES_HOME=/data
WORKDIR /data
RUN hermes postinstall && rm -rf /var/lib/apt/lists/* /tmp/*
CMD ["hermes","gateway","run"]

Verification apres build (sans toucher au conteneur en service) :

docker run --rm --entrypoint bash hermes-nabil:latest -lc \
  'which node ffmpeg rg; ls -d /root/.agent-browser/browsers/chrome-*'

Image finale ~666 Mo. Build ~4 min -> toujours en detache (nohup docker build ... > log 2>&1 &), le connecteur mcp-vps tombe sur les operations longues.

2. Rendu HTML/CSS -> PNG / PDF

Pas besoin de Playwright : Chrome headless en CLI suffit et est plus robuste.

CH=$(ls -d /root/.agent-browser/browsers/chrome-*/chrome | tail -1)
$CH --headless --disable-gpu --no-sandbox --hide-scrollbars \
    --window-size=1080,1350 --screenshot=/data/out.png file:///data/in.html
$CH --headless --disable-gpu --no-sandbox --no-pdf-header-footer \
    --print-to-pdf=/data/out.pdf file:///data/in.html

Les ERROR:dbus/bus.cc sont cosmetiques (pas de bus D-Bus en conteneur), le fichier est bien ecrit. --no-sandbox obligatoire en conteneur. @page{size:WxH;margin:0} en CSS pour un PDF au format exact.

3. Generation d'images IA — ni OpenCode, ni Gemini free tier

OpenCode : aucune capacite image (teste 18/07/2026)

  • /images/generations : 404, l'endpoint n'existe pas.
  • mimo-v2-omni : 400 "Upstream request failed" meme sur un prompt texte trivial -> modele mort cote provider.
  • mimo-v2.5 (200) invente un lien imgur bidon quand on lui demande une image.
  • /models : 403 Cloudflare 1010 sans en-tete User-Agent.

Gemini direct (Google AI Studio) : quota 0 sur le free tier

Cle valide (50 modeles listes), mais tous les modeles image renvoient 429 limit: 0 : gemini-3-pro-image, gemini-3.1-flash-image, gemini-2.5-flash-image et variantes. Les imagen-4.0-* renvoient 404 "no longer available to new users". => La generation d'images Google est reservee au tier payant (facturation activee sur le projet). Ce n'est pas un probleme de cle : la meme cle liste les modeles et fonctionne en texte.

Backend retenu : OpenRouter -> google/gemini-2.5-flash-image

Meme modele (nano-banana), accessible immediatement, cout une fraction de centime par image. Voir openrouter-image-gen.md pour les pieges (modalities, message.images[]). Cle OPENROUTER_API_KEY dans data/.env, reprise de HERMES_PERSO_OPENROUTER_KEY (hermes-platform/.env du NAS) et transferee sans jamais l'exposer : voir transfert-secret-inter-machines.md.

/data/nyora/nyora_image.py implemente la cascade OpenRouter -> Gemini direct : Gemini reste cable et prendra le relais sans modification de code le jour ou la facturation Google sera activee. Le backend OpenRouter accepte en plus une image source (edition : fond neutre, retouche), ce que la voie Gemini directe ne fait pas ici.

4. Pipeline flyer Nyora

/data/nyora/nyora_flyer.py : image IA -> HTML/CSS charte Or Bruni (navy #1A1A2E, cream #F5F5F0, gold #B8862A) -> PNG + PDF -> envoi Telegram (multipart urllib, zero dependance). Skill agent : /data/skills/nyora-flyer/SKILL.md.

python3 /data/nyora/nyora_flyer.py '{"nom":"x","titre":"Titre <em>or</em>","sous_titre":"NYORA",
 "corps":["ligne 1","ligne 2"],"cta":"Contact","prompt_image":"... sans texte","telegram":true}'

Regle : le prompt image precise sans texte — le texte est pose en HTML (net, orthographe maitrisee). Image encodee en base64 inline dans le HTML : un seul fichier, pas de probleme de chemin cote Chrome.

5. Rappels

  • Verifier une cle sans l'afficher : set -a; . /data/.env; set +a; eval v=\${VAR}; echo ${#v}. Attention : ${#VAR} sur le nom renvoie la longueur du nom, pas de la valeur.
  • data/.env est le seul fichier lu par Hermes (pas le .env racine).
  • Le wrapper mcp interdit docker rm -f : utiliser docker compose up -d (recreate propre) et docker run --rm pour les tests jetables.

6. Edition d'image (Fal.ai + repli OpenRouter)

/data/nyora/nyora_image_edit.py. Cascade Fal.ai -> OpenRouter nano-banana.

Fal.ai

  • Endpoint synchrone : POST https://fal.run/<modele>, en-tete Authorization: Key <FAL_KEY> (pas Bearer). Reponse : images[0].url (URL hebergee, a telecharger).
  • L'image source passe en data-URI base64, pas besoin d'heberger le fichier.
  • Piege de schema : le nom du champ source change selon le modele — nano-banana/edit attend image_urls (tableau), flux-pro/kontext et qwen-image-edit attendent image_url (chaine). Un mauvais champ = 422.
  • Modeles : fal-ai/nano-banana/edit (respect fidele du sujet, fond/retouche), fal-ai/flux-pro/kontext (edition dirigee), fal-ai/qwen-image-edit (texte et details).

Etat du compte (18/07/2026)

Cle valide et authentifiee, mais les trois modeles renvoient User is locked. Reason: Exhausted balance -> solde Fal.ai epuise, recharge necessaire sur fal.ai/dashboard/billing. Ce n'est ni un probleme de cle ni de code.

Lecon : un repli silencieux masque un probleme de facturation

La cascade avait fait son travail (les editions ont abouti via OpenRouter) mais sans rien signaler : les trois tests semblaient reussis alors que Fal etait mort. Correction appliquee — quand un repli se declenche, la raison de l'echec du backend principal est ecrite sur stderr (AVERTISSEMENT repli sur OpenRouter — Fal indisponible : ...). Regle generale : toute cascade de backends doit journaliser pourquoi elle est descendue d'un cran.

Consignes d'edition

Toujours formuler en conservant explicitement le sujet ("garde X exactement identique"), sinon le modele reinvente l'image. Pour un PNG reellement transparent : sujet sur fond blanc plat puis detourage flood-fill PIL depuis les bords (cf openrouter-image-gen.md).