gigafibre-fsm/services/targo-hub/templates
louispaulb 0fd1e9f6b5 feat(campaigns/templates): Gemini-powered HTML→native converter
Scales the native-block migration from "one template per manual spec"
to "any compiled .html template, one CLI command, ~5 seconds, ~$0.001
per template" via Gemini Flash semantic interpretation.

Pipeline (ai-convert-to-native.js):
  1. Read existing compiled .html
  2. Send inner body to Gemini Flash with a tight JSON schema
     (block.type ∈ text/image/button/divider/html, plus type-specific
     fields like fontSize/color/padding/href).
  3. AI returns { preheader, ariaLabel, blocks: [...] }
  4. Deterministic emit of a templates-spec/<name>-native.js file —
     no AI-touched markup goes into the final compiled output.
  5. Validation: every {{var}} in source MUST survive into the spec;
     warn loudly if any are dropped (the AI occasionally omits minor
     placeholders like {{year}} in the copyright line).

Why deterministic emit matters:
  Gemini understands SEMANTICS reliably ("this paragraph is the
  greeting, this div is the CTA, this span is a chip") but
  hallucinates DETAILS when generating final HTML. Splitting the
  responsibilities means the AI only outputs structured JSON
  describing the layout, and build-native-template.js produces the
  bytes shipped to recipients.

First conversion: gift-email-fr → gift-email-fr-native
  - 15 blocks identified by Gemini in 3006 tokens (Flash, ~5s).
  - 4 row groups: view-in-browser, white card (intro/chips/CTA/
    footer copy), contact info, dark footer band.
  - 7 text + 1 image + 1 button + 6 html blocks (chips, multi-logo
    strip, brand-logo card, expiry section stay as raw HTML —
    correct, those have no native equivalent).
  - HTML payload: 19,664 bytes vs original 39,913 bytes — **-51%**.
  - One AI omission caught by the new sanity check: {{year}} was
    stripped from the © line in the dark footer. Hand-patched in the
    generated spec. Re-running with stricter prompt should reduce
    that occurrence rate.

Hub preview endpoint now defaults vars.year to current year (matches
the test-send endpoint that already did this), so the sample render
shows "© 2026 TARGO Communications" instead of "©  TARGO ...".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 18:29:15 -04:00
..
contract-residential.html feat: flow editor, Gemini QR scanner with offline queue, dispatch planning v2 2026-04-22 10:44:17 -04:00
gift-email-en.html style(campaigns/templates): replace em-dashes with periods/commas 2026-06-01 12:26:59 -04:00
gift-email-en.json style(campaigns/templates): replace em-dashes with periods/commas 2026-06-01 12:26:59 -04:00
gift-email-fr-native.html feat(campaigns/templates): Gemini-powered HTML→native converter 2026-06-01 18:29:15 -04:00
gift-email-fr-native.json feat(campaigns/templates): Gemini-powered HTML→native converter 2026-06-01 18:29:15 -04:00
gift-email-fr.html feat(campaigns/templates): visible wrapper-expiry date in the email 2026-05-22 10:47:58 -04:00
gift-email-fr.json feat(campaigns/templates): visible wrapper-expiry date in the email 2026-05-22 10:47:58 -04:00
gift-email-fr.legacy-rich.html.bak feat(campaigns): MJML canonical templates + test-send button 2026-05-21 22:36:35 -04:00
gift-email-native-reminder-fr.html feat(campaigns/templates): native-block reminder template (proof of concept) 2026-06-01 15:31:15 -04:00
gift-email-native-reminder-fr.json feat(campaigns/templates): native-block reminder template (proof of concept) 2026-06-01 15:31:15 -04:00
gift-email-reminder-en.html style(campaigns/reminder): add "pour te remercier" / "as a thank-you" 2026-06-01 15:09:41 -04:00
gift-email-reminder-en.json style(campaigns/reminder): add "pour te remercier" / "as a thank-you" 2026-06-01 15:09:41 -04:00
gift-email-reminder-fr.html style(campaigns/reminder): add "pour te remercier" / "as a thank-you" 2026-06-01 15:09:41 -04:00
gift-email-reminder-fr.json style(campaigns/reminder): add "pour te remercier" / "as a thank-you" 2026-06-01 15:09:41 -04:00