concept24 / nova-ai-pagebuilder
AI Page Builder tool for Laravel Nova — conversational agent that builds landing pages (Page + blockText bands) with product selection, generated copy and images.
Requires
- php: >=8.1
- laravel/framework: ^12.0
- laravel/nova: ^4.12|^5.0
Requires (Dev)
None
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
AI Page Builder tool for Concept24 CMS — conversational multi-model agent that turns a natural-language brief into a complete draft landing page (Page + blockText bands, product selection, multi-locale copy, generated images), built on Laravel Nova.
Requirements
- PHP >= 8.1
- Laravel 12
- Laravel Nova 4.12+ / 5.x
- OpenRouter API key
- A C24CMS application — the package writes into the host app's
Page/BlockTextmodels and product catalog (not portable to other Laravel apps, same tradeoff asnova-ai-report)
Installation
composer require concept24/nova-ai-pagebuilder
The service provider is auto-discovered. Migrations run automatically via loadMigrationsFrom. Publish config manually:
php artisan vendor:publish --tag=nova-ai-pagebuilder-config
Register the tool in NovaServiceProvider::tools() and add a MenuSection pointing to /nova-ai-pagebuilder.
Configuration
config/nova-ai-pagebuilder.php:
| Key | Env var | Default |
|---|---|---|
openrouter.api_key | OPENROUTER_API_KEY | — |
models.coordinator | NOVA_AI_PB_MODEL_COORDINATOR | google/gemini-3.8-flash |
models.sql | NOVA_AI_PB_MODEL_SQL | google/gemini-3.8-flash |
models.copy | NOVA_AI_PB_MODEL_COPY | openai/gpt-6-astra |
models.image | NOVA_AI_PB_MODEL_IMAGE | google/gemini-3.1-flash-image |
model_options.* | — | per-role allowlists for the UI dropdowns |
max_tool_iterations | — | 30 |
page_defaults | — | draft (is_public=0, is_active=1), layout_default |
locales | — | null → config('app.allowed_languages') |
layouts.exclude | — | non-content bands excluded from the AI palette |
images.max_per_page | — | 12 |
rate_limit | NOVA_AI_PB_RATE_LIMIT | 30,1 |
Minimum .env:
OPENROUTER_API_KEY=sk-or-...
Features
- Clarify-first gate: for complex or ambiguous requests the coordinator asks the questions it needs (max 4, with proposed defaults) and makes no tool call until the user answers; simple, complete questions are answered directly.
- BI consultant stage (
select_productsinresearchmode): bestsellers / worst performers, FĂRĂ MIȘCARE (dead stock with immobilised value), MIȘCARE LENTĂ, SUPRASTOC / STOC CRITIC (days of cover), bought-together pairs, bundle proposals (slow mover + bestseller, both in stock, no invented discounts) and campaign product proposals that flow intopropose_structure. The SQL agent receives the real orders interval and the excluded (cancelled/returned) status ids computed from the DB, so an empty calendar window is reported honestly and analysed on the last days of activity; one time window per analysis. - Conversion skeleton for proposals: hero + image context band → bestsellers grid → benefits/guide → secondary products on an image layout (
catalog_09/catalog_08) → FAQ → final CTA band;generate_imageis dropped server-side on layouts that cannot render a generated image. - Conversational flow with consent gates: short interview → live layout catalog → proposed band structure (requires explicit user approval) → generation → data entry → links.
- Per-agent model dropdowns in the chat UI (Coordinator / DB queries / Copy / Images), config defaults + per-conversation override stored on the conversation (
modelsjson), validated server-side against per-role allowlists. - Product selection agent (
select_products): read-only SQL sub-agent (sanitizedSELECT/WITHonly, LIMIT cap, sensitive-column masking, session execution timeout). Supports curated pinned SKU selections (incl. best/worst-sellers viasite_orders_items) and dynamic filter specs (categories/brands/in_promo/last_added) consumed by the existingBlocktextRepositorypipeline. - Copy generation in all active locales (native per-locale writing, strict JSON, SEO meta limits enforced).
- Image generation via OpenRouter multimodal chat (
modalities: ['image','text']), persisted per-conversation to tmp storage and attached to bands via Spatie MediaLibrary by the applier. - Deterministic data entry (
LandingPageApplier): validates the full plan before any write (layouts on disk, min/max items, image refs, SKU existence), then creates the draft Page + bands + translations + media in one pass and flushescatalog/mediacache tags. Draft pages are previewable on the frontend by logged-in admins (Page::scopePublic). - Composition canvas (drag & drop): split view next to the chat — a layout palette (thumbnails + badges), band cards with per-band instructions, image toggle, variant select and product drop-zones; product chips from chat research are draggable onto bands; the agent's numbered structure proposals render as an importable card (layout choice stays with the user); "Generate page from composition" builds exactly the user's canvas (1:1 validation in the applier, pinned-product specs auto-filled from the canvas).
- Proposal → canvas handoff:
propose_structurecarries the SKUs already chosen withselect_products(validated server-side against active products), the per-band generated-image flag and the page-hero flag; "Import into the composition" pins them on the bands, so generation runs with no second product selection. - Server-side plan assembly:
create_landing_pageis called WITHOUT a plan —PlanAssemblerbuilds it from the canvas composition, the last successfulgenerate_copy(band refs in canvas order) and the generated images (band image ref = band copy ref,hero,<ref>_<n>per item); the coordinator only sendsproducts_by_bandfor product bands without pinned products. The explicitplanargument remains supported. - Live progress: sub-agents report steps over SSE (
tool_progress: each SQL query with its purpose and row count, copy attempts, parallel image batch) and running tool cards show an elapsed-time counter. - Parallel images: all
generate_imagecalls of one coordinator turn run as one HTTP pool (ImageGenerator::generateMany). - Product-aware copy: the copy agent receives the title, price and stock of the products pinned on each band and may name products/prices only from that list.
- Multi-conversation chat UI (SSE streaming, tool-call cards with image thumbnails, final page-result card with frontend + Nova links), per-phase cost logging (
coordinator/sql/copy/image).
Architecture
PageBuilderOrchestrator— coordinator tool loop (OpenAI-style function calling over OpenRouter, SSE).- Tools:
get_layout_catalog,select_products(modes: research/pinned/dynamic),generate_copy,generate_image(img2img with real product photos viaproduct_skus),create_landing_page,get_page_links,get_composition,propose_structure. LayoutCatalog— bands discovered fromresources/views/layouts_text/intersected with curated metadata (layout_catalog_meta.php).SqlToolRunner+QuerySanitizer— read-only SQL sub-loop.CopyGenerator,ImageGenerator— single-call sub-services with their own cost logging.LandingPageApplier— validation + transactional Page/BlockText creation.- Tables:
nova_ai_pagebuilder_conversations(incl.compositionjson — the canvas state, shared across users),nova_ai_pagebuilder_messages,nova_ai_pagebuilder_logs.
Changelog
| Version | Date | Notes |
|---|---|---|
| 0.4.0 | 2026-09-26 | Server-side plan assembly (PlanAssembler; create_landing_page without plan, optional products_by_band), live sub-agent progress (tool_progress SSE + elapsed timer), parallel image generation (generateMany, one HTTP pool per turn), product-aware copy (pinned products' title/price/stock per band), PHP time limit raised only during the chat stream and restored after (request_time_limit, env NOVA_AI_PB_REQUEST_TIME_LIMIT, default 900s — covers Octane's per-worker set_time_limit). Measured on a full Black Friday generation: 143s and $0.54 end-to-end, 0 rejected plans, 3 images in 17s. 61 feature tests |
| 0.3.1 | 2026-09-26 | Defaults from a benchmark on real sales data (16 conversations, verified against the DB): sql → google/gemini-3.8-flash, copy → openai/gpt-6-astra, coordinator stays google/gemini-3.8-flash (Opus 5.5 / Sonnet 5 / Astra Pro remain selectable). Coordinator: clarify-first gate (no tool call before the user answers), BI consultant stage with terminology and delivery format aligned to nova-ai-report, single time window per analysis, conversion skeleton for propose_structure. SQL agent: analysis recipes (velocity, days of cover, dead stock, bought-together pairs, bundles), real orders interval + excluded status ids injected from the DB, rationale surfaced on empty results. propose_structure drops generate_image on layouts without an image slot. Tests: applier test no longer depends on the host app's active locales |
| 0.3.0 | 2026-09-25 | Cost/latency: Anthropic prompt caching (cache_control on system + last message) in OpenRouterClient, layout catalog no longer duplicated in the system prompt (tool-only), SQL agent told to answer in 2-4 queries, 429 admission-control responses retried (max 2, Retry-After capped at 10s). Quality: SQL agent selects only in-stock products, treats expired price_promo as no discount and varies models (max 2 variants per model); copy agent receives each layout's notes (FAQ JSON body, stats numbers) and is forbidden to invent commercial claims (discounts, warranties, delivery times, customer counts) — same rule for the coordinator; image prompts get a server-side "no text/numbers/logos" suffix. Flow: propose_structure accepts product_skus, generate_image, page_hero and the canvas import pins them; general page instructions field removed from the canvas (tone/audience/goal come from the chat); empty SQL research results surface the agent's rationale. 55 feature tests (package tests/ now versioned) |
| 0.2.0 | 2026-09-25 | Model allowlists refreshed from the live OpenRouter catalog: coordinator default google/gemini-3.8-flash (+ GPT-6 Astra / Astra Pro, Claude Opus 5.5, Fable 5.1, Sonnet 5), SQL agent adds Opus 5.5 / Fable 5.1 / GPT-6 Astra, copy default openai/gpt-6-astra-pro, image adds Nano Banana Pro (google/gemini-3-pro-image) and GPT Image 2 (openai/gpt-5.4-image-2). Also: update an existing page from the composition + generate only from the composition, page-level hero, visible ⓘ tooltips, product search with drag & drop into the canvas; SQL fixes (tool-less closing call when iterations run out, explicit category-search guidance, error listing rejected SKUs) |
| 0.1.1 | 2026-08-26 | No functional changes — release de verificare pentru auto-update-ul Packagist (webhook Bitbucket) |
| 0.1.0 | 2026-08-26 | Composition canvas: split view with layout palette, drag&drop band cards (instructions, image kind, variants, product drop-zones), draggable product chips from chat research, importable numbered structure proposals (propose_structure), get_composition tool + MODUL COMPOZIȚIE prompt stage, GET/PUT conversations/{id}/composition, 1:1 canvas↔plan validation with auto-filled pinned-product specs, single-hero guard (page banner dropped when the first band is a hero with image). Fixes: SSE client dropped streaming tokens equal to "0" (PHP empty()), copy generator delta retry for missing band keys, interrupted tool-calls get synthetic results on replay (conversations stay resumable). Coordinator default moved to GPT (gpt-5.4, gpt-5.5 in allowlists); 45 feature tests |
| 0.0.1 | 2026-08-25 | Initial release: conversational landing-page agent with a two-stage flow — research/analysis turns (analytical product questions answered as markdown tables via mode=research, iterative proposals) and build stage (interview → structure consent → generation → data entry → links); per-agent model dropdowns (Coordinator/SQL/Copy/Image) with per-conversation override; read-only SQL product selection (pinned SKU + dynamic filters, best-sellers); multi-locale copy; image generation with img2img composition integrating the selected products' real photos (media read through the media disk, S3/spaces included); deterministic applier with full pre-write validation; draft-only pages with admin frontend preview; conversations shared across all tool users (owner shown in sidebar); per-phase cost logging; 31 feature tests |