Справочник API
Асинхронные задачи
У задач с изображениями, видео и музыкой один надёжный жизненный цикл: отправить один раз, сохранить task_id, дождаться конечного состояния и получить результат. Сделайте один обработчик задач и для каждой модели выбирайте только группу эндпоинтов.
#Один жизненный цикл для всех асинхронных моделей
- 1
Отправьте один раз
Используйте уникальный Idempotency-Key и сразу сохраняйте ответ.
POST /v1/{capability} - 2
Сохраните task_id
Сохраните его до того, как воркер подтвердит задание.
task_id - 3
Опрос или вебхук
Сравнивайте статус без учёта регистра и останавливайтесь на конечном состоянии.
GET /{task_id} - 4
Получите и сохраните результат
После успеха вызовите /content и сохраните полученный URL платформы.
GET /{task_id}/content
#Группы эндпоинтов
| Возможность | Отправка | Опрос | Результат |
|---|---|---|---|
| Изображения | /v1/images/tasks | /v1/images/tasks/{task_id} | /v1/images/tasks/{task_id}/content |
| Видео | /v1/videos | /v1/videos/{task_id} | /v1/videos/{task_id}/content |
| Музыка | /v1/music/generations | /v1/music/tasks/{task_id} | /v1/music/tasks/{task_id}/content |
#Значения статуса
Один жизненный цикл, два набора значений. Задачи с изображениями, музыкой и 3D используют статусы задач OpenAI; видео и все тела вебхуков — статусы видео OpenAI. Проверка статуса, написанная для одной группы, молча не сработает для другой — эта таблица показывает соответствие.
| Этап | Изображения · музыка · 3D | Видео · вебхук | Конечный | Значение |
|---|---|---|---|---|
| NOT_START | processing | queued | нет | Принята шлюзом, ещё не передана в канал. |
| SUBMITTED | queued | queued | нет | Отправлена провайдеру, он подтвердил получение. |
| QUEUED | queued | queued | нет | Ожидает в очереди провайдера. |
| IN_PROGRESS | processing | in_progress | нет | Генерируется. progress содержит процент в виде строки, например "60%". |
| SUCCESS | succeeded | completed | да | Готово. Получите результат через /content. |
| FAILURE | failed | failed | да | Окончательная ошибка. Причина указана в fail_reason; зарезервированная квота возвращается. |
| UNKNOWN | unknown | unknown | нет | Провайдер перестал сообщать состояние, понятное шлюзу. Продолжайте опрос с ограничением по времени, затем выполните сверку — не считайте это ни успехом, ни ошибкой. |
Проверяйте конечные статусы, а не «не выполняется»
UNKNOWN — не ошибка
#Безопасный цикл опроса
Останавливайтесь на конечных статусах для опрашиваемой группы, для всего остального задайте общий лимит времени и увеличивайте паузы, чтобы зависшая задача не превратилась в бесконечный цикл.
import time, requests
# The two vocabularies. Pick the one that matches the endpoint you poll.
TASK_DONE, TASK_FAILED = {"succeeded"}, {"failed"} # images / music / 3D
VIDEO_DONE, VIDEO_FAILED = {"completed"}, {"failed"} # videos + webhooks
DEADLINE_SECONDS = 15 * 60
def wait_for_image_task(task_id, api_key):
started = time.monotonic()
delay = 2
while True:
response = requests.get(
f"https://www.aisplice.store/v1/images/tasks/{task_id}",
headers={"Authorization": f"Bearer {api_key}"},
timeout=30,
)
response.raise_for_status()
task = response.json()
status = task.get("status", "")
if status in TASK_DONE:
return task
if status in TASK_FAILED:
raise RuntimeError((task.get("error") or {}).get("message", "task failed"))
# queued / processing / unknown all mean "not finished". Wait — but
# never forever: hand an overdue task to reconciliation.
if time.monotonic() - started > DEADLINE_SECONDS:
raise TimeoutError(f"task {task_id} still {status} after the deadline")
time.sleep(delay)
delay = min(delay * 1.5, 15)Продолжение после перезапуска
#Хранение результатов
Запрашивайте /content только после успеха. Сохраните полученный URL платформы в своей записи и скачайте собственную копию, если требования к хранению предполагают независимое хранилище.
Проблема не решена?
Пришлите нам ID запроса или текст ошибки, и мы разберёмся.