Справочник API

Асинхронные задачи

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

#Один жизненный цикл для всех асинхронных моделей

  1. 1

    Отправьте один раз

    Используйте уникальный Idempotency-Key и сразу сохраняйте ответ.

    POST /v1/{capability}
  2. 2

    Сохраните task_id

    Сохраните его до того, как воркер подтвердит задание.

    task_id
  3. 3

    Опрос или вебхук

    Сравнивайте статус без учёта регистра и останавливайтесь на конечном состоянии.

    GET /{task_id}
  4. 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_STARTprocessingqueuedнетПринята шлюзом, ещё не передана в канал.
SUBMITTEDqueuedqueuedнетОтправлена провайдеру, он подтвердил получение.
QUEUEDqueuedqueuedнетОжидает в очереди провайдера.
IN_PROGRESSprocessingin_progressнетГенерируется. progress содержит процент в виде строки, например "60%".
SUCCESSsucceededcompletedдаГотово. Получите результат через /content.
FAILUREfailedfailedдаОкончательная ошибка. Причина указана в fail_reason; зарезервированная квота возвращается.
UNKNOWNunknownunknownнетПровайдер перестал сообщать состояние, понятное шлюзу. Продолжайте опрос с ограничением по времени, затем выполните сверку — не считайте это ни успехом, ни ошибкой.

Проверяйте конечные статусы, а не «не выполняется»

Считайте succeeded / completed и failed единственными точками остановки, а всё остальное — включая значения, которых нет в этой таблице, — выполняющимся. Новые промежуточные состояния могут появиться; новые конечные — это несовместимое изменение, и их не будет.

UNKNOWN — не ошибка

Задача может оставаться в UNKNOWN, если провайдер перестал сообщать состояние, понятное шлюзу. Опрашивайте её с ограничением по времени и передавайте человеку или задаче сверки: если считать это ошибкой, повтор будет оплачен дважды, а если успехом — пользователь получит пустой результат.

#Безопасный цикл опроса

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

poll.py
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)

Продолжение после перезапуска

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

#Хранение результатов

Запрашивайте /content только после успеха. Сохраните полученный URL платформы в своей записи и скачайте собственную копию, если требования к хранению предполагают независимое хранилище.

Проблема не решена?

Пришлите нам ID запроса или текст ошибки, и мы разберёмся.