API リファレンス

非同期タスク

画像、動画、音楽のジョブは、永続的な 1 つのライフサイクルを共有します:1 回だけ送信し、task_id を保存し、終了状態を確認してから結果を取得します。タスク処理を 1 つ作り、モデルごとにエンドポイントの種類だけを選んでください。

#すべての非同期モデルに共通のライフサイクル

  1. 1

    1 回だけ送信

    一意の Idempotency-Key を使い、レスポンスをすぐに保存します。

    POST /v1/{capability}
  2. 2

    task_id を保存

    ワーカーがジョブを確認応答する前に保存します。

    task_id
  3. 3

    ポーリングまたは Webhook の受信

    ステータスは大文字小文字を区別せずに比較し、終了状態で停止します。

    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

#ステータスの値

ライフサイクルは 1 つですが、ステータスの語彙は 2 種類あります。画像、音楽、3D のタスクは OpenAI のタスク用の語を、動画とすべての Webhook ペイロードは OpenAI の動画用の語を報告します。一方のファミリー向けに書いたステータスチェックは、もう一方ではエラーもなく一致しないままになります — この表がその対応表です。

ライフサイクル画像 · 音楽 · 3D動画 · Webhook終了状態意味
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、エンドポイントの種類、モデル、作成日時、自社の業務 ID を保存してください。再起動したワーカーは、2 つ目のタスクを送信・課金することなくポーリングを続けられます。

#結果の保持

/content は成功後に取得してください。結果ファイルはタスク完了から 3 日間保存され、その後 /content は 410(コード media_expired)を返します。残す必要がある場合は 3 日以内にダウンロードしてください。

まだ解決しませんか?

リクエスト ID かエラーメッセージを送っていただければ、こちらで調査します。