Реалізація автоматичної генерації SEO-текстів для карток товарів (AI)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація автоматичної генерації SEO-текстів для карток товарів (AI)
Середня
~3-5 робочих днів
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація автоматичної генерації SEO-текстів для карточок товарів (AI)

Карточка товару без унікального тексту — це дублікат контенту від постачальника або шаблонна фраза з 30 слів. Ні те, ні те не ранжується пошуковиками. При каталозі від кількох тисяч позицій писати тексти вручну недоцільно — це завдання для автоматизації.

Генерація SEO-текстів через мовну модель вирішує цю задачу при правильній архітектурі: підготовлені промпти, контроль якості на виході, кешування та ревю перед публікацією.

Що на вході, що на виході

Вхід — структуровані дані товару: назва, категорія, характеристики, бренд, теги. Вихід — SEO-опис довжиною 150–600 слів з цільовими ключовими словами, природно вписаними в текст.

Приклад вхідних даних:

{
  "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"]
}

Prompt-інженерія для товарних текстів

Промпт — це не «напиши опис товару». Хороший промпт задає структуру, тон, довжину, вимоги до ключових слів та заборони:

function buildProductSeoPrompt(product: Product, keywords: string[]): string {
  return `
Напиши опис товару для каталогу е-комерції українською мовою.

Товар: ${product.name}
Категорія: ${product.category}
Бренд: ${product.brand}
Ключові характеристики: ${JSON.stringify(product.attributes)}
Теги: ${product.tags.join(", ")}

Вимоги:
- Довжина: 200–400 слів
- Включи ці ключові слова природно (не штучно): ${keywords.join(", ")}
- Структура: вступна заява користі → ключові особливості (3–5 пункти) → випадки використання → висновок
- Тон: інформативний, без пухнастості, без суперлативів типу «найкращий» чи «унікальний»
- НЕ використовуй: «цей товар», «представляємо твоєму виглядові», маркеровані списки
- НЕ починай з назви товару
- Пиши для людини, яка порівнює варіанти, а не для тієї, що вже вирішила

Вихід: простий текст, без markdown, без заголовків.
`.trim();
}

Пакетна обробка з черговими

Генерувати тексти синхронно неможливо — запит до GPT займає 3–10 секунд, а позицій можуть бути тисячі. Правильна схема — черга завдань:

// jobs/generate-seo-text.ts
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, // 5 паралельних запитів до API
  }
);

Контроль якості

Автоматично згенерований текст потребує валідації перед збереженням. Мінімальний набір перевірок:

interface ValidationResult {
  passed: boolean;
  issues: string[];
}

function validateSeoText(text: string, product: Product): ValidationResult {
  const issues: string[] = [];

  if (text.length < 500) {
    issues.push(`Занадто короткий: ${text.length} символів`);
  }

  // Перевіряємо наявність ключових слів
  const missingKeywords = product.targetKeywords.filter(
    (kw) => !text.toLowerCase().includes(kw.toLowerCase())
  );
  if (missingKeywords.length > 0) {
    issues.push(`Відсутні ключові слова: ${missingKeywords.join(", ")}`);
  }

  // Стоп-слова
  const stopPhrases = [
    "цей товар",
    "представляємо твоєму виглядові",
    "унікальний",
    "найкращий у своєму класі",
  ];
  for (const phrase of stopPhrases) {
    if (text.toLowerCase().includes(phrase)) {
      issues.push(`Містить стоп-фразу: "${phrase}"`);
    }
  }

  // Спам ключовими словами
  const wordCount = text.split(/\s+/).length;
  for (const kw of product.targetKeywords) {
    const kwCount = (text.toLowerCase().match(new RegExp(kw.toLowerCase(), "g")) || []).length;
    const density = kwCount / wordCount;
    if (density > 0.03) {
      issues.push(`Щільність ключового слова занадто висока для "${kw}": ${(density * 100).toFixed(1)}%`);
    }
  }

  return { passed: issues.length === 0, issues };
}

Тексти, що не пройшли валідацію, помічаються флагом needs_review та потрапляють у окрему чергу для повторної генерації з уточненим промптом.

Інтерфейс ревю

Редактор бачить список чернеток з можливістю прийняти, відхилити або редагувати:

GET /admin/seo-texts?status=draft&page=1
→ список карточок з текстом, кнопки: Опублікувати / Перегенерувати / Редагувати

POST /admin/seo-texts/:id/approve
→ змінює статус на published, оновлює карточку товару

POST /admin/seo-texts/:id/regenerate
→ додає завдання назад у чергу з позначкою attempt=2

Перегенерація з зворотним зв'язком — робітник читає причину відхилення та додає її до промпту:

if (job.data.rejectionReason) {
  prompt += `\n\nПопередня спроба була відхилена. Причина: ${job.data.rejectionReason}. Виправ це в новій версії.`;
}

Вартість і масштаб

GPT-4o-mini на момент написання коштує $0.15 за мільйон вхідних токенів і $0.60 за мільйон вихідних. Один товарний текст — приблизно 300–500 токенів на вході і 400–500 на виході. Разом близько $0.0004 за текст. 10 000 карточок — близько $4. Це робить масову генерацію економічно обґрунтованою навіть при частому оновленні каталогу.

При великому каталозі варто налаштувати тригер на оновлення атрибутів товару — якщо змінилася назва або ключові характеристики, текст автоматично помічається застарілим і ставиться на перегенерацію.