Skip to content

02 — AI Content Generatie

“Je hoeft niet te weten hoe een pagina eruitziet. Je hoeft alleen te weten wat je wilt zeggen.”

De AI Page Builder laat gebruikers pagina’s genereren op basis van een simpele beschrijving. De AI vertaalt de vraag naar de juiste blocks en patterns, vult ze met content die past bij het merk, en selecteert automatisch afbeeldingen uit de media library.


  1. Drie Informatiebronnen
  2. Twee Modi
  3. De AI Pipeline
  4. Per-Block Hergeneratie
  5. Tone of Voice Override
  6. Conversatie Modus
  7. Prompt Engineering
  8. Datamodel
  9. API Keuze
  10. Bouwvolgorde

De AI gebruikt altijd drie contextbronnen voor content generatie:

  1. Brand data — de JSON uit de onboarding (tone of voice, doelgroep, beschrijving, CTA’s, etc.)
  2. Bestaande pagina’s — gecachede samenvattingen van andere pagina’s op dezelfde site (voor consistentie en kruisverwijzingen)
  3. De prompt — wat de gebruiker vraagt, eventueel verfijnd door vervolgvragen

Eén tekstveld → volledige pagina in één keer.

┌─────────────────────────────────────────────┐
│ Beschrijf je pagina │
│ │
│ "Een diensten pagina voor onze drie │
│ renovatie services met pricing en een │
│ CTA naar het contactformulier" │
│ │
│ [✨ Genereer pagina] │
└─────────────────────────────────────────────┘

Chat-interface waar de AI eerst vragen stelt, dan stap voor stap de pagina opbouwt.

┌─────────────────────────────────────────────┐
│ AI: Wat voor pagina wil je maken? │
│ │
│ Gebruiker: Een pagina over onze diensten │
│ │
│ AI: Ik zie dat jullie in de bouw zitten. │
│ Hoeveel diensten wil je tonen? En wil je │
│ er pricing bij? │
│ │
│ Gebruiker: 3 diensten, met pricing │
│ │
│ AI: Dit is mijn voorstel voor de opbouw: │
│ 1. Hero met titel "Onze diensten" │
│ 2. 3× Dienst block met beschrijving │
│ 3. Pricing tabel │
│ 4. CTA naar contactformulier │
│ │
│ Zal ik dit genereren? │
│ │
│ [✅ Genereer] [✏️ Pas aan] │
└─────────────────────────────────────────────┘

De gebruiker typt een simpele beschrijving. Voordat de AI content gaat genereren, wordt de prompt intern verrijkt met context:

Gebruikersinput:
"Een diensten pagina met pricing"
Wordt intern:
Gebruikersvraag: "Een diensten pagina met pricing"
Brand context:
- Bedrijf: Bouwbedrijf De Vries — renovatie en nieuwbouw
- Doelgroep: Huiseigenaren 30-65, regio Utrecht
- Tone of voice: Professioneel maar benaderbaar, vakkundig zonder jargon
- Primaire CTA: "Vraag een gratis adviesgesprek aan"
- Differentiator: Persoonlijke begeleiding, één vast aanspreekpunt
Bestaande pagina's:
- Home: intro tekst over het bedrijf, 3 highlights
- Over ons: geschiedenis, team, werkwijze
(gecachede samenvattingen, niet volledige tekst)
Media library:
- 12 afbeeldingen beschikbaar
- AI beschrijvingen: "moderne woonkamer", "badkamer renovatie", etc.
Beschikbare blocks: hero, content, cta, pricing, feature, gallery, form
Beschikbare patterns: "Hero Primair", "Pricing Drie Kolommen", etc.

De AI bepaalt welke blocks en patterns nodig zijn en in welke volgorde.

Output (JSON):

{
"page_title": "Onze diensten",
"page_slug": "diensten",
"page_description": "Overzicht van renovatie, nieuwbouw en verbouwing diensten",
"structure": [
{
"position": 1,
"block_type": "hero",
"pattern_id": null,
"intent": "Paginatitel met korte intro over de diensten"
},
{
"position": 2,
"block_type": "feature",
"pattern_id": null,
"repeat": 3,
"intent": "Eén block per dienst met titel, beschrijving en afbeelding"
},
{
"position": 3,
"block_type": "pricing",
"pattern_id": "uuid-van-pricing-pattern",
"intent": "Pricing tabel met drie pakketten"
},
{
"position": 4,
"block_type": "cta",
"pattern_id": null,
"intent": "CTA naar contactformulier met primaire actieknop"
}
]
}

Als er een bestaand pattern past, gebruikt de AI dat via pattern_id. Anders wordt een block type gekozen.

Per block wordt content gegenereerd op basis van:

  • De intent uit de structuur
  • De brand data (tone of voice, beschrijvingen, CTA’s)
  • De bestaande pagina’s (consistentie, geen herhaling)
  • De media library (afbeeldingen matchen op AI beschrijvingen)

Output per block:

{
"position": 2,
"block_type": "feature",
"instance": 1,
"content": {
"title": "Renovatie",
"description": "Van badkamer tot complete woningrenovatie. We begeleiden je van ontwerp tot oplevering met één vast aanspreekpunt.",
"image": {
"media_id": "uuid-van-badkamer-foto",
"alt_text": "Moderne badkamer na renovatie door De Vries"
},
"cta": {
"text": "Meer over renovatie",
"link": "/diensten/renovatie"
}
}
}

De AI matcht afbeeldingen uit de media library op basis van:

  1. AI beschrijvingen van de afbeeldingen (gegenereerd bij upload of onboarding)
  2. Context van het block (bijv. “badkamer renovatie”)
  3. Wat al gebruikt is — voorkom duplicaten over blocks heen

Matching logica:

Block context: "Renovatie — badkamer tot complete woningrenovatie"
Media library scan:
- "moderne woonkamer met eiken vloer" → score 0.4
- "badkamer renovatie tegels" → score 0.9 ✅
- "team foto kantoor" → score 0.1
- "nieuwbouw woning buitenkant" → score 0.3

Als er geen passende afbeelding is, wordt een placeholder geplaatst met een suggestie (“Voeg hier een foto toe van een gerenoveerde badkamer”).


Na de initiële generatie kan de gebruiker per block de content opnieuw laten genereren. In de Page Editor verschijnt bij elk AI-gegenereerd block een ✨ icoon:

┌─────────────────────────────────┐
│ ✨ AI opties │
│ │
│ 🔄 Hergenereer content │
│ ✏️ Geef instructie │
│ 🎨 Andere tone of voice │
│ 🖼️ Andere afbeelding │
└─────────────────────────────────┘

🔄 Hergenereer content — nieuwe tekst met dezelfde context, andere formulering.

✏️ Geef instructie — gebruiker typt een aanpassing:

  • “Maak het korter”
  • “Voeg een opsomming toe”
  • “Focus meer op duurzaamheid”

De AI past de content aan op basis van de instructie, met behoud van brand context.

🎨 Andere tone of voice — tijdelijk de tone of voice aanpassen voor dit specifieke block. Toont dezelfde sliders als in de onboarding, maar dan per block. Overschrijft niet de brand data — eenmalige aanpassing.

🖼️ Andere afbeelding — AI toont de volgende best-matchende afbeeldingen uit de media library.


Standaard wordt de tone of voice uit de brand JSON gebruikt voor alle content generaties.

┌─────────────────────────────────┐
│ Tone of voice voor deze pagina │
│ │
│ [Gebruik brand standaard ✅] │
│ │
│ Of pas aan: │
│ Formeel ●────────○ Informeel │
│ Serieus ────●────○ Speels │
│ │
│ Preview: "Ontdek hoe wij uw │
│ woning transformeren met..." │
└─────────────────────────────────┘

Dit overschrijft niet de brand data — het is een eenmalige aanpassing voor deze specifieke generatie.


De AI heeft toegang tot alle brand data en bestaande pagina’s. Op basis daarvan stelt het slimme vragen.

  1. Doel begrijpen — open vraag: “Wat voor pagina wil je maken?”
  2. Specificeren — 2–3 gerichte vervolgvragen (hoeveel items, welke CTA, specifieke inhoud?)
  3. Structuur voorstellen — AI toont overzicht van blocks. Gebruiker kan aanpassen.
  4. Genereren — na goedkeuring wordt de pagina gegenereerd.
  5. Verfijnen — gebruiker kan per block feedback geven in de chat: “Block 2 is te lang” of “Voeg een testimonial toe na de pricing.”

Elke bericht bevat de volledige context:

{
"system_prompt": "Je bent de Beam page builder assistent...",
"context": {
"brand_data": { "..." },
"existing_pages_summary": [ "..." ],
"media_library": [ "..." ],
"available_blocks": [ "..." ],
"available_patterns": [ "..." ]
},
"conversation_history": [
{ "role": "user", "content": "..." },
{ "role": "assistant", "content": "..." }
]
}

De AI krijgt een system prompt die bestaat uit:

  1. Rol: “Je bent de Beam page builder assistent. Je helpt gebruikers pagina’s op te bouwen.”
  2. Brand context: volledige brand JSON
  3. Bestaande content: samenvattingen van andere pagina’s (niet volledige tekst — dat zou te veel tokens kosten)
  4. Block registry: beschrijving van elk beschikbaar block type en welke content velden het heeft
  5. Pattern registry: beschikbare patterns met hun structuur
  6. Media library: lijst van beschikbare afbeeldingen met AI beschrijvingen
  7. Output instructies: “Genereer output als JSON in het volgende format…”
  8. Tone of voice instructies: slider waarden vertaald naar concrete schrijfinstructies
Slider waarden:
formality: 0.6
seriousness: 0.7
technicality: 0.3
personality: 0.5
Wordt in de system prompt:
"Schrijf in een professionele maar benaderbare stijl.
Vermijd vakjargon — leg technische termen uit in eenvoudige taal.
Wees zakelijk maar niet afstandelijk. Gebruik 'u' als aanspreekvorm
maar houd de toon warm. Schrijf beknopt en to-the-point."

Om token-gebruik te beperken worden bestaande pagina’s niet volledig meegestuurd, maar samengevat:

{
"page": "Over ons",
"summary": "Beschrijft de geschiedenis van het bedrijf (opgericht 1985), het team (8 medewerkers), en de werkwijze (persoonlijke aanpak, één aanspreekpunt). Benadrukt vakmanschap en duurzaamheid.",
"key_terms": ["vakmanschap", "persoonlijke begeleiding", "duurzaam", "sinds 1985"],
"ctas_used": ["Neem contact op", "Bekijk onze projecten"]
}

Log van alle AI generaties voor debugging en verbetering.

KolomTypeOmschrijving
iduuid, PK
site_iduuid, FK
page_iduuid, FK, nullableNullable bij conversatie-modus
modeenum: quick, conversational
user_prompttextOriginele input van de gebruiker
enriched_prompttextVerrijkte prompt met brand context
ai_responsejsonbVolledige AI response (structuur + content)
model_usedtextBijv. claude-opus-4-6
tokens_usedintegerToken verbruik
tone_overridejsonb, nullableAfwijkende tone of voice voor deze generatie
created_attimestamptz

Gecachede samenvattingen van pagina’s voor AI context.

KolomTypeOmschrijving
iduuid, PK
page_iduuid, FK
summarytextAI-gegenereerde samenvatting
key_termstext[]Belangrijke termen
ctas_usedtext[]CTA’s die op de pagina voorkomen
generated_attimestamptz

Wordt opnieuw gegenereerd wanneer een pagina wordt opgeslagen.

AI beschrijvingen van media items voor slimme matching.

KolomTypeOmschrijving
iduuid, PK
media_iduuid, FK
descriptiontextAI beschrijving van de afbeelding
tagstext[]Automatisch gegenereerde tags
embeddingvector(1536), nullableToekomst: pgvector semantic search
generated_attimestamptz

De embedding kolom is voorbereiding op semantic search — later kun je met pgvector de media library doorzoeken op basis van block context.


De AI-laag is abstract zodat makkelijk gewisseld kan worden.

// Eén abstractie — interne implementatie is inwisselbaar
async function generateContent(
prompt: string,
context: GenerationContext,
options?: GenerationOptions
): Promise<GenerationResult>
CriteriumClaude (Anthropic)GPT (OpenAI)
Structured JSON outputSterk (met instructie)Native JSON mode
Tone of voice controleUitstekendGoed
Context window200K tokens128K tokens
Nederlandse contentGoedGoed
SnelheidSnelSnel

Voorkeur: Claude. Grotere context window is relevant voor het inladen van brand data + bestaande pagina’s + block registry in één call.


  1. page_content_summaries tabel + automatische samenvatting bij page save
  2. media_descriptions tabel + AI beschrijving generatie bij upload
  3. Block registry — gestructureerde beschrijving van elk block type en content velden
  1. UI: tekstveld + “Genereer pagina” knop
  2. Prompt verrijkings-pipeline (brand data + pagina-samenvattingen + media library)
  3. AI call → structuur bepalen (welke blocks/patterns)
  4. AI call → content genereren per block
  5. Afbeelding matching logica
  6. Resultaat renderen in de Page Editor
  1. ✨ AI opties menu per block in de editor
  2. Hergenereer content
  3. Instructie-gebaseerde aanpassing
  4. Afbeelding herwisselen
  5. Tone of voice override per block
  1. Chat interface UI
  2. Conversatie context management
  3. Structuur voorstel → goedkeuring flow
  4. Stapsgewijze generatie
  5. Per-block feedback in chat
  1. ai_generations logging (debugging + verbetering)
  2. Token optimalisatie (context window management)
  3. Caching van samenvattingen en beschrijvingen
  4. Vector embeddings voor media matching (pgvector)