Инструкция по настройке AGD Flow

Настройте publishing pipeline: сбор источников, RAG-контекст, AI-шаги, проверка и структурная публикация в WordPress или CMS.

🧭 Общая логика работы панели

AGD Flow работает как AI content pipeline для web publishing: вы подключаете сайт, подключаете AI-провайдера, готовите правила и ключевые слова, собираете шаблон pipeline, тестируете flow, а затем запускаете задачу публикации.

Начинайте с готового pipeline. Template может закрывать research, RAG, writing, review, Article Form mapping и публикацию в WordPress/CMS. После этого каждый шаг можно изменить под свои сайты, источники и редакционные правила.
Куда публикуете? Два разных пути:
WordPress — установите файл api.php в корень WordPress, см. раздел WordPress API.
OfferCMS / собственный CMS — установите клиентский комплект .cms, см. раздел Подключение сайта.
  1. 🌐 Domains — подключаете сайт, указываете API URL, токен и доменный AI-промпт.
  2. 🎨 Внешний шаблон сайта — после установки клиентского комплекта настройте .cms/temp: шапку, меню, карточки, сайдбар, стили, метрику и футер.
  3. 🤖 AI Providers — добавляете OpenAI, Gemini, Anthropic, xAI, DeepSeek, Qwen или Custom OpenAI-compatible API.
  4. 📝 Prompts — сохраняете повторяемые инструкции: SEO-правила, стиль, ограничения, формат статьи.
  5. 🔍 Keywords — создаёте наборы ключевых слов для генерации.
  6. ⚙️ Templates — собираете pipeline из шагов: поиск, парсинг, RAG, AI-генерация, обработка и финальная форма статьи.
  7. ▶️ Tasks — связываете домен, шаблон и набор ключей, выбираете режим публикации и запускаете задачу.
  8. 📝 Articles — смотрите, создаёте и редактируете статьи вручную, если это нужно.
Самая частая правильная последовательность: сначала сайт, токен и внешний шаблон .cms/temp, затем AI-провайдер, затем промпты и ключи, после этого pipeline-шаблон, тест pipeline и только потом рабочая задача.
Папку .cms/temp или весь клиентский комплект .cms можно загрузить в ИИ и попросить создать новый внешний шаблон, переделать дизайн под нишу, изменить карточки, меню, цвета, футер, статические страницы и рекламные/метрические вставки. Главное — не ломать системные переменные шаблона: $row, $posts, $post, $tophost, $incpage, $currentLang.

🌐 Подключение сайта и клиентского .cms

Для публикации статей на внешний сайт используется клиентский комплект .cms. Это маленькая CMS/API-часть, которая принимает публикации из панели, сохраняет статьи, изображения и дополнительные поля, а также отдаёт публичные URL.

Где взять комплект

  1. Откройте вкладку 🌐 Domains.
  2. Нажмите кнопку Скачать клиент (.zip).
  3. Распакуйте архив. Внутри будет комплект файлов сайта: index.php, classes/, pages/, temp/, vendor/ и другие служебные файлы.
Скачивайте актуальный клиентский архив кнопкой Скачать клиент (.zip) во вкладке Domains.

Вариант 1: установка в отдельную папку blog

  1. Создайте в корне нужного сайта папку blog.
  2. Скопируйте в неё содержимое клиентского архива.
  3. Проверьте, что API открывается по адресу https://example.com/blog/api.php.
  4. Если хостинг возвращает 404, настройте rewrite так, чтобы запросы внутри /blog/ обрабатывались клиентским index.php.
  5. В панели в настройках домена укажите API URL: https://example.com/blog/api.php.

Этот вариант безопаснее, если на домене уже есть сайт и вы не хотите смешивать файлы основной системы с клиентским комплектом.

Вариант 2: установка от корня сайта

  1. Скопируйте содержимое клиентского архива прямо в корень сайта.
  2. Используйте этот вариант только если сайт должен полностью работать на комплекте OfferCMS или если вы точно понимаете, какие файлы будут объединены с текущим сайтом.
  3. В панели в настройках домена укажите API URL: https://example.com/api.php.

API Token

  1. На сайте откройте файл classes/integration.php.
  2. В функции cms_get_api_token() замените стандартное значение на уникальную длинную строку.
  3. В панели откройте 🌐 Domains → Добавить домен или редактирование домена.
  4. В поле API Token вставьте ту же строку.
function cms_get_api_token(): string
{
    return 'your-unique-secret-token-here';
}
Панель отправляет публикации с заголовком Authorization: Bearer API_TOKEN. Если токен на сайте и токен в панели отличаются, публикация вернёт ошибку авторизации.

🌐 Domains — управление сайтами

Вкладка Domains отвечает за сайты, на которые панель будет публиковать готовые материалы.

  • Скачать клиент (.zip) — скачивает актуальный клиентский комплект для установки на сайт. Если появилась новая версия, рядом с кнопкой может отображаться отметка NEW.
  • Добавить домен — открывает форму подключения сайта.
  • ✏️ — редактирование домена.
  • 🗑️ — удаление домена из панели.

Поля домена

  • Домен — доменное имя без лишних параметров, например example.com.
  • API URL — полный адрес API клиента: https://example.com/api.php или https://example.com/blog/api.php.
  • API Token — секретная строка из cms_get_api_token() на сайте.
  • Системный промпт домена — правила именно для этого сайта: язык, тон, аудитория, тематика, структура, запреты и требования к публикациям.

Доменный промпт можно использовать внутри AI-шагов через переменную {{domain_aiprompt}}. Это удобно, когда один и тот же шаблон должен работать на разных сайтах с разной тематикой.

🤖 AI Providers — подключение моделей

AI-провайдеры вынесены отдельно от шаблонов. Благодаря этому один шаблон можно быстро переключать между разными ключами, аккаунтами и моделями.

Кнопки и действия

  • Добавить провайдера — создаёт новое подключение.
  • ✏️ — редактирует сохранённого провайдера.
  • 🧪 — отправляет тестовый запрос и показывает HTTP-код, модель, текст ответа и подсказки по ошибкам.
  • 🗑️ — удаляет провайдера. Если шаблон использовал этого провайдера, такой шаблон будет требовать внимания.

Поля провайдера

  • Тип провайдера — Gemini, OpenAI, Anthropic, xAI, DeepSeek, Qwen или Custom.
  • Название — понятное имя подключения. Можно оставить автоматически созданное или назвать по аккаунту/ключу.
  • Регион Qwen — появляется только для Qwen.
  • API URL — появляется для Custom OpenAI-compatible API.
  • Доступные модели — список моделей, по одной в строке. Именно из этого списка потом выбирается модель в LLM-шаге шаблона.
  • 🔄 Обновить список моделей — кнопка возле поля моделей. Она запрашивает каталог моделей у провайдера, показывает предпросмотр и позволяет вставить полученный список.
  • API ключ — ключ провайдера.
  • Активен — только активные провайдеры доступны для новых LLM-шагов.

Карточка провайдера показывает ID, тип, возможности, количество моделей, статус активности и возможную последнюю критическую ошибку: недостаточно средств, неверный ключ, rate limit, model not found, timeout и другие.

После добавления провайдера обязательно загрузите или вручную укажите модели. Если модель не сохранена в провайдере, её нельзя корректно выбрать в шаблоне.

📝 Prompts — глобальные правила

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

  • Создать промпт — добавляет новый reusable prompt.
  • Название — имя, по которому промпт будет вставляться в шаблон.
  • Содержимое — сам текст правил.
  • Категория — необязательная группировка, например seo, style, html, review.

В LLM-шаге промпт вставляется макросом:

{{prompt:"seo_article_rules"}}

Так можно держать большую стабильную инструкцию в одном месте и не копировать её вручную в каждый шаблон.

🔍 Keywords — наборы ключевых слов

Вкладка Keywords хранит базы ключевых слов. Одна задача может использовать один или несколько наборов.

  • Создать / добавить базу — создаёт новый набор или пополняет существующий.
  • Название базы — понятное имя набора, например Founders CRM EN или CBD Reviews PT.
  • Drag & drop .txt — загрузка файла со списком ключей.
  • Ручной ввод — вставка ключей в textarea, по одному ключу на строку.
  • Переименовать — меняет название выбранной базы.
  • Очистить — удаляет ключи внутри базы, но оставляет сам набор.
  • Удалить базу — удаляет набор полностью.

В pipeline текущий ключ доступен через переменную {{keyword}}. При запуске задачи система проходит по ключам выбранных наборов и для каждого ключа выполняет шаблон.

⚙️ Templates — сборка pipeline

Template — это схема генерации. Он описывает, что именно нужно сделать с ключевым словом: собрать выдачу, загрузить страницы, построить RAG-контекст, сгенерировать статью, извлечь поля и отправить финальные данные на публикацию.

Основные элементы окна шаблона

  • Название шаблона — имя pipeline в списке.
  • ТипНовые статьи, Обновление статей или Ключевые слова. После создания тип фиксируется, потому что он определяет обязательную финальную форму.
  • Палитра шагов — разделена на четыре группы: Функции, Источники, Логика и Результат. Это отделяет обработку данных, внешние источники, управляющие конструкции и финальную форму workflow.
  • Функции — ИИ, RegExp, преобразование, RAG-контекст, проверка текста и JavaScript.
  • Источники — поиск, новости, картинки, видео, извлечение статьи и HTML по URL.
  • Логика — IF/ELSE, WHILE, FOR EACH, объединение ветвей и STOP.
  • Результат — форма новой статьи, форма обновления статьи или форма ключевых слов в зависимости от типа шаблона.
  • Canvas — визуальная карта шагов. Карточки можно раскладывать удобнее для чтения.
  • − / + / 100% - масштаб canvas. Масштаб, позиция и фокус сохраняются при редактировании шага.
  • Маршрут выполнения - связи между карточками. Шаг можно перетащить, вставить в середину flow и явно назначить следующий переход.
  • К первой ошибке — помогает перейти к шагу, где макрос ссылается на отсутствующий или будущий шаг.
  • Показать/скрыть JSON редактор — ручное редактирование JSON шагов. Обычно удобнее работать визуально, JSON нужен для точечной правки или переноса шаблона.
Важно: расположение карточек на canvas и маршрут выполнения - не одно и то же. В graph-режиме порядок определяют поля next, on_true, on_false, on_pass, on_fail, body и after.

🧭 Типы шаблонов и задач

У каждого шаблона один тип workflow. В Tasks сначала выбирается тот же тип, после чего в списке остаются только совместимые шаблоны.

  • Новые статьи — входом служит ключевое слово. Финальная форма article_form собирает заголовок, описание, Markdown, изображение и дополнительные поля для новой публикации.
  • Обновление статей — входом служит существующая статья, выбранная на подключенном сайте. Финальная форма article_update_form готовит новую версию именно для этой статьи.
  • Ключевые слова — входом служат один или несколько seed-запросов. Финальная форма keywords_form нормализует сгенерированные строки и добавляет их в выбранный набор ключей.
Тип — это не просто подпись. Шаблон «Новые статьи» нельзя запустить для обновления существующих публикаций, а шаблон «Ключевые слова» не публикует статью.

Безопасность обновления статей

Шаблон обновления сохраняет ID статьи, slug, язык, статус и исходную дату публикации. Результат по умолчанию — Сначала показать изменения: генерация заканчивается, но сайт не меняется, пока в подробностях задачи не выбраны Применить или Пропустить.

Перед применением панель проверяет, не менялась ли исходная статья после попадания в очередь. Если менялась, возникает конфликт вместо перезаписи ручной правки. Применённую версию можно откатить, пока доступен её снимок.

🧱 Типы шагов pipeline

🤖 ИИ

LLM-шаг отправляет промпт выбранному AI-провайдеру и сохраняет текстовый ответ в output шага.

  • ID шага — короткое имя, например query_plan, article_mode, final_article.
  • Провайдер — активное подключение из AI Providers.
  • Тип — текст, text batch, картинки, видео или музыка, если провайдер поддерживает такие возможности.
  • Модель — выбирается из списка моделей провайдера.
  • Рольuser или system.
  • Глобальный промпт — удобный выбор сохранённого prompt, который вставляется макросом.
  • Промпт — основной текст инструкции. В нём можно использовать переменные и результаты предыдущих шагов.
  • Переменные — кнопка возле поля промпта, которая вставляет доступные макросы.
  • Вставить блок кеша — оборачивает стабильную часть промпта в AIPANEL_CACHE. Подробности и ограничения описаны в разделе кеширования.
  • Температура — уровень вариативности ответа. Оставьте Авто, чтобы модель использовала значение по умолчанию.
  • Лимит токенов ответа — ограничение длины ответа.
  • Рассуждение — дополнительное усилие для моделей, которые это поддерживают. Подробнее в разделе «Рассуждение и thinking».
  • Дополнительные параметры запроса — показываются только для подключения Custom API. Здесь задаются только не системные параметры конкретного провайдера.
  • Ожидание batch, секунд — появляется для text batch. Batch дешевле, но результат может прийти позже.

🔎 / 📰 / 🖼️ / 🎞️ Источники

Collector-шаги получают данные из поисковой выдачи, новостей, картинок, видео или по конкретным URL.

  • Новости — новостная выдача.
  • Картинки — поиск изображений.
  • Видео — YouTube или Yandex video.
  • Статья по URL — загружает страницы по указанным URL и извлекает основное содержимое для следующих шагов pipeline.
  • HTML по URL — загружает исходный HTML страницы по URL, когда следующему шагу нужна полная разметка, а не только очищенный текст статьи.
  • Источник запроса — ключ, текст или переменная предыдущего шага, например {{keyword}} или {{step.query_plan.output}}.
  • Лимит результатов SERP — сколько результатов брать на запрос, от 1 до 100.

Выход поисковых collector-шагов — структурированный объект: results, related, total_items. У результатов есть query, rank, link, title, content, date, thumb. Шаг Статья по URL возвращает массив документов с основным текстом, заголовком и ссылкой.

🧪 Обработка / RegExp

Regexp-шаг извлекает или заменяет фрагменты текста.

  • Источник — строка или output предыдущего шага.
  • Паттерн — регулярное выражение.
  • Флаги — модификаторы регулярного выражения.
  • Извлечь первое совпадение — берёт первое найденное значение.
  • Извлечь все совпадения — возвращает список совпадений через перенос строки.
  • Заменить совпадения — выполняет замену по регулярке.

🧩 Преобразование

Transform-шаг чистит и подготавливает данные между collector и AI-шагами.

  • Удалить дубли строк, Объединить в одну строку, Обрезать по символам, Перемешать массив, Обрезать массив, Убрать HTML, Trim.
  • Извлечь из JSON — берёт нужный фрагмент из JSON.
  • Строку в массив и Массив в JSON — меняют формат данных для следующих шагов.

📚 Создать RAG контекст

Самостоятельная функция в палитре Функции. Она собирает компактный evidence-контекст из документов, полученных шагом Статья по URL.

В настройках RAG можно ограничить общий объём контекста, количество источников, объём материалов с одного сайта и размер обрабатываемых фрагментов.

RAG собирает наиболее полезные фрагменты найденных материалов в компактный контекст для следующего AI-шага. Он не публикует материал самостоятельно.

🔀 IF/ELSE и маршруты

Шаг IF/ELSE сравнивает левое и правое значения и выбирает on_true или on_false. Поддерживаются операторы eq, neq, lt, lte, gt, gte, contains, not_contains, empty, not_empty, regex, truthy, falsy.

🛡️ Проверка текста

Выберите сервис проверки, задайте допустимый порог и настройте маршруты для трёх результатов: проверка пройдена, не пройдена или произошла ошибка.

🔁 WHILE и FOR EACH

WHILE повторяет ветку, пока условие истинно и не достигнут max_iterations. FOR EACH обходит массив из items_source. Внутри тела доступны {{loop.item}}, {{loop.index}}, {{loop.iteration}} и варианты с ID цикла, например {{loop.section_loop.iteration}}. Последний шаг тела обязан маршрутом вернуться в loop; после завершения выполняется after.

Повторный запуск шага перезаписывает его обычный output. Если нужно сохранить все результаты FOR EACH, накапливайте массив отдельным JavaScript-шагом, как в готовом примере Example - FOR EACH Sections.

🧩 JavaScript

JavaScript-шаг получает input, outputs в steps, безопасный context и helpers clone, jsonParse, jsonStringify, toArray, unique. Запрещены сеть, файловая система, process/runtime API, imports, eval, async/Promise и доступ к prototype. Ограничиваются время выполнения, размер кода и размер результата.

⋈ Merge и ■ STOP

Merge не запускает ветви параллельно. Это общая точка продолжения, которая получает результат реально пришедшей ветви в merge.output. STOP завершает текущий маршрут и сохраняет причину остановки в журнале.

📝 Форма статьи

Финальный шаг для публикации. Он собирает данные из предыдущих шагов в структуру статьи.

  • Заголовок статьи — например {{step.title_extract.output}}.
  • Описание статьи — meta description или краткое описание.
  • Изображение — URL главного изображения или переменная из image-шагов.
  • Содержимое (Markdown) — готовый текст статьи.
  • Дополнительные поля — пары ключ/значение, которые уйдут в xfields_json.
Slug и язык обычно формируются при публикации. В задаче можно принудительно указать Язык / раздел URL, например en, pt, blog или reviews.

🔄 Форма обновления статьи

Финальный шаг шаблона обновления. Он сопоставляет сгенерированные заголовок, описание, Markdown и дополнительные поля с существующей статьёй перед применением или проверкой изменений.

🔑 Форма ключевых слов

Финальный шаг шаблона ключевых слов. Он принимает массив найденных или сгенерированных ключей и передаёт их в выбранный набор ключевых слов.

🔗 Переменные и макросы

Макросы связывают шаги между собой. Они подставляют ключевое слово, домен, доменный промпт, глобальные промпты и output предыдущих шагов.

  • {{keyword}} — текущее ключевое слово.
  • {{domain}} — домен сайта.
  • {{domain_aiprompt}} — системный промпт домена.
  • {{prompt:"prompt_name"}} — глобальный промпт из вкладки Prompts.
  • {{step.step_id.output}} — полный выход предыдущего шага.
  • {{step.images.1.link}}, {{step.search.output}} и похожие переменные — конкретные поля структурированных результатов, если они доступны.

Входные переменные по типу workflow

  • Новые статьи — используйте {{keyword}} вместе с доменными переменными выше.
  • Обновление статей — доступны {{article.id}}, {{article.url}}, {{article.slug}}, {{article.lang}}, {{article.title}}, {{article.description}}, {{article.markdown}}, {{article.main_image}}, {{article.xfields_json}}, {{article.published_at}}, {{article.updated_at}} и {{article.age_days}}.
  • Ключевые слова — используйте {{seed.keyword}} и {{seed.set_name}}. Доменные переменные доступны, если в задаче выбран домен.

Кнопка Переменные в редакторе шага показывает доступные макросы с учётом текущего шага и предыдущих результатов.

Уже вставленная переменная выделяется цветом. Если один макрос использован несколько раз, рядом показывается количество вхождений. Макросы можно вставлять подряд без принудительного переноса строки, например {{keyword}}{{domain}}.

Если после изменения порядка выполнения шаг начинает ссылаться на будущий или удалённый шаг, шаблон получает статус Требует внимания. Исправьте макрос или порядок выполнения перед запуском задачи.

🧭 Маршруты, ограничения и проверка JSON

Явные переходы

  • next - следующий шаг для ИИ, collector, RegExp, transform, JavaScript, Merge и формы статьи.
  • on_true / on_false - две ветви IF/ELSE.
  • on_pass / on_fail / on_error - маршруты проверки текста.
  • body / after - тело цикла и маршрут после завершения.
  • stop или end в качестве target завершает маршрут без отдельной карточки STOP.

Для новых шаблонов указывайте маршруты явно: так порядок выполнения остаётся понятным при добавлении ветвей и циклов.

Проверка перед сохранением

Редактор и backend не сохраняют граф с пустыми или повторяющимися ID, отсутствующими target, незамкнутым телом loop или циклом, который не проходит через ограниченный loop. Во время выполнения действует дополнительный предел на общее число посещённых узлов. Для loop разрешено от 1 до 1000 итераций; для JavaScript - 50-5000 мс и ограниченный размер output.

Проверка JSON

steps_json и xfields_json проверяются строгим jsonlint-совместимым валидатором. Ошибка содержит понятное описание, строку и контекст, а повторяющиеся JSON-ключи считаются ошибкой. Корень steps_json должен быть массивом шагов; xfields_json должен быть объектом или массивом. Макросы внутри xfields_json разрешены и проверяются до подстановки.

Перед запуском выберите активного провайдера и подходящую модель в каждом AI-шаге.

🧠 Рассуждение и thinking

Некоторые текстовые модели могут потратить дополнительные токены на планирование перед тем, как вернуть итоговый текст. В панели это называется Рассуждение. Оно может улучшить сложные инструкции, структурированные тексты и многошаговый анализ, но увеличивает время и стоимость.

  • Авто — не отправляет принудительную настройку. Это обычный вариант для существующих шаблонов: провайдер сам выбирает стандартное поведение модели.
  • Выключено — просит совместимую модель отключить reasoning. Некоторые современные модели этого не разрешают; шаг остановится с понятной причиной, а не изменит запрос скрытно.
  • Минимальное, Низкое, Среднее, Высокое, Очень высокое, Максимальное — уровни усилия, которые переводятся в API выбранного провайдера. Начинайте с Низкого или Среднего и тестируйте шаблон до массового запуска.
  • Бюджет рассуждений — доступен только там, где API и модель принимают числовой thinking budget. Оставьте поле пустым для значения по умолчанию у провайдера.

В output шага всегда попадает только итоговый ответ. Внутреннее рассуждение не передается в следующие шаги, журналы задачи, RAG и публикацию.

Поддержка reasoning зависит от конкретной модели. Одно подключение может работать с одной моделью и отклонять настройку у другой, поэтому выберите точную модель и сначала сделайте короткий тест шаблона.

Параметры Custom API

Для Custom API доступны Дополнительные параметры запроса типов Строка, Число, Да/Нет и JSON. Они нужны для документированных параметров провайдера, например формата ответа или sampling-настроек. Панель защищает model, prompt, authentication, endpoint, stream, reasoning и token limits; для них используйте основные поля LLM-шага.

💰 Кеширование промптов (AIPANEL_CACHE)

AIPANEL_CACHE - это разметка стабильной части промпта. Панель использует ее только там, где это безопасно и поддерживается выбранным провайдером. Если провайдер или режим не поддерживает кеш, маркеры удаляются перед запросом, а сам текст промпта остается.

Как это работает по провайдерам

  • Google Gemini - платный explicit context cache через cachedContents в панели отключен. Для Gemini маркеры AIPANEL_CACHE вырезаются перед запросом, объект кеша у Google не создается. Это относится и к text batch. Автоматический implicit cache, если он применим у Google, работает без действий пользователя.
  • OpenAI / xAI / DeepSeek - используют автоматический prompt cache провайдера, когда повторяется стабильный префикс промпта.
  • Anthropic Claude - использует короткий ephemeral cache. Он подходит для близких по времени запусков и не рассчитан на долгосрочное хранение.
  • Qwen - поведение зависит от конкретного API и модели; если кеш не применяется, запрос уходит обычным промптом без маркеров.

Когда это выгодно

Кеширование имеет смысл, если один и тот же большой стабильный блок повторяется во многих запросах: SEO-правила, стиль, структура статьи, запреты, формат ответа. Экономия не гарантируется: итог зависит от провайдера, модели, размера блока и частоты повторов.

Как использовать

В редакторе LLM-шага есть кнопка Вставить блок кеша. Она оборачивает выделенную часть промпта в маркеры. Можно также вставить вручную:

<!-- AIPANEL_CACHE -->
Здесь - постоянные правила, которые не меняются от запроса к запросу:
- SEO-требования, стиль, структура, запреты, формат ответа
<!-- AIPANEL_CACHE_END -->

Keyword: {{keyword}}
Domain rules: {{domain_aiprompt}}
Research context: {{step.rag_context.output}}
Важное правило: не считайте AIPANEL_CACHE гарантированной экономией. Это только разметка стабильного блока. Перед массовыми запусками проверьте биллинг и документацию выбранного провайдера.

🧪 Тестирование шаблона

Перед рабочим запуском протестируйте шаблон прямо в окне Templates. Поля теста зависят от типа шаблона.

  • Новые статьи — выберите подключённый домен, затем одно ключевое слово из его набора или введите его вручную.
  • Обновление статей — выберите подключённый домен и одну существующую статью. Панель проверяет соединение и читает актуальные данные статьи для макросов {{article.*}}, но не изменяет её.
  • Ключевые слова — введите один seed-запрос или выберите его из набора. Домен для такого теста необязателен.

После выбора входных данных нажмите Запустить тест.

Во время теста панель показывает прогресс по шагам. После выполнения можно открыть отладку шага и посмотреть входные данные, итоговый промпт, ответ провайдера, результат regexp/transform, RAG-контекст и финальную структуру статьи.

Тестовый запуск нужен не только для проверки текста. Он помогает увидеть, правильно ли подставились макросы, есть ли результаты поиска, загрузились ли URL, хватает ли модели токенов и корректно ли собрана финальная форма. Тест не публикует материал, не изменяет статью и не добавляет ключи в набор.

▶️ Tasks — запуск генерации и публикации

Задача запускает сохранённый шаблон по зафиксированной очереди входных данных. Сначала выберите тип: Новые статьи, Обновление статей или Ключевые слова.

Создание задачи

  • Тип — определяет доступные поля ввода и совместимые шаблоны.
  • Домен — сайт, куда публикуем.
  • Шаблон — pipeline генерации. Шаблоны со статусом Требует внимания нельзя запускать, пока не исправлены провайдеры или макросы.
  • Наборы ключевых слов — можно выбрать один или несколько. Если оставить пусто, задача запускается без ключей.
  • Режим публикации — сразу все, только N статей или отложенный режим.
  • Количество статей для публикации — используется в режиме лимита.
  • Количество статей / Период (часы) — используется в отложенном режиме.
  • Язык / раздел URL — принудительный сегмент URL, например en, pt, blog, reviews.
  • Пропускать использованные ключевые слова — защищает от повторной генерации по уже обработанным ключам.
  • Информировать Google и Информировать Bing — отправляет уведомления после успешной публикации.

Входные данные по типам

  • Новые статьи — выберите один или несколько наборов ключей и режим: сразу, с лимитом или по расписанию.
  • Обновление статей — выберите статьи вручную через поиск и постраничный список, статьи старше указанного числа месяцев или диапазон даты публикации. Дополнительно доступны фильтры языка и статуса, а также лимит количества статей. В очереди сохраняются выбранные ID, а полный текст заново загружается непосредственно перед обработкой.
  • Ключевые слова — введите seed-запросы вручную или используйте существующие наборы. Выберите набор назначения либо укажите название нового.
Для обновления статей по умолчанию включена проверка. Статус Ожидает проверки означает, что новая версия готова, но ещё не применена на сайте.

Статистика и статусы

  • Всего, В работе, Завершено, Ошибок — общая статистика задач.
  • Слотов — доступные, занятые и свободные слоты выполнения.
  • Не хватает — сколько задач ждут свободных слотов.
  • Ожидает, В работе, Ждет batch, Ожидает проверки, Завершено, Ошибка, Приостановлено, Отменено — основные состояния задачи.

Действия с задачей

  • Подробности — показывает прогресс, результаты, URL, ошибки, поисковые уведомления и лог выполнения. У обновления статей здесь доступны исходная и предложенная версии, а также действия «Применить», «Пропустить» и «Откатить», если они доступны.
  • Редактировать — меняет параметры задачи.
  • Приостановить — останавливает дальнейшее выполнение.
  • Возобновить/перезапустить — продолжает или повторно запускает задачу, если есть свободный слот.
  • Отменить — отменяет выполнение.
  • Удалить задачу — удаляет задачу и связанные данные.

📝 Articles — ручная работа со статьями

Вкладка Articles нужна для просмотра и ручной правки материалов. Она полезна, если статью нужно создать без pipeline или проверить уже готовые записи.

  • Фильтр домена — показывает статьи конкретного сайта.
  • Фильтр статуса — draft, ready for review или published.
  • Обновить — перезагружает список.
  • Создать статью — открывает ручную форму статьи.

Поля статьи

  • Статус — черновик, готово к проверке или опубликовано.
  • Язык — например en, pt, ru.
  • Slug — URL-часть статьи.
  • Заголовок — H1/title статьи.
  • Описание — meta description или краткое описание.
  • Содержимое — Markdown-контент.
  • Главное изображение — загрузка файла, вставка URL или base64.
  • Дополнительные поля — произвольные поля, которые сохраняются в JSON.

🎨 .cms/temp — внешний шаблон сайта

Папка .cms/temp — это не pipeline-шаблон из вкладки Templates, а внешний шаблон сайта. Именно здесь настраивается то, как опубликованные статьи будут выглядеть для посетителя: шапка, меню, главная/листинг, карточки постов, страница статьи, сайдбар, футер, цвета, CSS, метрика и рекламные вставки.

Вкладка ⚙️ Templates в панели отвечает за генерацию контента. Папка .cms/temp на сайте отвечает за внешний вид опубликованного сайта. Это две разные части системы, и обе нужно настроить.

Главные файлы шаблона

  • temp/temp.php — основной HTML-шаблон сайта. В нём обычно настраиваются <head>, title/description, canonical, JSON-LD, шапка, меню, главный контейнер, вывод статьи, вывод сайдбара и футер.
  • temp/css/style.css — стили сайта: цвета, ширина контейнера, карточки, меню, типографика, адаптивность, кнопки, пагинация, сайдбар.
  • temp/short.php — маленькая карточка статьи для главной, языковых страниц, листингов и пагинации.
  • temp/sidebar.php — карточка похожей/случайной статьи в боковом блоке на странице публикации.
  • temp/metric.php — счётчики, аналитика, рекламные скрипты, пиксели и другие вставки перед закрытием </head> или внутри шаблона.
  • pages/ — статические страницы: about, contact, privacy, terms, cookies, disclaimer, legal. Их тоже нужно адаптировать под конкретный сайт.

Что обязательно поменять под свой сайт

  1. Откройте .cms/temp/temp.php.
  2. Замените название сайта, например $siteName, $defaultTitle и $siteTagline.
  3. Проверьте пункты меню: Home, Blog, About, Contact, Privacy, Terms. Уберите лишнее или добавьте нужные разделы.
  4. Проверьте тексты hero-блока на главной/листинге. Они должны соответствовать нише сайта, языку и аудитории.
  5. Проверьте футер: название проекта, описание, контакты, юридические ссылки.
  6. Откройте .cms/temp/css/style.css и настройте палитру в блоке :root: фон, основной цвет, акцент, ширина контейнера, радиусы, отступы.
  7. Откройте .cms/temp/metric.php и замените или удалите чужие счётчики, рекламные коды и пиксели. Нельзя оставлять чужой Google AdSense, Yandex.Metrika или другие чужие ID.
  8. Откройте файлы в .cms/pages/ и замените стандартные тексты на страницы конкретного проекта.

Настройка формы обратной связи через Telegram

Важно: форма на странице contact отображается сразу, но по умолчанию отправка отключена. Пока владелец сайта не укажет данные своего Telegram-бота, посетитель получит сообщение о том, что форма не настроена, а его сообщение никуда не отправится.
  1. Создайте собственного бота через @BotFather и получите токен бота.
  2. Отправьте боту любое сообщение, затем получите ID нужного личного чата или группы через метод Telegram getUpdates.
  3. Откройте файл .cms/classes/send.php.
  4. Укажите токен в переменной $telegram_api_token, а ID чата в переменной $chat_id.
  5. Откройте страницу contact на сайте и отправьте тестовое сообщение. Оно должно появиться только в указанном вами Telegram-чате.
$telegram_api_token = 'YOUR_TELEGRAM_BOT_TOKEN';
$chat_id = 'YOUR_TELEGRAM_CHAT_ID';
Не размещайте токен в pages/, temp/, JavaScript или публичном репозитории. Если токен стал известен посторонним, перевыпустите его через @BotFather. Укажите обработку формы и передачу имени, email, сообщения, IP и домена в Telegram в политике конфиденциальности сайта.

Какие данные доступны внутри шаблона

  • $row['title'] — заголовок текущей страницы или статьи.
  • $row['description'] — meta description или краткое описание.
  • $row['html_content'] — готовый HTML статьи или список карточек на главной/листинге.
  • $row['image_url'] — главное изображение статьи, если оно передано или найдено системой.
  • $row['date'] / $row['public_date'] — дата публикации, если она есть в записи.
  • $row['sidebar'] — HTML сайдбара со случайными/похожими статьями, если он был собран.
  • $posts — массив постов на главной, языковой странице или странице пагинации.
  • $post — один пост внутри short.php или sidebar.php.
  • $tophost, $hostname, $incpage, $currentLang, $pagePath — служебные переменные URL, домена, языка и текущей страницы.
Если меняете short.php или sidebar.php, помните: там используется переменная $post. Если меняете temp.php, основная переменная страницы — $row.

Как движок использует файлы temp

  1. Для главной страницы и страниц пагинации движок собирает список опубликованных материалов, каждый материал прогоняет через short.php, а затем выводит общий результат через temp.php.
  2. Для страницы статьи движок загружает статью, подготавливает $row['html_content'], собирает $row['sidebar'] через sidebar.php и затем подключает temp.php.
  3. Если в папке шаблона есть fullpage.php, он может использоваться для отдельных внутренних страниц вместо стандартного temp.php.
  4. metric.php обычно подключается из temp.php, поэтому все счётчики и рекламные скрипты удобно держать в одном отдельном файле.

Минимальный чек-лист перед публикацией

  • Открывается главная страница сайта.
  • Открывается статья по публичному URL.
  • Картинки не ломают верстку на телефоне.
  • Меню ведёт на существующие страницы.
  • В футере нет чужого бренда, чужих ссылок и тестового текста.
  • В metric.php нет чужих ID рекламных сетей и аналитики.
  • В .cms/classes/send.php указаны данные собственного Telegram-бота, и тестовое сообщение получено.
  • В исходном коде страницы есть нормальные title, meta description, canonical и, если нужно, JSON-LD.
  • Страницы privacy, terms, contact, about заполнены под конкретный сайт.

WordPress API — подключение моста

Для публикации на сайты под управлением WordPress используется специальный мост api.php. Панель отправляет публикации, проверяет уникальность URL, обновляет записи и загружает медиафайлы через этот файл.

Установка и настройка

  1. Скачайте файл плагина/моста: в шапке документации или в настройках домена выберите Скачать клиент WordPress (требуется авторизация).
  2. Скопируйте скачанный файл api.php в корневую директорию вашей установки WordPress (туда, где находится wp-load.php).
  3. Откройте файл wp-config.php вашего WordPress и добавьте секретный токен:
    define('AIPANEL_API_TOKEN', 'ваш-сложный-секретный-токен');
  4. В панели управления AGD Flow при добавлении домена укажите:
    • API URL: https://yourdomain.com/api.php
    • API Token: тот же токен, который вы указали в wp-config.php

Возможности моста

  • Действия (actions): поддерживает проверку связи (ping), публикацию статьи (publish_post), редактирование (edit_post), удаление (delete_post) и проверку занятости slug (check_slug).
  • Поддержка SEO-плагинов: автоматически записывает SEO-заголовок и описание в мета-поля популярных плагинов Yoast SEO (_yoast_wpseo_title, _yoast_wpseo_metadesc) и Rank Math (rank_math_title, rank_math_description).
  • Категории и теги: поддерживает передачу массивов категорий и тегов в поле xfields_json (структура: {"categories": ["Категория 1", "Категория 2"], "tags": ["Тег 1", "Тег 2"]}). Если категорий или тегов нет на сайте, они будут созданы автоматически.
  • Типы записей (Custom Post Types): по умолчанию публикации создаются как стандартные посты (post). Вы можете переопределить это, передав тип записи в xfields_json (например, {"post_type": "product"} или {"post_type": "page"}).
  • Изображения: автоматически скачивает главное изображение по ссылке или декодирует base64-строку, создавая вложение в медиабиблиотеке WordPress и устанавливая его в качестве "Featured Image" (изображения записи).

📋 Примеры готовых JSON Pipeline

Здесь представлены готовые шаблоны pipeline в формате JSON, которые вы можете импортировать через кнопку Показать/скрыть JSON-редактор во вкладке ⚙️ Templates.

1. Простая SEO статья (Simple SEO Article)

Минимальный шаблон: отправляет промпт в ИИ, вырезает теги заголовка, описания и контента с помощью RegExp, а затем передает их в форму публикации.

[
  {
    "id": "draft_article",
    "type": "llm",
    "provider_id": 0,
    "ai_capability": "text",
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Keyword: {{keyword}}\nDomain: {{domain}}\n\n{{domain_aiprompt}}\n\n\n{{prompt:\"seo_article_rules\"}}\n{{prompt:\"article_output_contract\"}}\n\nWrite a practical SEO article for the keyword. Vary the number of sections naturally; include FAQ only when it helps the topic.\n",
    "temperature": 0.4,
    "max_tokens": 4096,
    "output_key": "output"
  },
  {
    "id": "extract_title",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.draft_article.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "extract_description",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.draft_article.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "extract_content",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.draft_article.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "article",
    "type": "article_form",
    "title": "{{step.extract_title.output}}",
    "description": "{{step.extract_description.output}}",
    "markdown": "{{step.extract_content.output}}",
    "lang": "{{domain_lang}}",
    "slug": "",
    "main_image": "",
    "xfields_json": "[]",
    "public": 1
  }
]

2. Расширение ключевых слов (Keyword Expansion)

Шаблон типа "Keywords" для генерации связанных тем на основе одного главного ключа.

[
  {
    "id": "expand_keywords",
    "type": "llm",
    "provider_id": 0,
    "ai_capability": "text",
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Seed keyword: {{keyword}}\nDomain: {{domain}}\n\n{{domain_aiprompt}}\n\n\nGenerate 20 useful long-tail keyword ideas for content planning. Keep them specific, natural, and suitable for article topics.\nReturn one keyword per line, no numbering, no commentary.\n",
    "temperature": 0.35,
    "max_tokens": 2048,
    "output_key": "output"
  },
  {
    "id": "keywords",
    "type": "transform",
    "operation": "split_to_array",
    "arg1": "{{step.expand_keywords.output}}",
    "delimiter": "\n",
    "array_limit": 20,
    "output_key": "output"
  }
]

3. Обзорный Affiliate-шаблон с поиском и RAG (Advanced)

Сложный шаблон для написания обзоров товаров и сервисов: делает запросы в Google, скачивает контент страниц, строит контекст (RAG) и отдает на вход ИИ.

[
  {
    "id": "affiliate_queries",
    "type": "llm",
    "provider_id": 0,
    "ai_capability": "text_batch",
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Affiliate review idea: {{keyword}}\nDomain: {{domain}}\n\n{{domain_aiprompt}}\n\n\nGenerate 5 focused web search queries that support an affiliate review. Return one query per line only.\n",
    "temperature": 0.2,
    "max_tokens": 1024,
    "output_key": "output"
  },
  {
    "id": "affiliate_split_queries",
    "type": "transform",
    "operation": "split_to_array",
    "arg1": "{{step.affiliate_queries.output}}",
    "delimiter": "\n",
    "array_limit": 5,
    "output_key": "output"
  },
  {
    "id": "affiliate_search",
    "type": "collector",
    "channel": "web",
    "engine": "google",
    "query_source": "{{step.affiliate_split_queries.output}}",
    "serp_limit": 5,
    "output_key": "output",
    "concurrency": 6
  },
  {
    "id": "affiliate_slice_search_results",
    "type": "transform",
    "operation": "slice_array",
    "arg1": "{{step.affiliate_search.output}}",
    "array_limit": 3,
    "output_key": "output"
  },
  {
    "id": "affiliate_html",
    "type": "collector",
    "channel": "article",
    "engine": "article",
    "query_source": "{{step.affiliate_slice_search_results.output}}",
    "output_key": "output"
  },
  {
    "id": "affiliate_rag",
    "type": "transform",
    "operation": "rag_builder",
    "arg1": "{{step.affiliate_html.output}}",
    "array_limit": 5,
    "output_key": "output",
    "max_total_chars": 16000,
    "max_sources": 10,
    "chunk_size": 900
  },
  {
    "id": "affiliate_generate",
    "type": "llm",
    "provider_id": 0,
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Keyword: {{keyword}}\nDomain: {{domain}}\nResearch context:\n{{step.affiliate_rag.output}}\n\n{{domain_aiprompt}}\n\nWrite a practical affiliate review. Format output inside tags:\n<TITLE>[title]</TITLE>\n<DESCRIPTION>[description]</DESCRIPTION>\n<CONTENT>[content]</CONTENT>",
    "temperature": 0.45,
    "max_tokens": 6144,
    "output_key": "output"
  },
  {
    "id": "affiliate_extract_title",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.affiliate_generate.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "affiliate_extract_description",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.affiliate_generate.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "affiliate_extract_content",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.affiliate_generate.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "affiliate_article",
    "type": "article_form",
    "title": "{{step.affiliate_extract_title.output}}",
    "description": "{{step.affiliate_extract_description.output}}",
    "markdown": "{{step.affiliate_extract_content.output}}",
    "lang": "{{domain_lang}}",
    "slug": "",
    "main_image": "",
    "xfields_json": "[]",
    "public": 1
  }
]

4. Статья с исследованием и RAG (Research + RAG Article)

Пайплайн статьи на основе исследования: генерирует поисковые запросы, опрашивает Google, загружает страницы источников, строит RAG-контекст и пишет обоснованную статью.

[
  {
    "id": "research_queries",
    "type": "llm",
    "provider_id": 0,
    "ai_capability": "text_batch",
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Ключевое слово: {{keyword}}\nДомен: {{domain}}\n\n{{domain_aiprompt}}\n\n\nСгенерируйте 6 целевых поисковых запросов, которые поддерживают информативную статью по ключевому слову. Верните по одному запросу на строку, без нумерации и комментариев.\n",
    "temperature": 0.2,
    "max_tokens": 1024,
    "output_key": "output"
  },
  {
    "id": "research_split_queries",
    "type": "transform",
    "operation": "split_to_array",
    "arg1": "{{step.research_queries.output}}",
    "delimiter": "\n",
    "array_limit": 6,
    "output_key": "output"
  },
  {
    "id": "research_search",
    "type": "collector",
    "channel": "web",
    "engine": "google",
    "query_source": "{{step.research_split_queries.output}}",
    "serp_limit": 5,
    "output_key": "output",
    "concurrency": 6
  },
  {
    "id": "research_slice",
    "type": "transform",
    "operation": "slice_array",
    "arg1": "{{step.research_search.output}}",
    "array_limit": 4,
    "output_key": "output"
  },
  {
    "id": "research_html",
    "type": "collector",
    "channel": "article",
    "engine": "article",
    "query_source": "{{step.research_slice.output}}",
    "output_key": "output"
  },
  {
    "id": "research_rag",
    "type": "transform",
    "operation": "rag_builder",
    "arg1": "{{step.research_html.output}}",
    "array_limit": 5,
    "output_key": "output",
    "max_total_chars": 16000,
    "max_sources": 10,
    "chunk_size": 900
  },
  {
    "id": "research_writer",
    "type": "llm",
    "provider_id": 0,
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Ключевое слово: {{keyword}}\nДомен: {{domain}}\nКонтекст исследования:\n{{step.research_rag.output}}\n\n{{article_structure_hint}}\n\n{{domain_aiprompt}}\n\n\nНапишите практическую статью на основе предоставленного контекста. Опирайтесь на источники; не выдумывайте факты. Оформите вывод внутри тегов:\n<TITLE>[заголовок]</TITLE>\n<DESCRIPTION>[мета-описание]</DESCRIPTION>\n<CONTENT>[полный текст статьи в markdown]</CONTENT>\n",
    "temperature": 0.45,
    "max_tokens": 6144,
    "output_key": "output"
  },
  {
    "id": "research_extract_title",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.research_writer.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "research_extract_description",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.research_writer.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "research_extract_content",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.research_writer.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "research_article",
    "type": "article_form",
    "title": "{{step.research_extract_title.output}}",
    "description": "{{step.research_extract_description.output}}",
    "markdown": "{{step.research_extract_content.output}}",
    "lang": "en",
    "slug": "",
    "main_image": "",
    "xfields_json": "[]",
    "public": 1
  }
]

5. Мультиязычная публикация (Multilingual Publishing)

Публикует одну статью на двух языках из общего исходного материала: шаг написания на английском и шаг написания на русском, каждый со своей article form. Адаптируйте второй язык, промпты и правила домена под проект.

[
  {
    "id": "shared_draft",
    "type": "llm",
    "provider_id": 0,
    "ai_capability": "text",
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Ключевое слово: {{keyword}}\nДомен: {{domain}}\n\n{{domain_aiprompt}}\n\n\nСоставьте краткую структуру статьи для ключевого слова: вступление, 3-5 секций H2 и блок FAQ только если он помогает теме. Верните только структуру нумерованным списком.\n",
    "temperature": 0.3,
    "max_tokens": 1024,
    "output_key": "output"
  },
  {
    "id": "writer_en",
    "type": "llm",
    "provider_id": 0,
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Keyword: {{keyword}}\nDomain: {{domain}}\nOutline:\n{{step.shared_draft.output}}\n\n{{domain_aiprompt}}\n\n\nWrite a practical English article following the outline. Format output inside tags:\n<TITLE>[title]</TITLE>\n<DESCRIPTION>[meta description]</DESCRIPTION>\n<CONTENT>[full article markdown]</CONTENT>\n",
    "temperature": 0.45,
    "max_tokens": 4096,
    "output_key": "output"
  },
  {
    "id": "extract_title_en",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.writer_en.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "extract_description_en",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.writer_en.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "extract_content_en",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.writer_en.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "article_en",
    "type": "article_form",
    "title": "{{step.extract_title_en.output}}",
    "description": "{{step.extract_description_en.output}}",
    "markdown": "{{step.extract_content_en.output}}",
    "lang": "en",
    "slug": "",
    "main_image": "",
    "xfields_json": "[]",
    "public": 1
  },
  {
    "id": "writer_ru",
    "type": "llm",
    "provider_id": 0,
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Ключевое слово: {{keyword}}\nДомен: {{domain}}\nСтруктура:\n{{step.shared_draft.output}}\n\n{{domain_aiprompt}}\n\n\nНапишите практическую статью на русском языке по этой структуре. Оформите вывод внутри тегов:\n<TITLE>[заголовок]</TITLE>\n<DESCRIPTION>[мета-описание]</DESCRIPTION>\n<CONTENT>[полный текст статьи в markdown]</CONTENT>\n",
    "temperature": 0.45,
    "max_tokens": 4096,
    "output_key": "output"
  },
  {
    "id": "extract_title_ru",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.writer_ru.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "extract_description_ru",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.writer_ru.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "extract_content_ru",
    "type": "regexp",
    "mode": "extract",
    "input_source": "{{step.writer_ru.output}}",
    "pattern": "\\s*(.*?)\\s*",
    "flags": "si",
    "output_key": "output"
  },
  {
    "id": "article_ru",
    "type": "article_form",
    "title": "{{step.extract_title_ru.output}}",
    "description": "{{step.extract_description_ru.output}}",
    "markdown": "{{step.extract_content_ru.output}}",
    "lang": "ru",
    "slug": "",
    "main_image": "",
    "xfields_json": "[]",
    "public": 1
  }
]

6. Запись товара WordPress (WordPress Product Post)

Генерирует товар в стиле WooCommerce и публикует его как custom post type product с категориями, тегами, ценой, артикулом, SEO-мета и изображением записи. WordPress-мост читает эти поля из xfields_json.

[
  {
    "id": "product_brief",
    "type": "llm",
    "provider_id": 0,
    "ai_capability": "text",
    "model": "",
    "prompt_role": "user",
    "prompt_text": "Ключевое слово товара: {{keyword}}\nДомен: {{domain}}\n\n{{domain_aiprompt}}\n\n\nСгенерируйте структурированное описание товара по ключевому слову. Верните только валидный JSON (без markdown-ограждений) с ключами:\n{\"title\": \"\", \"short_description\": \"\", \"description\": \"\", \"price\": \"\", \"sku\": \"\", \"categories\": [\"\"], \"tags\": [\"\"]}\n",
    "temperature": 0.4,
    "max_tokens": 3072,
    "output_key": "output"
  },
  {
    "id": "product_title",
    "type": "transform",
    "operation": "json_path",
    "arg1": "{{step.product_brief.output}}",
    "output_key": "title"
  },
  {
    "id": "product_description",
    "type": "transform",
    "operation": "json_path",
    "arg1": "{{step.product_brief.output}}",
    "output_key": "description"
  },
  {
    "id": "product_short",
    "type": "transform",
    "operation": "json_path",
    "arg1": "{{step.product_brief.output}}",
    "output_key": "short_description"
  },
  {
    "id": "product_xfields",
    "type": "transform",
    "operation": "json_path",
    "arg1": "{{step.product_brief.output}}",
    "output_key": "xfields"
  },
  {
    "id": "product_article",
    "type": "article_form",
    "title": "{{step.product_title.output}}",
    "description": "{{step.product_short.output}}",
    "markdown": "{{step.product_description.output}}",
    "lang": "en",
    "slug": "",
    "main_image": "",
    "xfields_json": "{\"post_type\":\"product\",\"categories\":{{step.product_xfields.output.categories}},\"tags\":{{step.product_xfields.output.tags}},\"meta\":{\"_regular_price\":\"{{step.product_xfields.output.price}}\",\"_sku\":\"{{step.product_xfields.output.sku}}\",\"_visibility\":\"visible\"},\"seo\":{\"title\":\"{{step.product_title.output}}\",\"description\":\"{{step.product_short.output}}\"}}",
    "public": 1
  }
]

7. Готовые примеры pipeline

В разделе Templates доступны готовые примеры pipeline. Их можно открыть, изучить, скопировать и адаптировать под свой workflow.

ШаблонЧто показываетКлючевой маршрут
Example - Graph IF ELSE and MergeIF/ELSE, две AI-ветви, Merge, JavaScript, RegExp и форма статьи.condition → writer → merge → script → article_form
Example - AI Check Rewrite LoopСтрогий AI-порог, три маршрута проверки, ограниченный WHILE и STOP.draft → check → loop/rewrite → check → article
Example - FOR EACH SectionsПодготовку массива, loop-переменные, обработку каждого элемента и накопление результатов.script → for_each → AI → accumulator → loop → article
Example - Source RAG Quality GateПоиск, загрузку материалов по URL, RAG-контекст, IF и AI quality gate.search → article → RAG → condition → writer → check → article
IF/ELSE + Merge

Условие с оператором regex ищет признаки сравнения в keyword. Выполняется только одна ветвь. Обе ветви ведут в Merge, а JavaScript возвращает input.output из merge-объекта. Merge здесь служит точкой схождения, а не параллельным исполнителем.

{
  "id": "choose_article_mode",
  "type": "condition",
  "left": "{{keyword}}",
  "operator": "regex",
  "right": "~\\b(vs|versus|compare|comparison|сравнение|против)\\b~iu",
  "on_true": "comparison_writer",
  "on_false": "guide_writer"
}
{
  "id": "branch_merge",
  "type": "merge",
  "next": "unwrap_branch"
}
{
  "id": "unwrap_branch",
  "type": "script",
  "input_source": "{{step.branch_merge.output}}",
  "code": "return input && typeof input === \"object\" && \"output\" in input ? input.output : input;",
  "next": "branch_title"
}
AI Check + ограниченный rewrite loop

После каждой проверки select_candidate выбирает последний rewrite, если он уже существует. При fail цикл разрешает не более трёх переписываний. Тело возвращается через rewrite_article → select_candidate → ai_quality → rewrite_loop, поэтому цикл валиден и ограничен. Исчерпание попыток и ошибка сервиса ведут в разные STOP.

{
  "id": "ai_quality",
  "type": "ai_check",
  "input_source": "{{step.select_candidate.output}}",
  "threshold_ai_percent": 30,
  "comparison": "less_than",
  "on_pass": "approved_title",
  "on_fail": "rewrite_loop",
  "on_error": "detector_error"
}
{
  "id": "rewrite_loop",
  "type": "loop",
  "mode": "while",
  "left": "{{step.ai_quality.output.passed}}",
  "operator": "falsy",
  "body": "rewrite_article",
  "after": "rewrite_exhausted",
  "max_iterations": 3
}
FOR EACH + накопление результатов

prepare_sections возвращает массив. AI пишет один раздел для текущего {{loop.item}}. Поскольку повторный output одного шага обычно содержит только последний результат, collect_sections явно добавляет новый текст к своему предыдущему массиву. После loop шаг render_markdown объединяет массив.

{
  "id": "section_loop",
  "type": "loop",
  "mode": "for_each",
  "items_source": "{{step.prepare_sections.output}}",
  "body": "write_section",
  "after": "render_markdown",
  "max_iterations": 10
}
{
  "id": "collect_sections",
  "type": "script",
  "input_source": "{{step.write_section.output}}",
  "code": "const previous = Array.isArray(steps.collect_sections) ? steps.collect_sections : [];\nreturn previous.concat([input]);",
  "next": "section_loop"
}
Источники + RAG + quality gate

Результаты поиска передаются в Статья по URL, затем в RAG. Условие не запускает writer при пустом контексте. Writer получает подготовленный контекст, после чего готовый материал проходит проверку текста.

{
  "id": "article_extract",
  "type": "collector",
  "channel": "article",
  "engine": "article",
  "query_source": "{{step.evidence_search.output}}",
  "next": "evidence_rag"
}
{
  "id": "evidence_rag",
  "type": "transform",
  "operation": "rag_builder",
  "arg1": "{{step.article_extract.output}}",
  "max_total_chars": 15000,
  "max_per_host": 2,
  "max_sources": 8,
  "chunk_size": 1000,
  "next": "context_gate"
}

Полный JSON четырёх примеров

Ниже приведены полные JSON-массивы примеров. Их можно скопировать в JSON-редактор шаблона и адаптировать под свой workflow.

Example - Graph IF ELSE and Merge

Полный JSON: IF/ELSE, две ветви, Merge, JavaScript и форма статьи.

[
    {
        "id": "choose_article_mode",
        "type": "condition",
        "left": "{{keyword}}",
        "operator": "regex",
        "right": "~\\b(vs|versus|compare|comparison|сравнение|против)\\b~iu",
        "on_true": "comparison_writer",
        "on_false": "guide_writer",
        "output_key": "output"
    },
    {
        "id": "comparison_writer",
        "type": "llm",
        "provider_id": 2,
        "ai_capability": "text",
        "model": "",
        "prompt_role": "user",
        "prompt_text": "Keyword: {{keyword}}\nDomain: {{domain}}\n\n{{domain_aiprompt}}\n\nWrite a balanced comparison article. Return exactly:\n<TITLE>Title</TITLE>\n<DESCRIPTION>Meta description</DESCRIPTION>\n<CONTENT>Markdown article</CONTENT>",
        "temperature": 0.4,
        "max_tokens": 4096,
        "output_key": "output",
        "next": "branch_merge"
    },
    {
        "id": "guide_writer",
        "type": "llm",
        "provider_id": 2,
        "ai_capability": "text",
        "model": "",
        "prompt_role": "user",
        "prompt_text": "Keyword: {{keyword}}\nDomain: {{domain}}\n\n{{domain_aiprompt}}\n\nWrite a practical how-to guide. Return exactly:\n<TITLE>Title</TITLE>\n<DESCRIPTION>Meta description</DESCRIPTION>\n<CONTENT>Markdown article</CONTENT>",
        "temperature": 0.4,
        "max_tokens": 4096,
        "output_key": "output",
        "next": "branch_merge"
    },
    {
        "id": "branch_merge",
        "type": "merge",
        "output_key": "output",
        "next": "unwrap_branch"
    },
    {
        "id": "unwrap_branch",
        "type": "script",
        "language": "javascript",
        "input_source": "{{step.branch_merge.output}}",
        "code": "return input && typeof input === \"object\" && \"output\" in input ? input.output : input;",
        "timeout_ms": 1000,
        "max_output_bytes": 262144,
        "output_key": "output",
        "next": "branch_title"
    },
    {
        "id": "branch_title",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.unwrap_branch.output}}",
        "pattern": "<TITLE>\\s*(.*?)\\s*</TITLE>",
        "flags": "si",
        "output_key": "output",
        "next": "branch_description"
    },
    {
        "id": "branch_description",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.unwrap_branch.output}}",
        "pattern": "<DESCRIPTION>\\s*(.*?)\\s*</DESCRIPTION>",
        "flags": "si",
        "output_key": "output",
        "next": "branch_content"
    },
    {
        "id": "branch_content",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.unwrap_branch.output}}",
        "pattern": "<CONTENT>\\s*(.*?)\\s*</CONTENT>",
        "flags": "si",
        "output_key": "output",
        "next": "branch_article"
    },
    {
        "id": "branch_article",
        "type": "article_form",
        "title": "{{step.branch_title.output}}",
        "description": "{{step.branch_description.output}}",
        "markdown": "{{step.branch_content.output}}",
        "lang": "{{domain_lang}}",
        "slug": "",
        "main_image": "",
        "xfields_json": "{}",
        "public": 1,
        "output_key": "article_data",
        "next": "end"
    }
]
Example - AI Check Rewrite Loop

Полный JSON: AI-проверка, bounded WHILE, повторное переписывание и STOP-маршруты.

[
    {
        "id": "initial_draft",
        "type": "llm",
        "provider_id": 2,
        "ai_capability": "text",
        "model": "",
        "prompt_role": "user",
        "prompt_text": "Keyword: {{keyword}}\nDomain: {{domain}}\n\n{{domain_aiprompt}}\n\nWrite a useful article in a natural editorial style. Return exactly:\n<TITLE>Title</TITLE>\n<DESCRIPTION>Meta description</DESCRIPTION>\n<CONTENT>Markdown article</CONTENT>",
        "temperature": 0.65,
        "max_tokens": 4096,
        "output_key": "output",
        "next": "select_candidate"
    },
    {
        "id": "select_candidate",
        "type": "script",
        "language": "javascript",
        "input_source": "{{step.initial_draft.output}}",
        "code": "return steps.rewrite_article || input;",
        "timeout_ms": 1000,
        "max_output_bytes": 262144,
        "output_key": "output",
        "next": "ai_quality"
    },
    {
        "id": "ai_quality",
        "type": "ai_check",
        "detector": "service_1",
        "input_source": "{{step.select_candidate.output}}",
        "threshold_ai_percent": 30,
        "comparison": "less_than",
        "on_pass": "approved_title",
        "on_fail": "rewrite_loop",
        "on_error": "detector_error",
        "output_key": "output"
    },
    {
        "id": "rewrite_loop",
        "type": "loop",
        "mode": "while",
        "left": "{{step.ai_quality.output.passed}}",
        "operator": "falsy",
        "right": "",
        "body": "rewrite_article",
        "after": "rewrite_exhausted",
        "max_iterations": 3,
        "output_key": "output"
    },
    {
        "id": "rewrite_article",
        "type": "llm",
        "provider_id": 2,
        "ai_capability": "text",
        "model": "",
        "prompt_role": "user",
        "prompt_text": "Rewrite the article below in a more natural, specific and varied editorial style. Preserve factual meaning and the TITLE, DESCRIPTION and CONTENT tags.\n\nCurrent article:\n{{step.select_candidate.output}}\n\nRewrite attempt: {{loop.iteration}} of 3",
        "temperature": 0.85,
        "max_tokens": 4096,
        "output_key": "output",
        "next": "select_candidate"
    },
    {
        "id": "approved_title",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.select_candidate.output}}",
        "pattern": "<TITLE>\\s*(.*?)\\s*</TITLE>",
        "flags": "si",
        "output_key": "output",
        "next": "approved_description"
    },
    {
        "id": "approved_description",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.select_candidate.output}}",
        "pattern": "<DESCRIPTION>\\s*(.*?)\\s*</DESCRIPTION>",
        "flags": "si",
        "output_key": "output",
        "next": "approved_content"
    },
    {
        "id": "approved_content",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.select_candidate.output}}",
        "pattern": "<CONTENT>\\s*(.*?)\\s*</CONTENT>",
        "flags": "si",
        "output_key": "output",
        "next": "approved_article"
    },
    {
        "id": "rewrite_exhausted",
        "type": "stop",
        "reason": "Text did not pass the AI threshold after 3 rewrites. Last AI score: {{step.ai_quality.output.ai_percent}}%",
        "output_key": "output"
    },
    {
        "id": "detector_error",
        "type": "stop",
        "reason": "AI text-check service failed: {{step.ai_quality.output.error}}",
        "output_key": "output"
    },
    {
        "id": "approved_article",
        "type": "article_form",
        "title": "{{step.approved_title.output}}",
        "description": "{{step.approved_description.output}}",
        "markdown": "{{step.approved_content.output}}",
        "lang": "{{domain_lang}}",
        "slug": "",
        "main_image": "",
        "xfields_json": "{\"ai_percent\":\"{{step.ai_quality.output.ai_percent}}\"}",
        "public": 1,
        "output_key": "article_data",
        "next": "end"
    }
]
Example - FOR EACH Sections

Полный JSON: FOR EACH, loop-переменные и накопление результатов в JavaScript.

[
    {
        "id": "prepare_sections",
        "type": "script",
        "language": "javascript",
        "input_source": "{{keyword}}",
        "code": "return [\"Overview and definitions: \" + input, \"Practical implementation: \" + input, \"Common mistakes and checks: \" + input];",
        "timeout_ms": 1000,
        "max_output_bytes": 262144,
        "output_key": "output",
        "next": "section_loop"
    },
    {
        "id": "section_loop",
        "type": "loop",
        "mode": "for_each",
        "items_source": "{{step.prepare_sections.output}}",
        "body": "write_section",
        "after": "render_markdown",
        "max_iterations": 10,
        "output_key": "output"
    },
    {
        "id": "write_section",
        "type": "llm",
        "provider_id": 2,
        "ai_capability": "text",
        "model": "",
        "prompt_role": "user",
        "prompt_text": "Keyword: {{keyword}}\nSection request: {{loop.item}}\nZero-based index: {{loop.index}}\nIteration: {{loop.section_loop.iteration}}\n\n{{domain_aiprompt}}\n\nWrite only this article section in Markdown. Start with an H2 heading and avoid repeating other sections.",
        "temperature": 0.45,
        "max_tokens": 1536,
        "output_key": "output",
        "next": "collect_sections"
    },
    {
        "id": "collect_sections",
        "type": "script",
        "language": "javascript",
        "input_source": "{{step.write_section.output}}",
        "code": "const previous = Array.isArray(steps.collect_sections) ? steps.collect_sections : [];\nreturn previous.concat([input]);",
        "timeout_ms": 1000,
        "max_output_bytes": 262144,
        "output_key": "output",
        "next": "section_loop"
    },
    {
        "id": "render_markdown",
        "type": "script",
        "language": "javascript",
        "input_source": "{{step.collect_sections.output}}",
        "code": "const sections = Array.isArray(input) ? input : [];\nreturn sections.join(\"\\n\\n\");",
        "timeout_ms": 1000,
        "max_output_bytes": 262144,
        "output_key": "output",
        "next": "sections_article"
    },
    {
        "id": "sections_article",
        "type": "article_form",
        "title": "Guide: {{keyword}}",
        "description": "A structured practical guide about {{keyword}}.",
        "markdown": "{{step.render_markdown.output}}",
        "lang": "{{domain_lang}}",
        "slug": "",
        "main_image": "",
        "xfields_json": "{\"sections\":{{step.collect_sections.output}}}",
        "public": 1,
        "output_key": "article_data",
        "next": "end"
    }
]
Example - Source RAG Quality Gate

Полный JSON: источники, RAG-контекст, IF и AI quality gate.

[
    {
        "id": "evidence_search",
        "type": "collector",
        "channel": "web",
        "engine": "google",
        "query_source": "{{keyword}}",
        "serp_limit": 8,
        "output_key": "output",
        "next": "article_extract"
    },
    {
        "id": "article_extract",
        "type": "collector",
        "channel": "article",
        "engine": "article",
        "query_source": "{{step.evidence_search.output}}",
        "max_total_time_sec": 300,
        "output_key": "output",
        "next": "evidence_rag"
    },
    {
        "id": "evidence_rag",
        "type": "transform",
        "operation": "rag_builder",
        "arg1": "{{step.article_extract.output}}",
        "max_total_chars": 15000,
        "max_per_host": 2,
        "max_sources": 8,
        "chunk_size": 1000,
        "output_key": "output",
        "next": "context_gate"
    },
    {
        "id": "context_gate",
        "type": "condition",
        "left": "{{step.evidence_rag.output}}",
        "operator": "not_empty",
        "right": "",
        "on_true": "evidence_writer",
        "on_false": "no_evidence",
        "output_key": "output"
    },
    {
        "id": "evidence_writer",
        "type": "llm",
        "provider_id": 2,
        "ai_capability": "text",
        "model": "",
        "prompt_role": "user",
        "prompt_text": "Keyword: {{keyword}}\nDomain: {{domain}}\n\nEvidence context:\n{{step.evidence_rag.output}}\n\n{{domain_aiprompt}}\n\nUse only supported claims from the evidence context. Respect KEY_CLAIMS and VERDICT credibility signals. Add a final section named Sources used. Return exactly:\n<TITLE>Title</TITLE>\n<DESCRIPTION>Meta description</DESCRIPTION>\n<CONTENT>Markdown article</CONTENT>",
        "temperature": 0.35,
        "max_tokens": 6144,
        "output_key": "output",
        "next": "evidence_content"
    },
    {
        "id": "evidence_content",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.evidence_writer.output}}",
        "pattern": "<CONTENT>\\s*(.*?)\\s*</CONTENT>",
        "flags": "si",
        "output_key": "output",
        "next": "evidence_quality"
    },
    {
        "id": "evidence_quality",
        "type": "ai_check",
        "detector": "service_1",
        "input_source": "{{step.evidence_content.output}}",
        "threshold_ai_percent": 30,
        "comparison": "less_than",
        "on_pass": "evidence_title",
        "on_fail": "quality_rejected",
        "on_error": "quality_service_error",
        "output_key": "output"
    },
    {
        "id": "evidence_title",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.evidence_writer.output}}",
        "pattern": "<TITLE>\\s*(.*?)\\s*</TITLE>",
        "flags": "si",
        "output_key": "output",
        "next": "evidence_description"
    },
    {
        "id": "evidence_description",
        "type": "regexp",
        "mode": "extract_one",
        "input_source": "{{step.evidence_writer.output}}",
        "pattern": "<DESCRIPTION>\\s*(.*?)\\s*</DESCRIPTION>",
        "flags": "si",
        "output_key": "output",
        "next": "evidence_article"
    },
    {
        "id": "no_evidence",
        "type": "stop",
        "reason": "No usable evidence context was produced.",
        "output_key": "output"
    },
    {
        "id": "quality_rejected",
        "type": "stop",
        "reason": "Generated article failed the AI threshold: {{step.evidence_quality.output.ai_percent}}%",
        "output_key": "output"
    },
    {
        "id": "quality_service_error",
        "type": "stop",
        "reason": "AI text-check service failed: {{step.evidence_quality.output.error}}",
        "output_key": "output"
    },
    {
        "id": "evidence_article",
        "type": "article_form",
        "title": "{{step.evidence_title.output}}",
        "description": "{{step.evidence_description.output}}",
        "markdown": "{{step.evidence_content.output}}",
        "lang": "{{domain_lang}}",
        "slug": "",
        "main_image": "",
        "xfields_json": "{\"ai_percent\":\"{{step.evidence_quality.output.ai_percent}}\"}",
        "public": 1,
        "output_key": "article_data",
        "next": "end"
    }
]

🛠️ Если что-то не работает

  • Сайт не принимает публикацию — проверьте API URL, токен в classes/integration.php, rewrite и доступность api.php.
  • auth_failed — токен в панели не совпадает с токеном на сайте.
  • Модель не видна в LLM-шаге — откройте провайдера, загрузите список моделей кнопкой 🔄 или вставьте модели вручную.
  • Шаблон требует внимания — в одном из AI-шагов нет провайдера, выбран удалённый провайдер или макрос ссылается на будущий/удалённый шаг.
  • Поиск вернул 0 результатов — проверьте запрос, поисковый backend, лимит SERP и доступность прокси/источника.
  • Статья по URL не загрузилась — проверьте, что предыдущий шаг действительно отдаёт URL, а не обычный текст без ссылок.
  • RAG пустой — убедитесь, что шаг загрузки статей возвращает документы с HTML-контентом.
  • Batch завис или завершился ошибкой ожидания — увеличьте время ожидания batch или используйте обычный текстовый режим.
  • Публикация прошла, но URL странный — проверьте поле Язык / раздел URL, slug, заголовок и правила генерации slug на стороне клиента.
Начинайте диагностику с Подробности задачи и отладки шагов. Там видно, на каком шаге pipeline остановился, какой вход получил шаг и какой output он вернул.