AI Product Description Generator
Module 22 · ai · intermediate
Lesson 22 · AI Product Description Generator
Goal
Stores have hundreds of products with no copy, or placeholder text (TBD, lorem ipsum). AI can write it, but unchecked AI copy invents specs and makes claims you can't back up. Build a generator that writes in batches, checks every draft, and publishes only what a human approves.
Prerequisites
- Modules 10 (AI generation), 15 (AI with a template fallback), 18 (structured AI output)
- For the live part: an OpenAI key and a Shopify store (a development store is free) with an Admin API access token
Concepts
- Batching. Pick only products that need copy (empty, under 30 words, or placeholder text like TBD or lorem ipsum) and cap each run (
batch_size). Cost stays predictable and the review queue stays manageable; the rest waits for the next run. - Brand voice in Settings. Voice, audience and banned phrases are data, not buried in the prompt, so a client can change them.
- Structured output + code-built HTML. The model returns fields (description, bullets, SEO title, meta description, tags). Code builds and escapes the HTML, so the model can never inject markup.
- Guardrails. Code checks every draft: banned phrases (health, eco and guarantee claims are legal risks), numbers that don't appear in the product data (a cheap, effective hallucination check), word count, and thin product data. Anything flagged is marked
needs_review. - Fallback. If the AI fails, a plain template built from the facts goes to review instead. The run never stops.
- Merge before shared steps. When some items go through the AI and some don't (supplied drafts), a Merge node joins both branches so the checks and the response run once.
- Human in the loop. Nothing is published automatically. Reviewers approve (optionally with edits) or reject; publishing counts only when Shopify returns the product.
Build it
Step 1: Triggers, Settings, Route
- Schedule
Daily 7 AM, WebhooksGenerate API(POSTpd/generate),Review API(GETpd/review),Decide API(POSTpd/review/decide). - Edit Fields
Settings (edit me): brand name, voice, audience,banned_phrases,max_words,min_existing_words,batch_size,max_tags,use_ai. - Switch
Route: generate / review / decide.
Step 2: Load and pick
- IF
Products from API?→ else Shopify Product → Get Many (limit 250, On Error → Continue, Always Output Data). - Code
Pick Products(select.js): normalize (strip HTML, count words, options → attributes), choose products needing copy (skipping ones already in review), cap atbatch_size, attach run info to the first item.
Step 3: Write and check
- IF
Use AI?→ Basic LLM ChainWrite with AI(prompt incode/ai-prompt.txt) + OpenAI Chat Model + Structured Output ParserCopy Format; On Error → Continue. - Merge
Join Branches(append): AI output on input 1, non-AI items on input 2. - Code
Check Copy(check.js): AI copy, supplied draft or template; guardrails; SEO cut at a word boundary (60/155); tags merged, lowercased, deduped; escaped HTML. - Code
Queue for Review(queue.js): save drafts (version +1 on regenerate) unless dry run → Respond (API) or Notify Reviewer (Exercise 1).
Step 4: Review and publish
- Code
Review Queue(review.js) → Respond. - Code
Apply Decision(decide.js): reject → saved with note; approve → final HTML with edits. - IF
Publish?→ Shopify Product → Update (body_html, tags), On Error → Continue → CodeRecord Publish(published.js): published only if Shopify returned the product id.
Publish the workflow (static data only persists for production executions).
Test it
./test/test.sh # 40 assertions, no credentials
WITH_CREDS=1 SHOPIFY_PRODUCT_ID=1234567890 ./test/test.sh # AI copy + publish one product
Check copy you already have:
curl -X POST http://localhost:5678/webhook/pd/generate -H 'Content-Type: application/json' -d '{"dry_run":true,
"products":[{"id":"x1","title":"Wool Throw","attributes":{"material":"Merino wool"},
"draft":{"description":"The best ever throw, warm for 10 years.","bullets":["Merino wool"]}}]}'
Common problems
- Good copy flagged "number not in product data": add the spec to the product's attributes (or options in Shopify); the check is deliberately strict.
- A product never gets new copy: products with a pending or rejected draft are skipped so a reviewer's queue isn't overwritten. Approve it, or regenerate with
force: true. - Shopify update fails: the access token needs
write_products; the product id must be the numeric id. - Copy sounds generic: make
voiceconcrete (sentence length, words you use and avoid) and add more facts per product.