公式 SDK
5 言語に対応した公式 SDK
パッケージを 1 つインストールすれば、自分のサーバーから画像・動画・音声モデルを呼び出せます。認証と結果の待機は SDK が引き受けるので、リクエストを書いて答えを読むだけです。
SDK が代わりにやってくれること
書くのは関数の呼び出し 1 回だけ。リクエストの署名、ファイルのアップロード、結果の待機は SDK が行い、結果は型付きのデータで返ります。
- あなたのコード関数を 1 回呼ぶだけ
- 公式 SDK署名、アップロード、結果の待機を担当
- 画像・動画・音声モデルウェブサイトと同じモデル、同じ料金
こんなときに
- バックエンドサービス自社の API やジョブキューの中でメディアを生成できます。
- スクリプトとバッチ処理スプレッドシートや定期ジョブから、まとめてタスクを作成できます。
- サーバーのあるアプリキーはサーバーに置いたまま、完成したファイルだけをユーザーに届けられます。
3 ステップで始める
- ステップ 1
API キーを作成
コンソールで作成し、サーバーに SPICY_API_KEY として保存します。
- ステップ 2
パッケージをインストール
下から使う言語を選んで、インストールのコマンドを実行します。
- ステップ 3
タスクを作成して結果を受け取る
プロンプトを送り、タスクの完了を待って、返ってきたファイルを保存します。
言語を選ぶ
どの SDK も各言語の主要なレジストリで公開されていて、同じ API につながります。タブを切り替えると、インストール方法と完全なリクエスト例を確認できます。
npm install @spicyapi/sdk
export SPICY_API_KEY="injected from your secret manager"import { randomUUID } from "node:crypto";
import { SpicyClient } from "@spicyapi/sdk";
const client = new SpicyClient();
const model = await client.getModel("MODEL_ID_FROM_CATALOG");
const task = await client.run(
{ model: model.model, input: { prompt: "A cinematic night portrait" } },
{ idempotencyKey: randomUUID() },
);
console.log(task.state, task.output?.assets?.[0]?.url);pip install spicyapi
export SPICY_API_KEY="injected from your secret manager"import uuid
from spicyapi import SpicyClient, output_assets
client = SpicyClient() # reads SPICY_API_KEY from the environment
model = client.get_model("MODEL_ID_FROM_CATALOG")
quote = client.quote_task(
model=model["model"],
input_data={"prompt": "A cinematic night portrait"},
)
print(quote["estimatedCost"], quote["maxCharge"]) # decide before you spend
task = client.create_task(
model=model["model"],
input_data={"prompt": "A cinematic night portrait"},
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"])Go
github.com/spicyapi-ai/spicy-goGo 1.23+ が必要です
標準ライブラリだけで動くので、依存グラフには何も増えません。go get で今すぐ使えます。
go get github.com/spicyapi-ai/spicy-go
export SPICY_API_KEY="injected from your secret manager"client, err := spicy.New(spicy.Options{}) // reads SPICY_API_KEY from the environment
if err != nil {
return err
}
request := spicy.CreateTaskInput{
Model: "MODEL_ID_FROM_CATALOG",
Input: map[string]any{"prompt": "A cinematic night portrait"},
}
quote, err := client.Quote(ctx, request)
if err != nil {
return err
}
request.QuoteID = quote.QuoteID
request.ExpectedCost = quote.EstimatedCost
// Store this next to your own record of the job before sending it: its whole
// purpose is to still be there after the crash that lost the response.
key, err := spicy.NewIdempotencyKey()
if err != nil {
return err
}
task, err := client.CreateTask(ctx, request, key, spicy.CreateTaskOptions{})
if err != nil {
return err
}
final, err := client.WaitForTerminal(ctx, task.TaskID, spicy.WaitOptions{})
if err != nil {
return err
}
for _, asset := range final.ReadyAssets() {
log.Println(asset.URL)
}composer require spicyapi/spicyapiuse SpicyApi\SpicyClient;
$client = new SpicyClient(); // reads SPICY_API_KEY from the environment
$quote = $client->quote('MODEL_ID_FROM_CATALOG', ['prompt' => 'A cinematic night portrait']);
printf("at most %s\n", $quote['maxCharge']); // decide before you spend
$task = $client->createTask(
model: $quote['model'],
input: ['prompt' => 'A cinematic night portrait'],
idempotencyKey: SpicyClient::idempotencyKey(),
quoteId: $quote['quoteId'],
expectedCost: $quote['estimatedCost'],
);
$final = $client->waitForTerminal($task['taskId']);
foreach (SpicyClient::readyAssets($final) as $asset) {
echo $asset['url'], "\n";
}Java
ai.spicyapi:spicyapi-java:0.1.0Java 17+, Jackson が必要です
record と Jackson。run() が作成と待機をまとめて行います。
<dependency>
<groupId>ai.spicyapi</groupId>
<artifactId>spicyapi-java</artifactId>
<version>0.1.0</version>
</dependency>SpicyClient client = SpicyClient.builder().apiKeyFromEnvironment().build();
CreateTaskRequest request = CreateTaskRequest.of(
"MODEL_ID_FROM_CATALOG",
Map.of("prompt", "A cinematic night portrait"));
TaskQuote quote = client.quote(request); // free; reserves nothing
System.out.println("this will cost at most " + quote.maxCharge());
TaskRecord task = client.run( // createTask + waitForTerminal
request.withQuote(quote), UUID.randomUUID().toString());
// Transcription and similar endpoints answer in text and return no files at all.
task.outputText().ifPresent(System.out::println);
for (TaskAsset asset : task.assets()) {
asset.url().ifPresent(System.out::println);
}送信したあとの流れ
画像・動画の生成は、作成の呼び出しが返ったあとも続きます。タスク ID を保存しておき、完了は Webhook か、回数を区切ったステータス確認で受け取ってください。
- createTask冪等キー付きで送れば、同じ生成が二重に受理されることはありません。
- taskId応答はすぐ返り、タスクは裏で走り続けます。
- Webhook / recordInfoまず署名付き Webhook。ポーリングは復旧手段です。
- output.assetsそのまま使える URL が返ります。残すものは自分側に保存してください。
ブラウザやモバイルアプリから呼ぶ場合
クライアントアプリに入れたキーは、公開されたキーと同じです。キーはサーバーに置きましょう。@spicyapi/proxy がフロントエンドからのリクエストに認証情報を付けるので、アプリ側にキーが渡ることはありません。
- アプリの中にキー誰でも読み取れて、残高を使われてしまいます。
- キーを内蔵したアプリ
- SpicyAPI
- サーバーにキーアプリはサーバーと通信し、プロキシがキーを付けます。
- ブラウザまたはスマホ
- 自分のサーバー + プロキシ
- SpicyAPI
公開前のチェックリスト
- 01モデルが現在利用可能か確認します。
- 02モデルページの正確な項目で検証します。
- 03API キーをサーバーだけに置きます。
- 04送信前に見積もりを表示します。
- 05taskId をブラウザー外に保存します。
- 06Webhook 署名または状態確認の上限を検証します。
- 07受理後はキャンセル不可として扱います。
よくあるエラーの直し方
最初のつまずきは、たいていこの 3 つのどれかです。カードには、表示される内容と直すポイントを 1 つずつ載せています。
- 401
API キーが無効です
キーがないか、違うキーが API に届いています。コードを実行する環境と同じ場所で SPICY_API_KEY を設定してください。
- 待機
タスクがまだ実行中です
動画は数分かかることがあります。待機には制限時間を付けるか、Webhook を使いましょう。同じ Idempotency-Key を付けずに再送信すると、課金される 2 つ目のタスクができてしまいます。
- リンク
結果のリンクが期限切れです
ダウンロードリンクの有効期間は短めです。古いリンクを保存せず、タスクから新しいリンクを取得してください。
