Common.AI.ImageGen — Генерация изображений

Автор: Art Yg
Версия: 1.0

ImageGen — универсальный плагин для асинхронной генерации изображений через внешний Webhook Processor, с сохранением результата в lead (URL и/или base64) и поддержкой сценарного выхода (success/error/timeout).

Плагин спроектирован так, чтобы работать в двухфазном режиме, как LLMQuery:


Зачем он существует

В Metabot-сценариях нельзя считать генерацию изображения “быстрой синхронной функцией”:

ImageGen стандартизирует этот поток:


Что использует внутри

ImageGen — это обёртка, которая опирается на инфраструктурные компоненты:

Важно: RemoteApiCall как транспорт в принципе поддерживает любых провайдеров, но текущая версия ImageGen по умолчанию заточена под OpenAI Images API.


Поддерживаемые провайдеры

На текущий момент поддержан:

Если вам нужен другой провайдер (например, Replicate, Stability, Midjourney proxy, внутренний сервис) — свяжитесь с командой, и мы расширим плагин.

Примечание по архитектуре: сейчас таблица провайдеров (PROVIDERS) находится внутри плагина. При необходимости её можно вынести наружу (в конфиг бота/таблицу/отдельный реестр), чтобы вы могли подключать свои провайдеры без изменения кода плагина.


Что сохраняет

В зависимости от настроек:


Двухфазный протокол выполнения

PHASE 1 — отправка запроса

Когда isFirstImmediateCall = true:

  1. Инициализирует timeout-policy через Common.Platform.AsyncFallback (если задан timeout)

  2. Берёт токен из атрибута бота (по auth.tokenKey)

  3. Собирает итоговый prompt:

    • если задан prompts — собирает system[] + user[]

    • элементы массива могут быть:

      • inline строка
      • ссылка $alias (берётся из таблицы promptTable для agentName)
    • если в prompts используются $alias, то обязательны agentName и promptTable

  4. Формирует request body под /images/generations

  5. Отправляет запрос через RemoteApiCall.send(..., asyncResponse: true)

  6. (опционально) показывает messages.wait

  7. Возвращает false — сценарий “выходит” и ждёт callback


PHASE 2 — обработка callback

Когда isFirstImmediateCall = false:

  1. Проверяет, что это действительно callback от процессора (payload.is_async_response)

  2. Если это не callback (пользователь что-то написал):

    • показывает messages.processing
    • возвращает false
  3. Если callback:

    • снимает таймаут-job через AsyncFallback.unschedule()
    • парсит payload.content
    • извлекает url или b64_json
    • сохраняет в lead
    • если включён requireUrl и url нет → ошибка
  4. Если задан successScript — делает bot.run(successScript), иначе возвращается true


Конфигурация

Ниже описаны ключевые блоки ImageGen.run().


Provider + Auth

provider: "openai",
auth: { tokenKey: "OPENAI_API_KEY" }

Prompts (таблица + массивы)

ImageGen поддерживает интерфейс промптов “на вырост” — как в LLMQuery: массивы промптов и табличные ссылки.

agentName: "orion",
promptTable: "gpt_prompts",

prompts: {
  system: ["$avatar_brief_generator"],
  user: ["...основной запрос..."]
}

Принципы:

Примечание: OpenAI Images API принимает один prompt (строкой), поэтому ImageGen склеивает массивы в итоговый текст (обычно system + пустая строка + user). Это сделано для унификации с LLMQuery и поддержки других провайдеров/форматов в будущем.


Image параметры

image: {
  model: "dall-e-3",
  n: 1,
  size: "1024x1792",
  quality: "standard",
  style: "natural",
  background: null,
  response_format: "url"
}

Практика по форматам результата:


requireUrl

requireUrl: true

Если true, то отсутствие URL считается ошибкой (даже если пришёл b64).

Это удобно для MVP-потока “дай URL, а скачивание/сохранение сделаю потом”.


Таймаут (fallback)

timeout: {
  seconds: 120,
  script: "Orion_Image_Timeout"
}

Если callback не пришёл за указанное время — планировщик Metabot запускает timeout.script.

Таймаут реализован через Common.Platform.AsyncFallback внутри ImageGen.


Namespace для fallback

fallback: {
  namespace: "orion_image_reflection"
}

Нужен, чтобы несколько асинхронных операций не конфликтовали.

Если не задан, будет auto:


UX сообщения

messages: {
  wait: "🜁 Генерируем…",
  processing: "⏳ Подожди, ещё формируется…",
  error: "⚠️ Не удалось получить изображение"
}

Ошибки

error: {
  script: "Orion_Image_Error",
  flagAttr: "orion_image_error",
  reasonAttr: "orion_image_error_reason"
}

Успешный выход

successScript: "Orion_Image_Ready"

Если не указан — ImageGen.run() возвращается в ту же точку (return true), без перехода.


Таймаут: встроенный vs внешний

В большинстве сценариев таймаут проще и чище задавать внутри ImageGen через timeout, потому что плагин сам использует Common.Platform.AsyncFallback.

Внешнее управление таймаутом имеет смысл, если:


Примеры использования

Пример 1 — как используется в Orion: system prompt из таблицы + timeout + error + URL (MVP)

/**
 * orion_profiling_reflection_image
 *
 * Назначение:
 * - асинхронно сгенерировать вертикальный "Operator Reflection" образ
 * - сохранить URL в лид (скачивание/сохранение — отдельным шагом)
 * - timeout + error внутри ImageGen (как у LLMQuery)
 */

const ImageGen = require("Common.AI.ImageGen");

return ImageGen.run({
  lead,
  isFirstImmediateCall,

  code: "OrionActorImage",

  // Provider/Auth
  provider: "openai",
  auth: { tokenKey: "OPENAI_API_KEY" },

  // Prompts из таблицы + inline
  agentName: "orion",
  promptTable: "gpt_prompts",
  prompts: {
    // системный слой (табличный)
    system: ["$avatar_brief_generator"],

    // основной запрос (inline)
    user: [`
Create a vertical codex-grade mythotech Operator icon in Aurum Void aesthetic.

Aurum Void: cold matte gold schematic lines (axes, nodes, ritual UI glyphs) over deep graphite void.
No glossy sci-fi, no neon, no superhero vibe, no humor.

Faceless figure (hood/shadow/mask/void), calm, stable, centered on a strong vertical axis.
Heavy materials: carbon composite armor/robe, matte metal, dense fabric, worn realistic textures.
Subtle fog/particles for depth.

This is NOT a human portrait. It is an operational manifestation of a system entrepreneur / product leader at the scaling stage.
Output: a visual artifact, not an illustration.
    `.trim()]
  },

  // Таймаут (fallback)
  timeout: {
    seconds: 120,
    script: "Orion_Image_Timeout"
  },

  // Ошибки (как в LLMQuery)
  error: {
    script: "Orion_Image_Error",
    flagAttr: "orion_image_error",
    reasonAttr: "orion_image_error_reason"
  },

  // Namespace чтобы не конфликтовать
  fallback: {
    namespace: "orion_image_reflection"
  },

  // MVP: хотим именно URL
  requireUrl: true,

  image: {
    model: "dall-e-3",
    size: "1024x1792",
    quality: "standard",
    style: "natural",
    response_format: "url"
  },

  messages: {
    wait: "🜁 ORION формирует визуальное отражение…",
    processing: "⏳ Подожди, образ ещё куется…",
    error: "⚠️ Не удалось получить изображение"
  },

  save: {
    urlAttr: "orion_actor_image_url",
    b64Attr: "orion_actor_image_b64",
    rawJsonAttr: "orion_actor_image_payload"
  }

  // successScript: "Orion_Image_Ready" // опционально
});

Пример 2 — минимальный сценарий с таблицей промптов, без successScript

Подходит, когда вы хотите вернуться “в ту же точку” и решать дальше в текущем шаге.

const ImageGen = require("Common.AI.ImageGen");

return ImageGen.run({
  lead,
  isFirstImmediateCall,

  code: "OperatorIcon",

  provider: "openai",
  auth: { tokenKey: "OPENAI_API_KEY" },

  agentName: "orion",
  promptTable: "gpt_prompts",
  prompts: {
    system: ["$avatar_brief_generator"],
    user: ["Create a vertical mythotech Operator icon in Aurum Void aesthetic..."]
  },

  timeout: { seconds: 90, script: "Image_Timeout" },
  error: { script: "Image_Error" },

  requireUrl: true,

  image: {
    model: "dall-e-3",
    size: "1024x1792",
    response_format: "url"
  },

  save: {
    urlAttr: "operator_icon_url",
    rawJsonAttr: "operator_icon_payload"
  }
});

Пример 3 — внешний контроль timeout через AsyncFallback (продвинутый режим)

Этот способ полезен, если:

const ImageGen = require("Common.AI.ImageGen");
const AsyncFallback = require("Common.Platform.AsyncFallback");

if (isFirstImmediateCall) {
  AsyncFallback.configure({
    lead,
    namespace: "orion_image_reflection",
    timeout: { seconds: 120, script: "Orion_Image_Timeout" },
    error: { flagAttr: "orion_image_error", reasonAttr: "orion_image_error_reason" }
  }).schedule();
}

const res = ImageGen.run({
  lead,
  isFirstImmediateCall,

  code: "OrionActorImage",
  provider: "openai",
  auth: { tokenKey: "OPENAI_API_KEY" },

  agentName: "orion",
  promptTable: "gpt_prompts",
  prompts: {
    system: ["$avatar_brief_generator"],
    user: ["Create a vertical mythotech Operator icon in Aurum Void aesthetic..."]
  },

  // timeout внутри не задаём, потому что контролируем снаружи
  error: {
    script: "Orion_Image_Error",
    flagAttr: "orion_image_error",
    reasonAttr: "orion_image_error_reason"
  },

  requireUrl: true,

  image: {
    model: "dall-e-3",
    size: "1024x1792",
    response_format: "url"
  },

  save: {
    urlAttr: "orion_actor_image_url",
    rawJsonAttr: "orion_actor_image_payload"
  }
});

if (!isFirstImmediateCall && res === true) {
  AsyncFallback.configure({
    lead,
    namespace: "orion_image_reflection"
  }).unschedule();
}

return res;

Частые сценарии отказов и как реагировать


Итог

Common.AI.ImageGen — стандартизированный способ подключить генерацию изображений в сценарии Metabot:


Версия #5
Artem Garashko создал 1 February 2026 10:57:26
Artem Garashko обновил 1 February 2026 12:04:33