Если в продукте появляется api генерации видео, привычная модель «запрос → ответ за секунды» перестаёт работать. Видео — это длительная операция, поэтому HTTP-запрос лучше рассматривать как запуск задачи, а не как ожидание готового файла.
Для видео по api в приложении я бы сразу разделял три состояния: запрос принят, задача выполняется или стоит в очереди, результат готов. У сервиса для этого есть отдельные маршруты POST /generate и GET /tasks/{id}, а готовность можно получать и через необязательный callback_url. Документация и выдача ключа находятся в разделе API.
Это меняет не столько код вызова, сколько архитектуру интерфейса. Пользователь не должен держать открытую страницу несколько минут ради одного HTTP-запроса, а сервер приложения не должен создавать бесконтрольное количество дорогих задач.
1) Три минуты ожидания в продукте, где привыкли к секундам
Главная ошибка — проектировать генерацию видео как синхронный метод вроде generateVideo(), который вызывается из обработчика кнопки и ждёт окончания работы. Такой подход связывает пользовательский интерфейс с длительностью внешней операции и плохо масштабируется: закрытая вкладка, мобильный интернет или перезагрузка страницы уже становятся отдельными проблемами.
Правильнее создать собственную сущность задачи. Например, после нажатия «Создать видео» приложение записывает video_job со статусом queued, отправляет запрос на запуск операции и сохраняет полученный идентификатор задачи. Дальше клиент получает состояние отдельно.
POST /wp-json/genius/v1/generate
Authorization: Bearer <ключ>
Для проверки состояния предусмотрен маршрут GET /tasks/{id}. Поэтому фронтенд может обновлять карточку задачи, не удерживая первоначальный запрос открытым.
Для небольшого продукта достаточно polling с интервалом, например, 5–10 секунд. Это не является ограничением сервиса, а инженерным параметром вашего приложения: частоту проверки стоит выбирать так, чтобы интерфейс оставался отзывчивым, а количество дополнительных HTTP-запросов было контролируемым.
Если нужен push-механизм, при запуске можно передать callback_url. Когда задача готова, сервис отправляет на этот адрес POST-запрос. Тогда браузеру не требуется самостоятельно постоянно спрашивать сервер о состоянии: ваше backend-приложение принимает callback, меняет статус задачи и уже затем уведомляет клиент.
Например, последовательность может выглядеть так:
Пользователь
|
v
POST /generate
|
v
ваша БД: queued
|
v
задача выполняется / ожидает
|
+---- GET /tasks/{id}
|
+---- callback_url
|
v
ваша БД: completed
|
v
интерфейс показывает результат
Ключевой принцип здесь простой: браузер знает о вашей задаче, а не обязан знать о длительности генерации. Если пользователь ушёл со страницы, задача не должна исчезать вместе с вкладкой.
Для самого API генерации видео также полезно проверять баланс до запуска дорогой операции. Маршрут GET /balance позволяет получить остаток, а операция «Видео по описанию» стоит 119 ₽ за один запуск.
| Операция | Код | Цена за запуск |
|---|---|---|
| Видео по описанию | video |
119 ₽ |
| Оживить фото | photo-video |
25 ₽ |
| Изменить фото по описанию | image-edit |
35 ₽ |
| Говорящий аватар | avatar |
120 ₽ |
| Картинка по описанию | image |
9 ₽ |
Цены в таблице — именно стоимость одного запуска. У сервиса нет абонентской платы и минимального платежа; при выпуске первого ключа на баланс начисляется 50 ₽ для пробного использования.

2) Очередь и приоритеты: кто идёт первым
Очередь задач видео должна существовать как минимум на уровне вашего приложения. Даже если сейчас запросы выполняются быстро, пользователь может нажать кнопку несколько раз, открыть несколько вкладок или запустить генерацию сразу из нескольких рабочих процессов.
Я обычно разделяю очередь и фактический запуск. В БД задача сначала получает статус queued. В ней сохраняются пользователь, время создания, тип операции, параметры генерации и внутренний идентификатор внешней задачи. Воркер выбирает следующую задачу, проверяет ограничения и только после этого запускает операцию.
Приоритеты имеет смысл задавать явно. Например, интерактивная задача пользователя может иметь приоритет 10, повторная автоматическая генерация — 5, а пакетная обработка — 1. Эти числа являются внутренними правилами вашего приложения, а не настройкой API.
Важно не путать собственную очередь с очередью самого сервиса. API возвращает состояние конкретной задачи, но из предоставленной документации не следует, что клиент может управлять внутренним порядком выполнения задач. Поэтому бизнес-логику приоритетов безопаснее держать у себя.
Ещё одна полезная деталь — идемпотентность на уровне кнопки. Если пользователь дважды отправил одну и ту же команду из-за задержки интерфейса, не стоит автоматически считать это двумя независимыми заказами. Можно создать внутренний request_id и несколько секунд не принимать дубликаты с одинаковыми параметрами.
При этом нельзя считать повтор задачи бесплатным. Стоимость относится к запуску операции: видео — 119 ₽ за запуск. Поэтому повторная отправка запроса без контроля может одновременно создать две задачи и списать стоимость за обе.
Для очереди удобно иметь минимальный набор полей:
id
user_id
operation
provider_task_id
status
priority
created_at
started_at
finished_at
error_code
result_url
Такой набор уже позволяет отвечать на основные вопросы: сколько задач ждёт пользователь, сколько времени задача провела в очереди, сколько выполнялась и где закончилась ошибка.
3) Лимит на пользователя и защита от перебора
Ограничения генерации видео стоит вводить на двух уровнях. Первый — технический лимит API: для ключа разрешено не более 60 запросов в минуту. Второй — бизнес-лимиты вашего продукта, которые определяют, сколько дорогих операций может запускать конкретный пользователь.
Лимит 60 запросов в минуту не означает, что пользователю нужно разрешить 60 генераций видео в минуту. При цене 119 ₽ за запуск потенциальный расход быстро становится заметным. Поэтому лучше ограничивать именно дорогую операцию, а не только число HTTP-запросов.
Например, приложение может хранить счётчик запусков video за выбранное окно времени и отдельно ограничивать число задач в статусах queued и running. Конкретные значения — 3 активные задачи, 10 запусков в час или другое число — должны зависеть от вашей экономики и сценария продукта, а не от предположения о внутренних ограничениях API.
Хорошая проверка перед запуском выглядит так:
if active_video_jobs(user_id) >= VIDEO_CONCURRENCY_LIMIT:
return 429, "Слишком много активных задач"
if video_jobs_in_period(user_id) >= VIDEO_PERIOD_LIMIT:
return 429, "Лимит генераций исчерпан"
if balance() < VIDEO_PRICE:
return 402, "Недостаточно средств"
enqueue_video_job(user_id, payload)
Отдельно стоит защищать кнопку от повторного нажатия. На клиенте можно временно отключить её, но это только удобство интерфейса. Настоящее ограничение должно проверяться на сервере, потому что клиентские проверки легко обойти.
Для контроля расходов полезно считать не только количество запросов, но и потенциальную стоимость очереди. Если у пользователя уже 20 задач на видео, приложение должно понимать, что речь идёт о потенциальных 2380 ₽ запуска. Это не обязательно повод автоматически отменять задачи, но такой показатель нужен для контроля.
Тот же подход работает и для других операций. Например, «Оживить фото» стоит 25 ₽, «Говорящий аватар» — 120 ₽, а «Увеличить качество фото» — 50 ₽. Поэтому универсальный лимит «100 задач на пользователя» мало что говорит о финансовой нагрузке без учёта типа операции.

4) Что показывать, пока ролик делается
Пользователь не должен видеть бесконечный spinner с текстом «Загрузка». Если задача потенциально занимает минуты, интерфейс должен объяснять, что произошло: запрос принят, генерация ещё выполняется, страницу можно закрыть.
Первое состояние — «Задача создана». Здесь полезно показать название операции и идентификатор задачи, если он нужен для поддержки. Второе — «В очереди». В этот момент не стоит писать точное время готовности, если приложение не располагает надёжной статистикой для такого прогноза.
Третье состояние — «Генерируется». Можно показывать индикатор активности и уже известные параметры. Если API возвращает дополнительные сведения о состоянии задачи, их можно использовать в интерфейсе; не следует придумывать проценты выполнения, если сервер их не предоставляет.
Четвёртое — «Готово». Только здесь карточка должна переключаться на результат. Пятый сценарий — «Не удалось выполнить», причём пользователю лучше показать понятное сообщение, а технические детали оставить журналу.
Polling можно организовать на backend или frontend. При frontend-polling браузер обращается к вашему серверу, а ваш сервер уже получает состояние задачи. Это позволяет не раскрывать API-ключ в клиентском коде.
import time
import requests
BASE_URL = "https://genius-bot.ru/wp-json/genius/v1"
API_KEY = "YOUR_KEY"
task_id = "TASK_ID"
headers = {
"Authorization": f"Bearer {API_KEY}"
}
while True:
response = requests.get(
f"{BASE_URL}/tasks/{task_id}",
headers=headers,
timeout=30
)
response.raise_for_status()
task = response.json()
print(task)
if task.get("status") in ("completed", "failed"):
break
time.sleep(10)
Это пример именно схемы проверки состояния. Значения полей конкретного ответа задачи нужно брать из ответа API, а не предполагать заранее. Сам ключ также не должен попадать в мобильное или браузерное приложение: его выдаёт раздел API после входа, и ключ показывается один раз.
Если используется callback, интерфейс становится ещё проще. Сервер принимает POST на ваш endpoint, проверяет событие, обновляет запись задачи и отправляет браузеру обычное уведомление через механизм, который уже используется вашим продуктом.
5) Ошибки и возвраты: если видео не получилось
Ошибка генерации и отмена пользователем — разные события, поэтому их стоит хранить раздельно. В первом случае операция могла завершиться неуспешно на стороне обработки, во втором — ваше приложение само прекратило ожидание или сняло задачу с очереди.
Не показывайте пользователю необработанный JSON ошибки. В БД сохраните технический ответ и идентификатор задачи, а в интерфейсе используйте короткое сообщение: «Не удалось создать видео. Попробуйте ещё раз» или более конкретное описание, если причина действительно известна.
Особенно важно заранее определить финансовую политику приложения. Сервис работает по модели оплаты за запуск, поэтому нельзя обещать пользователю автоматический возврат средств только на основании факта, что результат ему не понравился. Успешно созданное видео и неудачный запуск — разные случаи, которые ваша бизнес-логика должна учитывать отдельно.
Для повторной попытки полезно создавать новую внутреннюю задачу, а не менять старую с failed обратно на queued. Так журнал сохраняет историю: первая попытка завершилась ошибкой, вторая была отдельным запуском.
Ещё одна практическая защита — ограничить автоматические ретраи. Если ошибка повторяется, бесконечный цикл способен превратить единичный сбой в серию платных запусков. Для дорогой операции лучше заранее определить максимальное число автоматических повторов и после него передавать задачу в состояние, требующее ручного или пользовательского действия.
В API доступен также GET /balance. Перед новой попыткой приложение может проверить остаток, а в административной части полезно показывать суммарную стоимость запусков. Это особенно важно, когда повторная генерация доступна одной кнопкой.

6) Наблюдение: какие числа стоит писать в журнал
Минимальная телеметрия должна отвечать на четыре вопроса: сколько задач создаётся, сколько ждёт, сколько выполняется и сколько денег тратится. Без этих данных разработчик видит только жалобы «видео долго грузится», но не знает, где именно находится задержка.
Для каждой задачи я бы записывал как минимум время создания, время фактического запуска, время завершения и итоговый статус. Из них легко получить две разные метрики: время ожидания в вашей очереди и общее время до результата.
| Метрика | Что показывает |
|---|---|
queue_wait_seconds |
Сколько задача ждала запуска |
generation_seconds |
Сколько времени прошло от запуска до завершения |
total_seconds |
Полное время от создания задачи до результата |
queued_count |
Размер очереди в конкретный момент |
failed_count |
Количество неуспешных задач |
cost_rub |
Стоимость запущенной операции |
Полезно смотреть не только среднее время. Например, 90% задач могут завершаться быстро, а небольшая группа будет ждать значительно дольше. Поэтому для анализа очереди имеет смысл хранить распределение задержек и отдельно смотреть длинные задачи.
Ещё одна важная цифра — количество задач на пользователя. Если один аккаунт создаёт существенно больше операций, чем остальные, это не обязательно злоупотребление, но такой случай должен быть виден в журнале. Затем можно сопоставить его с лимитами, стоимостью и фактическим использованием продукта.
На уровне API стоит также считать HTTP-ошибки и количество запросов к /tasks/{id}. При polling с коротким интервалом запросов проверки может стать гораздо больше, чем самих запусков. Это особенно важно рядом с лимитом 60 запросов в минуту на ключ.
Для API генерации видео я бы также записывал тип операции. Тогда расходы можно разложить на video, photo-video, avatar и остальные операции, не смешивая задачи с разной стоимостью.
Наконец, полезно иметь отдельный журнал баланса: остаток до запуска, стоимость операции и остаток после запуска, если эти данные доступны вашему приложению. Это упрощает разбор спорных случаев и помогает заметить ошибочную логику повторных запусков.
Частые вопросы
Нужно ли держать HTTP-запрос открытым до готовности видео?
Нет. Практичнее запустить задачу через POST /generate, сохранить её идентификатор и затем получать состояние через GET /tasks/{id} либо использовать callback_url.
Как часто проверять состояние задачи?
Фиксированного интервала в справке сервиса не указано. В приложении можно использовать polling, например раз в 5–10 секунд, и отдельно контролировать количество запросов. Для критичных по нагрузке сценариев callback позволяет не опрашивать состояние постоянно.
Какой лимит запросов установлен у API?
Не более 60 запросов в минуту на один ключ. Это технический лимит API; собственные ограничения на число генераций видео для одного пользователя приложение может задавать отдельно.
Сколько стоит один запуск генерации видео?
Операция «Видео по описанию» (video) стоит 119 ₽ за один запуск. Оплата идёт за запуск, без абонентской платы и минимального платежа.
Можно ли получить результат без постоянного polling?
Да. При запуске можно передать необязательный параметр callback_url. Когда задача готова, на указанный адрес приходит POST-запрос.
Где взять API-ключ?
После входа ключ выдаётся в разделе подключения API и показывается один раз. В серверном приложении его следует хранить как секрет и передавать в заголовке Authorization: Bearer <ключ>.
