HiAPI
ブログ

チュートリアル

HiAPI で gemini-3.1-flash-tts を呼び出す方法:curl、Python、そして実行可能なリクエスト

Oct 31, 2026
深靛蓝色背景上多层嵌套的宽箭头依次向右上方推进,箭头前缘为杏橙色,构成规整的信号流示意图形,这是文章的封面图。

gemini-3.1-flash-tts が HiAPI 上でできること

gemini-3.1-flash-tts は、HiAPI の統一 API を通じて提供されるテキスト読み上げモデルです。テキストと音声設定を送信すると、プラットフォームが生成した音声を返します。単一の一貫したインターフェースで公開されているため、モデルごとに個別の統合は不要です。同じ認証ヘッダー、同じベース URL、そして同じ非同期タスクパターンが、プラットフォーム上のすべての TTS モデルに適用されます。

以下のような機能が必要な場合に、このモデルを選択できます。

  • マルチスピーカーのナレーション。 台本、対話、ポッドキャスト風のコンテンツなど、異なるセグメントが異なる声で聞こえるべき場合。
  • 迅速なターンアラウンド。 flash シリーズは低遅延生成を指向しており、インタラクティブなアプリケーションや厳しい SLA を持つバッチ処理で特に重要です。
  • 予測可能な統合インターフェース。 1 つのリクエスト形式で、1 行のテキストからマルチスピーカーシナリオまで、あらゆるケースに対応できます。

すでに他の HiAPI モデルを呼び出しているアプリケーションを構築中であれば、音声機能の追加はモデル識別子を置き換え、リクエストボディを調整するだけです。新しい SDK も、新しい認証情報フローも不要です。

前提条件と認証設定

初回呼び出しの前に、以下を用意してください。

  1. HiAPI アカウントと API キー。 コンソールからキーを生成します。機密情報として扱い、ソースコード管理にコミットしないでください。
  2. HiAPI ベース URL。 すべてのリクエストは同じホストに送信されます。異なるのはエンドポイントごとのパスのみです。
  3. HTTP リクエストを送信するツール。 素早いテスト用の curl、およびスクリプト用の Python 3.9+ と requests ライブラリ。

認証は Authorization リクエストヘッダーにベアラートークンを含める形で行います。

Authorization: Bearer $HIAPI_API_KEY

キーはハードコードせず、環境変数に保存してください。

export HIAPI_API_KEY="your_key_here"

以下で説明する各エンドポイント(タスク送信、ステータス確認、ファイル取得)は、すべて同じリクエストヘッダーを使用します。401 を受け取った場合、リクエストヘッダーが欠落しているか、形式が誤っているか、キーが失効しています。環境間で 1 つのキーを共有するのではなく、コンソールでキーをローテーションしてください。

マルチスピーカー音声用のリクエストボディを構築する

リクエストボディは JSON です。最低限、モデル識別子と入力内容を含める必要があります。マルチスピーカー出力の場合は、名前付き話者を音声にマッピングする話者設定を追加し、入力テキスト内で話者タグによりマークします。

典型的なリクエストボディは次のようになります。

{
  "model": "gemini-3.1-flash-tts",
  "input": {
    "text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
    "multi_speaker": true,
    "speakers": [
      { "name": "Host", "voice": "voice_a" },
      { "name": "Guest", "voice": "voice_b" }
    ]
  }
}

つまずきやすい重要なポイント:

  • 話者名は完全に一致させる必要があります。 speakers 配列内の name は、テキスト内で使用されるタグ(この例では角括弧内)と完全に一致しなければなりません。大文字と小文字の不一致は、マルチスピーカーレンダリングが失敗する最も一般的な原因です。
  • すべてのタグを宣言する必要があります。 テキストが [Narrator] を参照しているのに、name: "Narrator" を定義する話者が存在しない場合、リクエストは拒否されます。
  • 音声識別子はプラットフォームの音声カタログから取得します。 推測せず、HiAPI が提供する識別子を使用してください。シングルスピーカータスクの場合は、multi_speaker と speakers を省略し、代わりに単一の voice フィールドを設定します。
  • テキストは単一の文字列として送信します。 長い台本でも問題ありませんが、プラットフォームに記載されたリクエストごとの制限に注意してください。

リクエストボディが検証に合格すると、タスクが受け付けられ、ポーリングに使用するタスク識別子が返されます。

curl で実行する

上記のリクエストボディを payload.json として保存し、送信します。

curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d @payload.json

レスポンスには、id と status フィールド(通常は queued または processing)を持つタスクオブジェクトが含まれます。

{ "id": "job_abc123", "status": "queued" }

進捗を確認するには、ID でタスクを取得します。

curl "$HIAPI_BASE_URL/v1/audio/speech/jobs/job_abc123" \
  -H "Authorization: Bearer $HIAPI_API_KEY"

status が succeeded になると、レスポンスには音声ファイル参照(URL またはファイル ID)が含まれ、後続のリクエストでダウンロードできます。詳細は以下のポーリングセクションを参照してください。タスクが失敗した場合、status は failed になり、原因を説明する error フィールドが含まれます。

素早い実験の場合は、ファイルを省略して JSON をインラインで直接指定できます。

curl -X POST "$HIAPI_BASE_URL/v1/audio/speech/jobs" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gemini-3.1-flash-tts","input":{"text":"Hello from HiAPI.","voice":"voice_a"}}'

Python で実行する

Python バージョンでは requests と小さなヘルパー関数を使用して、ポーリングループを読みやすく保ちます。リクエストボディは curl の例とまったく同じです。

import os
import time
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
BASE_URL = os.environ["HIAPI_BASE_URL"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

payload = {
    "model": "gemini-3.1-flash-tts",
    "input": {
        "text": "[Host] Welcome back to the show. [Guest] Thanks for having me.",
        "multi_speaker": True,
        "speakers": [
            {"name": "Host", "voice": "voice_a"},
            {"name": "Guest", "voice": "voice_b"},
        ],
    },
}

resp = requests.post(
    f"{BASE_URL}/v1/audio/speech/jobs",
    headers={**HEADERS, "Content-Type": "application/json"},
    json=payload,
    timeout=30,
)
resp.raise_for_status()
job = resp.json()
job_id = job["id"]
print("submitted", job_id)

while True:
    r = requests.get(f"{BASE_URL}/v1/audio/speech/jobs/{job_id}", headers=HEADERS, timeout=30)
    r.raise_for_status()
    status = r.json()
    if status["status"] in ("succeeded", "failed"):
        break
    time.sleep(2)

if status["status"] == "failed":
    raise RuntimeError(status.get("error"))

print("audio ready:", status["output"])

注意事項:

  • タイムアウトは重要です。 各リクエストに明示的にタイムアウトを設定してください。ハングしたポーリングループは、失敗したループよりも悪いです。
  • ポーリングを過度に頻繁に行わないでください。 短い台本には 2 秒の間隔が妥当ですが、長い台本ではバックオフすべきです。
  • リクエストボディを関数内に置きます。 実際のコードでは、テキスト、話者、音声をパラメーター化し、シングルスピーカータスクにも同じ送信ロジックを再利用できるようにします。

非同期タスクをポーリングして音声をダウンロードする

音声生成は非同期です。タスクを送信し、タスクが終了状態に達するまでステータスを確認します。終了状態は 2 つあります——succeeded と failed です。それ以外のすべての状態は「待機を継続」とみなすべきです。

堅牢なポーリングプログラムは次のようにすべきです。

  1. 総待機時間を制限する。 高速なモデルでも他の作業の後ろに並ぶことがあります。妥当な上限で停止し、呼び出し側が再試行できるようタスク ID を公開します。
  2. 指数バックオフ。 1〜2 秒から開始し、上限まで倍増させます。これにより、長いタスクで API に過度な負荷をかけずに済みます。
  3. 失敗を明示的に処理する。 status == "failed" の場合は、error フィールドを読み取って記録します。これは通常、リクエストボディの問題(未宣言の話者、空のテキスト、サポートされていない音声)を示しています。

タスクが成功すると、ステータスレスポンスには出力参照が含まれます。同じ認証ヘッダーを使用してダウンロードします。

out = status["output"]
audio = requests.get(out["url"], headers=HEADERS, timeout=60)
audio.raise_for_status()
with open("narration.wav", "wb") as f:
    f.write(audio.content)

レスポンスが URL ではなくファイル ID を返す場合は、HiAPI 上の対応するファイルエンドポイントを通じて取得してください。元のタスク ID を保存したファイルと一緒に保存してください。これは、後で不良レンダリングをそのリクエストに追跡するための唯一の信頼できる方法です。

文字単位の課金を理解する

HiAPI 上の gemini-3.1-flash-tts は、入力テキストの文字数に基づいて課金されます。リクエスト単位や分単位の課金要素をモデル化する必要はありません。タスクのコストは送信するテキスト量に応じて拡大するため、見積もりは簡単です。すべての台本の総文字数に現在の文字単価を掛けるだけです。

実際の影響:

  • 公開前に見積もる。 予想される月間テキスト量を合計し、料金パネルに表示される現在の単価と照合してください。単価をコードにハードコードしないでください。ビルド時にプラットフォームから読み取るか、設定に保存してください。
  • 長いコンテンツがコストを支配する。 10 分間のナレーションは主にテキストコストです。オーディオブックやコース教材を生成する場合は、まずボリュームをモデル化してください。
  • 再試行には費用がかかります。 生成後に失敗したタスクは、失敗モードによっては課金される可能性があります。送信前にクライアント側で検証してください。すべての話者タグが宣言され、テキストが空でないことを確認します。
  • 積極的にキャッシュする。 同じ台本が繰り返しレンダリングされる場合(例:デモやテストフィクスチャ)、生成された音声を保存して再利用し、同じ文字に対して繰り返し課金されないようにします。

現在の料金と量に応じた階層については、ウェブサイトの料金パネルを参照してください。それが唯一の信頼できる情報源です。

よくある失敗ポイントとその修正方法

ほとんどの統合問題は少数のカテゴリに分類されます。順番に確認してください。

401 未認証

Authorization リクエストヘッダーが欠落しているか、形式が誤っています。キーが環境に設定されていること、およびヘッダー内容が正確に Bearer <key> であることを確認してください。キーがローテーションされた場合は、環境を更新してください。

400 不正なリクエスト——不明な話者

テキストに、speakers で宣言されていない [Name] タグが含まれているか、大文字と小文字が一致していません。タグと name フィールドをバイト単位で完全に一致させてください。

400 不正なリクエスト——入力が空または大きすぎる

空のテキストは即座に検証に失敗します。非常に長い台本はリクエストごとの制限を超える可能性があります。切り詰めるのではなく、複数のタスクに分割してください。

400 不正なリクエスト——無効な音声識別子

音声名はプラットフォームのカタログから取得する必要があります。識別子を正確にコピーしてください。独自の分かりやすい名前を作らないでください。

タスクが processing 状態でスタックする

これは通常、キュー待ちであり、バグではありません。バックオフと総タイムアウトを適用してください。通常よりはるかに長い時間が経過しても続く場合は、タスク ID を記録し、サイズが問題かどうかを判断するために、より小さなリクエストボディで一度再試行してください。

タスクが failed になり、生成エラーが付随する

error フィールドを読み取ってください。これは通常、一時的な障害ではなく、コンテンツまたは設定の問題を示しています。リクエストボディを修正して再送信し、盲目的な再試行ループは避けてください。試行ごとに文字が課金される可能性があります。

音声はダウンロードできるが再生できない

ファイルが破損していると仮定する前に、ダウンロードしたファイルのコンテンツタイプを確認してください。返された形式に対応する正しい拡張子で保存し、バイト長がゼロでないことを検証してください。ファイルが切り詰められている場合は、通常、ダウンロードリクエストが中断されたことを意味します。再生成するのではなく、ダウンロードを再試行してください。

これらのチェックにより、ほとんどの初日の統合問題は数時間ではなく数分で解決できます。

永続的なAIアーティファクトで開発を始める

APIキーを取得して、タスクベースの1つのAPIで画像・動画・音声モデルを呼び出せます。

APIドキュメントを読む