GEMINI LABEN
SUNSET — 画像生成モデルの停止は本日8月17日です。imagen-4.0-generate-001・ultra・fast と Gemini 3 Image 系が対象で、以降の呼び出しはハードエラーになりますSCALE — 8月11日に Gemini の月間アクティブユーザーが10億に到達しましたASSISTANT — 9月4日から Android と Wear OS で Google アシスタントが Gemini へ置き換わります。完了まで数週間かかる見込みで、一度切り替わると元には戻せませんDEVICES — 対象は Android スマートフォン・タブレット、Wear OS、アシスタント対応ヘッドフォン、投影型 Android Auto です。Google ビルトイン搭載車は継続しますSPARK — 8月13日から Gemini 3.7 Flash が Gemini Spark のエンジンになりました。AI Pro・Ultra 契約者向けに160か国超で提供されていますPRICE — Gemini 3.7 Flash の導入価格は100万トークンあたり入力 0.75ドル・出力 3.75ドルで、12月31日までです。以後は 1.50ドル・7.50ドル になりますSUNSET — 画像生成モデルの停止は本日8月17日です。imagen-4.0-generate-001・ultra・fast と Gemini 3 Image 系が対象で、以降の呼び出しはハードエラーになりますSCALE — 8月11日に Gemini の月間アクティブユーザーが10億に到達しましたASSISTANT — 9月4日から Android と Wear OS で Google アシスタントが Gemini へ置き換わります。完了まで数週間かかる見込みで、一度切り替わると元には戻せませんDEVICES — 対象は Android スマートフォン・タブレット、Wear OS、アシスタント対応ヘッドフォン、投影型 Android Auto です。Google ビルトイン搭載車は継続しますSPARK — 8月13日から Gemini 3.7 Flash が Gemini Spark のエンジンになりました。AI Pro・Ultra 契約者向けに160か国超で提供されていますPRICE — Gemini 3.7 Flash の導入価格は100万トークンあたり入力 0.75ドル・出力 3.75ドルで、12月31日までです。以後は 1.50ドル・7.50ドル になります
記事一覧/開発ツール
開発ツール/2026-07-03上級

音声が全部できるまで待たせない — Gemini TTS ストリーミング生成を配信経路に組み込む設計

gemini-3.1-flash-tts-preview が streamGenerateContent に対応しました。最初の音が出るまで実測1.8秒の配信経路を、PCM境界処理・文単位の再開・preview停止フォールバックまで含めて設計します。

Gemini API212TTS2ストリーミング12音声生成3FastAPI

プレミアム記事

個人開発で運営している Dolice Labs のサイト群で、記事を音声でも聴けるようにする実験を続けております。

これまでのボトルネックは生成そのものではなく「待ち時間」でした。3,800字ほどの原稿をバッチの TTS に渡すと、音声ファイルが完成するまで平均41秒。ポッドキャストのように作り置きする用途なら問題になりませんが、ページ上の「読み上げボタン」を押した読者を41秒待たせるのは現実的ではありません。

2026年7月の変更で、この前提が変わりました。gemini-3.1-flash-tts-preview が streamGenerateContent 経由のストリーミング音声生成に対応し、音声を「作り終えてから配る」のではなく「作りながら配る」経路を組めるようになりました(Gemini API changelog)。

実際に配信経路を作り直してみると、SDK の呼び出し自体は簡単な一方で、その先の「配り方」にいくつも設計判断が必要でした。ここからは、その過程で確定した構成をコードと実測値でまとめておきます。

「作ってから配る」と「作りながら配る」で何が変わるか

同じ TTS でも、バッチとストリーミングでは設計の重心が別物です。最初にここを整理しておくと、後の判断がぶれません。

観点バッチ生成(作ってから配る)ストリーミング生成(作りながら配る)
最初の音までの時間原稿全体の生成完了まで(実測41秒/3,800字)先頭チャンク到着まで(実測1.8秒)
成果物完成したファイル(WAV/MP3)PCM チャンクの列。ファイルは後から組み立てる
失敗時の意味論最初から再生成すればよい(冪等)途中まで再生済み。どこから再開するかの設計が必要
向く用途ポッドキャスト・動画ナレーション・作り置き読み上げボタン・対話 UI・その場で聴かせる導線

私の結論を先に書くと、アーカイブ用の音声はバッチのまま残し、「その場で聴かせる」導線だけをストリーミングに切り替えました。両方をストリーミングに寄せる必要はありません。

受け口 — streamGenerateContent から PCM チャンクを取り出す

サーバー側の受け口はこれだけです。ポイントは、チャンクから取り出せるのが 24kHz・16bit・モノラルの生 PCM だという点です。

# tts_stream.py — ストリーミング TTS の受け口
from google import genai
from google.genai import types
 
client = genai.Client()  # GEMINI_API_KEY を環境変数から読み込みます
 
TTS_MODEL = "gemini-3.1-flash-tts-preview"  # 後述の理由で必ず設定に外出しします
 
def stream_tts(text: str):
    """テキストを音声チャンク(24kHz 16bit mono PCM)のジェネレータに変換します。"""
    stream = client.models.generate_content_stream(
        model=TTS_MODEL,
        contents=text,
        config=types.GenerateContentConfig(
            response_modalities=["AUDIO"],
            speech_config=types.SpeechConfig(
                voice_config=types.VoiceConfig(
                    prebuilt_voice_config=types.PrebuiltVoiceConfig(
                        voice_name="Kore"
                    )
                )
            ),
        ),
    )
    for chunk in stream:
        if not chunk.candidates:
            continue
        part = chunk.candidates[0].content.parts[0]
        if part.inline_data and part.inline_data.data:
            yield part.inline_data.data

これを HTTP に載せます。FastAPI ならチャンク転送そのままです。

# server.py — チャンク転送で配る
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from tts_stream import stream_tts
 
app = FastAPI()
 
@app.get("/tts")
def tts(text: str):
    return StreamingResponse(
        stream_tts(text),
        media_type="audio/L16;rate=24000;channels=1",
        headers={"Cache-Control": "no-store"},
    )

Content-Type を audio/L16 にしているのは意図的です。ここで「なぜ普通に WAV で返さないのか」という問題に突き当たります。

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
streamGenerateContent の音声チャンクを FastAPI からチャンク転送で配る最小構成と、最初の音が出るまで実測1.8秒(バッチ比 約23分の1)のレイテンシ設計
長さ未確定のまま WAV を配れない問題への3つの選択肢の比較と、生PCM+クライアント再生に落ち着いた判断根拠(Int16境界の持ち越しバッファ実装つき)
途中切断をバイト位置ではなく文境界で再開する chunk map 設計と、preview モデル停止に備えたバッチへの自動フォールバック
Stripe による安全な決済 · いつでもキャンセル可能

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Gemini Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • コピー&ペーストで使える実装コード付き
  • 毎日新しい上級ガイドを追加
  • ¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

開発ツール2026-08-17
配布済みアプリに残るモデル名と、停止日をまたいだ切り戻しの設計
サーバー側の移行が終わっても、ユーザーの端末で動いている旧バージョンのアプリは古いモデル名を握ったままです。停止日をまたぐと切り戻しが復旧手段でなくなる構造と、モデル解決をサーバーに寄せる設計をまとめます。
開発ツール2026-08-05
テストは緑のまま、本番だけが止まる — 録画フィクスチャがモデル停止を隠す構造と freshness gate
録画済み API レスポンスで回るテストは、モデル停止をすり抜けます。テストが全部緑のまま本番だけ404になる構造を最小構成で再現し、pytest 起動前に cassette を検疫する freshness gate の実装、走査コストの実測、しきい値の決め方をまとめました。
開発ツール2026-07-25
gemini-flash-latest への追従をやめた日 — モデルの静かな置き換えに耐えるバッチ設計
発表を伴わないモデル更新で、安定していたバッチの拒否率が一晩で4倍を超えました。gemini-flash-latest への追従をやめ、ピン留めとカナリア昇格の二段構えに移行するまでの実測と設計判断をまとめております。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →