spicyapiドキュメント
SDK
本文

Python SDK

SpicyAPI 公式の Python SDK(spicyapi)のガイドです。インストール、見積もりと最初の生成、ローカルファイルのアップロード、Webhook の検証、すべてのエラーコードの読み方までをまとめています。

spicyapi は、SpicyAPI 公式の Python SDK です。画像・動画・音声の生成を、1 つのクライアントオブジェクトの後ろにまとめます。API キーを付ける、応答のエンベロープをただの辞書に変換する、ほどよく間隔を広げながらタスクの完了を待つ、ローカルファイルを 1 回の呼び出しでアップロードする、Webhook の署名を「内容によって処理時間が変わらない方法」で検証する。こうした作業を、すべて引き受けます。

必要なのは Python 3.11 以降だけで、実行時の依存パッケージはありません。これは意図した設計です。このパッケージが入るのは、あなたがすでに抱えている依存関係の中です。制約を 1 つ増やすたびに、衝突の可能性も 1 つ増えます。

このツールで合っている?

やりたいこと使うもの
自分の Python のコードから SpicyAPI を呼び出すこの SDK
Node.js や TypeScript から呼び出すTypeScript SDK
Go、PHP、Java から呼び出すGo、PHP、Java の各 SDK
コードを書かずに、ターミナルから生成するCLI
AI アシスタントに、SpicyAPI を代わりに呼び出してもらうMCP サーバーと Agent Skill
チャットモデルやテキストモデルを使うSpicyAPI に向けた公式の openai、anthropic、google-genai ライブラリ。テキストとストリーミングを参照

インストール

pip install spicyapi

キーは環境変数に入れてください。そうすれば、コードにもシェルの履歴ファイルにも残りません。

export SPICY_API_KEY="sk-spicy-..."

最初の結果

価格を尋ねて、判断して、タスクを作成し、待って、ファイルを読み取ります。見積もりは無料で、何も確保しません。

import os, uuid
from spicyapi import SpicyClient, output_assets

client = SpicyClient()  # 環境変数から SPICY_API_KEY を読み取ります

model = client.get_model("MODEL_ID_FROM_CATALOG")
quote = client.quote_task(model=model["model"], input_data={"prompt": "a lantern in fog"})
print(quote["estimatedCost"], quote["maxCharge"])   # お金を使う前に判断します

task = client.create_task(
    model=model["model"],
    input_data={"prompt": "a lantern in fog"},
    idempotency_key=str(uuid.uuid4()),
    quote_id=quote["quoteId"],
    expected_cost=quote["estimatedCost"],
)
final = client.wait_for_terminal(task["taskId"])
for asset in output_assets(final):                  # モジュール直下のヘルパー関数で、メソッドではありません
    print(asset["url"])

MODEL_ID_FROM_CATALOG は仮の値です。実際の ID は、認証付きのカタログ(client.list_models()、つまり GET /api/v1/models)から取得してください。記憶や古い Web ページから写してはいけません。モデルは追加・一時停止・終了されるからです。input_data は、そのモデル自身の inputSchema(list_models(include_schema=True) が返します)に従って組み立ててください。受け付けるフィールドは、モデルごとに違います。

金額は米ドルの十進文字列で返ります。浮動小数点数ではありません。2 進数の浮動小数点数では、ほとんどの十進の金額を正確に保持できないからです。比較や加算には decimal.Decimal を使ってください。この API には、クレジットやポイントの仕組みはどこにもありません。

wait_for_terminal は、終端状態のどれかに達した時点で戻ります。終端状態は、成功した状態という意味ではありません。出力を読む前に final["state"] を確認してください。

エンドポイントによっては、ファイルではなくテキストで応答します。モデルが文字起こしやキャプションを返す場合は、先に output_text(final) を読んでください。成果物の一覧しか見ないクライアントは、完全に成功したタスクを「何も生成されなかった」と報告してしまいます。

ローカルのファイルから始める

画像から動画を作る、被写体を差し替える、画像を編集する。どれも、まず素材を当社側に置く必要があります。upload_file は、チケットの発行、ストレージへの PUT、確定という 3 つのステップを 1 回の呼び出しで行い、spicy:// の URI を返します。入力に入れるのは、この URI です。

uploaded = client.upload_file("/path/to/reference.png")
task = client.create_task(
    model="MODEL_ID_FROM_CATALOG",
    input_data={"image": uploaded["uri"], "prompt": "slow dolly in"},
    idempotency_key=str(uuid.uuid4()),
)

公開されている HTTPS の URL なら、アップロードは一切必要なく、そのまま入力に入れられます。画像は 10 MiB まで、音声と動画は 90 MiB までです。残りはメディアにまとめています。

Webhook

verify_webhook はモジュール直下の関数なので、リクエストハンドラーはクライアントを作らずに使えます。比較にかかる時間は内容によって変わらず、タイムスタンプの確認は、署名が正しいと分かったあとにだけ行います。

from spicyapi import verify_webhook

delivery = verify_webhook(
    raw_body=request.body,                      # 解析する前の、そのままのバイト列
    signature=request.headers["X-Webhook-Signature"],
    timestamp=request.headers["X-Webhook-Timestamp"],
    payload_version=request.headers["X-Webhook-Payload-Version"],
    secret=os.environ["SPICY_WEBHOOK_SECRET"],
)

検証するのは生のバイト列です。json.loads してから json.dumps するとバイト列が変わり、署名は二度と一致しなくなります。配信は再試行されるので、配信 ID で重複を取り除いてください。配信の形式と再試行のスケジュールは、Webhook にすべて書いてあります。

エラー

失敗はすべて SpicyApiError として送出され、status、code、request_id、retry_after_seconds を持ちます。分岐は必ず code で行い、メッセージの文面では判断しないでください。メッセージは翻訳されますが、コードは変わりません。

HTTP 503 は、3 つの異なるビジネスコードで共有されています。 そのため、HTTP ステータスだけを見ても、次に何をすべきかは決められません。

コード意味対処
40003アップロードされたバイト列が、チケットと一致しないチケットを取り直して、最初からやり直します
40004そのパラメーターの組み合わせに対応できる構成がないメッセージに書かれているパラメーターを変更します
40201残高が足りないチャージします
40901タスクが作成される前に価格が変わった見積もりを取り直します。冪等キーは同じものを使ってください
503依存している何かが、短時間だけ利用できないRetry-After の秒数だけ待ってから再試行します
50301そのモデルに、いま使える構成も価格もないカタログを取り直します。連打しないでください
50302同期的な生成が上流で失敗し、返金された新しい冪等キーで再試行します

err.recovery は、実行時にこれと同じ案内を返します。サポートに問い合わせるときは request_id を伝えてください。すべてのコードはエラーに一覧があります。

お金を守る 2 つのこと

1 回の送信につき、冪等キーは 1 つに保ってください。 タイムアウトや接続切れのあとも含め、その送信を送り直すときは毎回同じキーを使います。応答が失われたことは、タスクが作成されなかったことの証明にはなりません。新しいキーを使うと、「結果が分からないだけ」だったものが、課金される 2 つ目のタスクに変わります。冪等性を参照してください。

成功したタスクは、結果が期待外れでも課金されます。 価格が気になるときは、先に見積もりを取ってください。quote_task は何も確保せず、何も作成しません。

このパッケージが扱わないこと

  • テキストモデル。 OpenAI、Anthropic、Gemini のリクエスト形式に対応しているので、公式の openai、anthropic、google-genai ライブラリがそのまま使えます。ベース URL を https://api.spicyapi.ai/v1 に向け、キーは同じものを設定してください。テキストとストリーミングを参照してください。
  • ブラウザー・モバイル・デスクトップのアプリ。 このキーを、配布するアプリケーションの中に入れないでください。クライアントに埋め込まれたキーは、公開されたキーと同じです。呼び出しは、必ず自分のサーバーから行ってください。
  • モデルを選んだり、そのフィールドを埋めたりすること。 SDK が渡すのは、カタログと各モデルのスキーマです。何を送るかは、あなたが決めます。
  • タスクのキャンセル。 いったん受理されたタスクは、最後まで実行されます。プログラムを止めても、止まるのはあなたの側の待機だけです。

ソースコード

このパッケージは MIT ライセンスで、github.com/spicyapi-ai/spicy-python で公開のまま開発しています。README は、クライアント全体をいちばん短く見渡せる資料です。このページは、その周りにある考え方を補います。

次のステップ

このページの内容