Перейти к содержанию
Публикация AiManual

ComfyUI как API: собираем веб-приложение для генерации изображений без кода через api2app

ComfyUI может работать как API-бэкенд, а api2app собирает вокруг него интерфейс без программирования. Разбираем экспорт workflow в JSON, три конфигурации API, c

Коротко

Что будет в материале

  1. 01

    Зачем превращать ComfyUI в API и что берёт на себя api2app

  2. 02

    Шаг 1. Готовим workflow ComfyUI и экспортируем его в JSON

  3. 03

    Шаг 2. Запускаем ComfyUI в режиме CORS для локального тестирования

  4. 04

    Шаг 3. Первая конфигурация API в api2app: постановка задачи

ComfyUI принимает граф генерации по HTTP: один запрос ставит задачу в очередь, второй отдаёт её статус, третий возвращает готовый файл. Движок остаётся локальным, интерфейс живёт отдельно. В разбираемом сценарии интерфейс собирается в api2app без программирования, и, по словам автора урока, такую форму можно оперативно перестраивать под меняющиеся задачи, не трогая код (разбор на Хабре).

Схема раскладывается на три слоя.

СлойЧто делаетГде живёт
Workflow ComfyUIОписывает граф: модель, промпт, сэмплер, разрешениеМашина с GPU
HTTP-слойТри конфигурации API: постановка задачи, статус, файлapi2app
ИнтерфейсТекстовое поле, кнопка, прогрессбар, область выводаapi2app

Запросов три, потому что генерация асинхронная. Первый вызов только ставит задачу в очередь и возвращает её идентификатор. Второй проверяет состояние. Третий отдаёт картинку по идентификатору контента. Одной конфигурацией не обойтись: ответ на постановку задачи изображения не содержит.

Что понадобится: рабочая установка ComfyUI на машине с GPU, аккаунт api2app и, если приложением будут пользоваться из интернета, пакет comfy-api-proxy. Без него стандартное API ComfyUI годится для локальных экспериментов.

Зачем превращать ComfyUI в API и что берёт на себя api2app

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

Плата за это - привязка к платформе и к формату ответов ComfyUI. Логика приложения живёт в конфигурациях API, а не в коде, и её возможности ограничены тем, что умеет конструктор.

Кому подходит схема, а кому проще написать код

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

Ограничения начинаются там, где нужна логика посложнее. Своя авторизация пользователей, биллинг, приоритеты в очереди, история генераций, тонкая обработка ошибок на серверной стороне: всё это придётся либо обходить средствами платформы, либо переносить в код. Если таких требований много, FastAPI плюс небольшой фронтенд дадут больше контроля, хотя и потребуют разработчика. Конструктор без кода экономит время на старте и ограничивает свободу на дистанции.

Шаг 1. Готовим workflow ComfyUI и экспортируем его в JSON

В уроке за основу взят готовый шаблон ComfyUI «Flux.2 [Klein] 4B: текст в изображение». Порядок такой: открыть шаблон, прогнать генерацию в обычном режиме и убедиться, что результат устраивает. Отправлять в API неотлаженный граф смысла нет: ошибка в нодах превратится в задачу, которая упадёт уже на стороне приложения, и разбираться придётся в двух местах сразу.

После успешного прогона делается экспорт для API. Это отдельное действие: обычное сохранение workflow и экспорт для API дают разные файлы, и для отправки в очередь нужен второй. Полученный json-файл открывают и копируют содержимое в буфер обмена целиком.

Структура API-формата узнаваема: объект, где ключи - идентификаторы нод, а внутри каждого лежат class_type и inputs. Данных интерфейса вроде координат нод на канвасе в нём, как правило, нет.

Почему в теле запроса ключ prompt, а не workflow

Стандартное API ComfyUI ждёт JSON workflow под ключом prompt. Тело запроса выглядит примерно так:

{
  "prompt": {
    "3": { "class_type": "...", "inputs": { ... } }
  }
}

При работе через comfy-api-proxy ключ меняется на workflow:

{
  "workflow": {
    "3": { "class_type": "...", "inputs": { ... } }
  }
}

Это первое место, где ломаются запросы при переходе с локального режима на прокси. Ошибка выглядит как отказ принять тело запроса, хотя сам workflow рабочий. Держите два варианта тела под рукой и меняйте ключ вместе с эндпоинтом, иначе отладка уйдёт в сторону проверки графа, где всё в порядке.

Шаг 2. Запускаем ComfyUI в режиме CORS для локального тестирования

Браузер пользователя api2app обращается к ComfyUI с другого origin. Без разрешающего заголовка запрос блокируется ещё до того, как дойдёт до сервера, и в консоли появляется ошибка CORS. В уроке ComfyUI запускают так:

python main.py --enable-cors-header

В пример из урока в параметр подставляется домен api2app, чтобы разрешение выдавалось конкретному источнику. Ответ ComfyUI получает заголовок Access-Control-Allow-Origin, и браузер пропускает данные.

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

Шаг 3. Первая конфигурация API в api2app: постановка задачи

В разделе «API» на api2app нажимаем «Добавить новый API». Дальше вкладка «Сырые данные»: там создаётся объект с ключом prompt, и в него вставляется скопированный JSON workflow. Метод запроса меняется на POST, URL указывает на эндпоинт постановки задачи вашей установки ComfyUI (в стандартном API это путь /prompt).

Тест запускают в режиме «Браузер»: запрос уходит из браузера, и в ответе видно, что задача действительно встала в очередь, а не упала на валидации графа. Ответ содержит идентификатор задачи в очереди, и именно это значение понадобится во второй конфигурации.

Скопируйте идентификатор и проверьте, что он меняется от запуска к запуску. Если значение повторяется, скорее всего запрос уходит не туда или тело подставляется из кеша.

Шаг 4. Вторая конфигурация API: опрос статуса задачи

Создаётся новая конфигурация с методом GET. URL строится из адреса очереди и идентификатора задачи: /api/v2/jobs/{id}. В примере из урока используется именно этот путь.

В ответе приходит статус. Четыре состояния: queued - задача в очереди, running - генерация идёт, succeeded - результат готов, error - выполнение сорвалось. Эти же состояния будут управлять прогрессбаром.

При succeeded в ответе появляются outputs: URL для получения результата и идентификатор контента, он же asset_id (в ответе лежит в поле id).

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

Шаг 5. Третья конфигурация API: получение изображения по asset_id

Третья конфигурация тоже GET. URL собирается вокруг идентификатора контента: asset_id берётся из ответа второй конфигурации. В уроке этот запрос назван просмотром изображения. Конкретный вид пути зависит от сборки, поэтому один раз выполните его вручную и убедитесь, что в ответ приходит файл, а не JSON с текстом ошибки.

Цепочка целиком: POST постановки, идентификатор задачи, GET статуса, succeeded, asset_id, GET файла, картинка в интерфейсе. Три конфигурации образуют одну последовательность, а не три независимых запроса. Вторая без первой не знает, что опрашивать, третья без второй не знает, что скачивать. При отладке идите по цепочке с начала: сначала стабильный идентификатор задачи, потом статус succeeded, и только затем вывод файла.

Шаг 6. comfy-api-proxy: доступ из мира, токен и заголовок Authorization

Стандартное API ComfyUI рассчитано на локальное применение. Для доступа извне в уроке предлагается отдельный пакет, который ставится через pip:

pip install comfy-api-proxy

Запуск с ключом авторизации и CORS:

comfy-api-proxy --enable-cors-header --token=<ваш-токен>

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

После запуска меняются три вещи: адрес запроса становится /api/v2/jobs, ключ в теле запроса меняется с prompt на workflow, а в заголовки добавляется Authorization с тем же токеном. Все три пункта перечислены в источнике (урок по связке ComfyUI и api2app).

Что именно ломается при переходе на прокси

ЭлементЛокальный режимЧерез comfy-api-proxy
Эндпоинт постановки задачиПуть стандартного API ComfyUI/api/v2/jobs
Ключ тела запросаpromptworkflow
ЗаголовкиБез авторизацииAuthorization с токеном
Поле авторизации в режиме «Браузер»Не используетсяНе должно быть приватным

Чек-лист типовых ошибок: остался ключ prompt; не добавлен заголовок Authorization; в конфигурации указан эндпоинт локальной установки вместо прокси; поле авторизации помечено как приватное в режиме «Браузер» (кнопка с иконкой замка). В уроке отдельно оговорено: в режиме «Браузер» это поле приватным быть не должно, иначе тест не пройдёт. Причина в том, что приватное поле не уходит в браузерный запрос, а прокси без токена отвечает отказом.

Шаг 7. Связываем интерфейс с API: поля ввода, вывода и прогрессбар

Оговорка про источник: опубликованный текст урока обрывается на этапе создания конфигураций, поэтому детали привязки элементов, скрытых полей и статусов ниже описаны по логике работы api2app и не процитированы дословно из материала.

Набор элементов минимальный: текстовое поле для промпта, кнопка запуска, индикатор прогресса и область вывода изображения. Связываются они действиями ввода и вывода: действие ввода берёт значение из элемента интерфейса и подставляет в тело запроса, действие вывода раскладывает ответ API по полям формы.

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

Последовательность при нажатии кнопки:

  1. Взять текст из поля и отправить POST в конфигурацию постановки задачи.
  2. Записать идентификатор задачи в скрытое поле.
  3. Опрашивать вторую конфигурацию, подставляя идентификатор и обновляя прогрессбар по статусу.
  4. При succeeded записать asset_id в скрытое поле и остановить опрос.
  5. Запросить третью конфигурацию и вывести изображение в область результата.

Прогрессбар привязывается к тем же четырём статусам: queued - ожидание в очереди, running - генерация, succeeded - готово, error - сбой. Полоска делает ожидание понятным: человек видит, что приложение работает, а не зависло на отправке.

Как обрабатывать статус error

На статусе error опрос нужно остановить, прогрессбар сбросить и показать понятное сообщение. Зависший в running интерфейс хуже явной ошибки: пользователь не понимает, ждать ему или закрывать вкладку. Конкретные тексты ошибок ComfyUI зависят от версии и от того, на каком узле упал граф, так что в интерфейс стоит выводить общую формулировку и кнопку повторной попытки. Логи полезно сохранять: без них причина сбоя останется загадкой.

Шаг 8. Публикация приложения и доступ извне без лишнего риска

Приложение публикуется в api2app, после чего им можно пользоваться по ссылке. Чтобы запросы доходили до локального ComfyUI, нужен обратный туннель: он принимает внешние соединения и передаёт их на машину с GPU. API при этом переводится в режим «Сервер», а заголовки авторизации помечаются приватными, чтобы токен оставался на серверной стороне и не попадал в клиентский код. Утёкший токен означает чужой доступ к вашей очереди, а вместе с ней к видеокарте и электричеству.

Базовой защитой от злоупотреблений в уроке предусмотрено ограничение дневных запросов с одного IP. Фильтр грубый: он отсекает случайный спам, обходится сменой адреса и не заменяет нормальную авторизацию. Пользователей за одним адресом он при этом уравнивает в квоте.

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

Ограничения подхода и когда он не подойдёт

  • Машина с ComfyUI должна быть включена. Перезагрузка ПК или падение интернета превращаются в ошибки у всех пользователей приложения.
  • Одна GPU обрабатывает задачи последовательно. При нескольких одновременных запросах очередь растёт, и время ожидания становится непредсказуемым.
  • Прокси и токен добавляют компонент, который нужно обслуживать: обновлять пакет, читать логи, ротировать ключ.
  • Лимит запросов по IP не различает людей за одним адресом и не спасает от целенаправленного обхода.
  • Конструктор без кода ограничивает логику: роли, оплата, история генераций и сложные сценарии ошибок упираются в его рамки.
  • Формат ответов зависит от версии ComfyUI, поэтому обновление движка может потребовать правок в конфигурациях API.

Схема хорошо работает как быстрый способ отдать готовый workflow наружу: интерфейс собирается за вечер, а генерация остаётся под контролем владельца железа. Заменой продакшен-инфраструктуре она не становится. Когда запросов станет много, следующим шагом будет вынос ComfyUI на серверную GPU, очередь с приоритетами и собственная авторизация, а api2app останется удобным слоем для формы. Начать стоит с одного workflow и трёх конфигураций: этого достаточно, чтобы понять, где именно ваша схема упрётся в ограничения.

Подписаться на канал