Автоматична генерація SEO-текстів карток товарів
Ми автоматизуємо генерацію SEO-описів для інтернет-магазинів, де каталог налічує тисячі позицій. Ручне написання унікальних текстів під кожен товар займе місяці та мільйони — наша система справляється за години. Але просто викликати API нейромережі недостатньо: потрібна продумана архітектура з підготовки даних, промпт-інжинірингу, пакетної обробки, валідації та інтерфейсу рев'ю. Маючи досвід понад 10 років у розробці високонавантажених систем, ми гарантуємо стабільність і якість генерації.
Чому це працює?
Сучасні мовні моделі — такі як ChatGPT (GPT-4o) та Claude — генерують осмислені тексти, якщо дати їм структуровані дані: назву, категорію, характеристики. Згідно з документацією OpenAI, контекстне навчання дозволяє адаптувати виведення під завдання. Промпт-інжиніринг задає тон, довжину, структуру та вимоги до ключових слів, щоб результат був релевантним та SEO-оптимізованим. Приклад для кросівок Nike Air Max 270:
{
"id": "SKU-4821",
"name": "Кроссовки Nike Air Max 270",
"category": "Мужская обувь / Кроссовки",
"brand": "Nike",
"attributes": { "material": "mesh + synthetic", "sole": "Air Max unit", "colors": ["black/white", "navy/grey"], "sizes": "40–46", "weight": "310g" },
"tags": ["беговые", "повседневные", "амортизация"],
"targetKeywords": ["nike air max 270 купить", "кроссовки найк аир макс 270"]
}
Як гарантується унікальність текстів?
Модель з температурою >0 завжди видає різний результат. Додатково ми перевіряємо кожну генерацію на дублі через Elasticsearch — якщо текст збігається з уже існуючим, запускаємо повторну генерацію з новим seed. Це виключає появу копій у каталозі. Такий підхід дозволяє зберігати унікальність навіть при масовій генерації.
Як ми проєктуємо промпти для товарних текстів?
Промпт — це не «напиши опис товару». Хороший промпт задає структуру, тон, довжину, вимоги до ключових слів і заборони. Приклад на TypeScript:
function buildProductSeoPrompt(product: Product, keywords: string[]): string {
return `
Write a product description for an e-commerce catalog in Russian.
Product: ${product.name}
Category: ${product.category}
Brand: ${product.brand}
Key attributes: ${JSON.stringify(product.attributes)}
Tags: ${product.tags.join(", ")}
Requirements:
- Length: 200–400 words
- Include these keywords naturally: ${keywords.join(", ")}
- Structure: opening benefit statement → key features (3–5 points) → use cases → closing
- Tone: informative, no hype, no superlatives like "лучший" or "уникальный"
- Do NOT use: "данный товар", "представляем вашему вниманию", bullet points
- Do NOT start with the product name
- Write for a person who is comparing options
Output: plain text, no markdown, no headings.
`.trim();
}
Чому важлива пакетна обробка з чергами?
Генерувати тексти синхронно не можна — запит до LLM займає 3–10 секунд, а позицій можуть бути тисячі. Ми використовуємо чергу завдань на BullMQ з паралелізмом і повторними спробами.
import { Queue, Worker } from "bullmq";
import { openai } from "../lib/openai";
import { db } from "../lib/db";
const seoQueue = new Queue("seo-generation", {
connection: { host: "localhost", port: 6379 },
});
export async function queueProductsForGeneration(productIds: string[]) {
const jobs = productIds.map((id) => ({
name: "generate",
data: { productId: id },
opts: { attempts: 3, backoff: { type: "exponential", delay: 5000 }, removeOnComplete: 100 },
}));
await seoQueue.addBulk(jobs);
}
const worker = new Worker("seo-generation", async (job) => {
const product = await db.products.findById(job.data.productId);
if (!product) return;
const keywords = await getTargetKeywords(product);
const prompt = buildProductSeoPrompt(product, keywords);
const completion = await openai.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: prompt }],
temperature: 0.7,
max_tokens: 600,
});
const text = completion.choices[0].message.content?.trim();
if (!text) throw new Error("Empty response");
await db.productSeoTexts.upsert({
productId: product.id,
text,
status: "draft",
model: "gpt-4o-mini",
generatedAt: new Date(),
});
}, { connection: { host: "localhost", port: 6379 }, concurrency: 5 });
Як обробляються помилки при генерації?
При збої запиту або порожній відповіді завдання автоматично переставляється в чергу з експоненціальною затримкою (backoff). Після трьох невдалих спроб товар позначається як failed і відправляється на ручну перевірку. Це забезпечує відмовостійкість і мінімізує втрати даних.
Контроль якості через валідацію
Згенерований текст автоматично перевіряється: довжина, наявність усіх ключових слів, відсутність стоп-фраз, щільність входжень. Якщо перевірка не пройдена — товар позначається флагом needs_review і відправляється на повторну генерацію з уточненим промптом.
interface ValidationResult { passed: boolean; issues: string[] }
function validateSeoText(text: string, product: Product): ValidationResult {
const issues: string[] = [];
if (text.length < 500) issues.push(`Too short: ${text.length} chars`);
const missingKeywords = product.targetKeywords.filter(kw => !text.toLowerCase().includes(kw.toLowerCase()));
if (missingKeywords.length > 0) issues.push(`Missing keywords: ${missingKeywords.join(", ")}`);
const stopPhrases = ["данный товар", "представляем вашему вниманию", "уникальный", "лучший в своём классе"];
for (const phrase of stopPhrases) {
if (text.toLowerCase().includes(phrase)) issues.push(`Contains stop phrase: "${phrase}"`);
}
const wordCount = text.split(/\s+/).length;
for (const kw of product.targetKeywords) {
const kwCount = (text.toLowerCase().match(new RegExp(kw.toLowerCase(), "g")) || []).length;
if (kwCount / wordCount > 0.03) issues.push(`Keyword density too high for "${kw}": ${(kwCount / wordCount * 100).toFixed(1)}%`);
}
return { passed: issues.length === 0, issues };
}
Інтерфейс рев'ю
Редактор бачить список чернеток з кнопками «Опублікувати», «Регенерувати», «Редагувати». Регенерація враховує причину попереднього відхилення — воркер додає її в промпт. Усі чернетки зберігаються у статусі draft, публікація відбувається тільки після підтвердження.
Порівняння: ручна генерація vs AI
| Параметр | Ручний копірайтинг | AI-генерація |
|---|---|---|
| Швидкість на 1 текст | 15–30 хвилин | 5–15 секунд |
| Вартість на 10 000 текстів | висока (залежить від авторів) | значно нижча |
| Масштабованість | лінійно зростає з числом авторів | паралельна черга |
| Контроль якості | залежить від виконавця | автоматична валідація |
| Актуальність | оновлювати вручну | тригер по зміні даних |
Приклад: для великого клієнта з сегменту одягу ми згенерували 12 000 описів за 4 години. Промпти враховували сезонність, стать, розмірну сітку. Після первинної генерації 8% текстів потрапили в needs_review через високу щільність ключових слів — після коригування промпта відсоток знизився до 2%. Фінальний запуск зайняв один день.
Етапи впровадження
| Етап | Опис | Строк |
|---|---|---|
| Аналіз | Збір структури даних, тестування промптів на вибірці | 1 тиждень |
| Розробка | Інтеграція LLM, черга, валідатори, інтерфейс рев'ю | 2–3 тижні |
| Тестування | Прогон на 500 товарах, ітеративне правлення промптів | 1 тиждень |
| Запуск | Генерація всього каталогу, навчання команди | 1 тиждень |
Що входить у реалізацію?
- Інтеграція з LLM (OpenAI, Claude) через API
- Система черг на BullMQ з повторними спробами та backoff
- Промпт-інжиніринг під вашу специфіку (категорії, тональність, ключі)
- Інтерфейс для рев'ю та модерації (React + TypeScript)
- Валідатори: довжина, ключові слова, стоп-слова, щільність
- Документація та навчання команди
- Підтримка протягом місяця після запуску
Строки та вартість
Строк реалізації — від 2 до 6 тижнів залежно від обсягу каталогу та складності інтеграції. Вартість розраховується індивідуально — чим більше товарів, тим дешевше кожен окремий текст. Оцінимо ваш проєкт? Зв'яжіться з нами — розкажемо, як знизити бюджет на SEO-контент у рази.
Замовте консультацію — ми проаналізуємо ваш каталог і підберемо оптимальну модель генерації. Отримайте прототип на ваших даних і оцініть ефект.







