GEMINI LABEN
PRO35 — 報道が目標日としていた7月17日を過ぎましたが、Gemini 3.5 Proの公式発表もモデルカードも本日時点で確認できていません。予備日として7月24日が挙げられていますNB2LITE — Nano Banana 2 Lite(Gemini 3.1 Flash-Lite Image)が登場しました。約4秒で画像を生成し、1,000枚あたり0.034ドルという水準ですOMNI — Gemini Omni Flashが公開プレビューに入りました。最長10秒の動画を生成でき、価格は出力1秒あたり0.10ドルですEDIT — Omni Flashは会話による編集を軸に設計されています。登場人物の差し替え、ライティングの変更、アングルの調整を自然文で指示でき、元の音声と映像のトラックは保持されますSYNTHID — 新しい2モデルにはSynthIDの電子透かしが組み込まれており、生成物の来歴をGeminiアプリ側から確認できますSHUTDOWN — 旧来の画像生成モデルは非推奨となり、8月17日に停止されます。移行の期限をご確認いただければと思いますPRO35 — 報道が目標日としていた7月17日を過ぎましたが、Gemini 3.5 Proの公式発表もモデルカードも本日時点で確認できていません。予備日として7月24日が挙げられていますNB2LITE — Nano Banana 2 Lite(Gemini 3.1 Flash-Lite Image)が登場しました。約4秒で画像を生成し、1,000枚あたり0.034ドルという水準ですOMNI — Gemini Omni Flashが公開プレビューに入りました。最長10秒の動画を生成でき、価格は出力1秒あたり0.10ドルですEDIT — Omni Flashは会話による編集を軸に設計されています。登場人物の差し替え、ライティングの変更、アングルの調整を自然文で指示でき、元の音声と映像のトラックは保持されますSYNTHID — 新しい2モデルにはSynthIDの電子透かしが組み込まれており、生成物の来歴をGeminiアプリ側から確認できますSHUTDOWN — 旧来の画像生成モデルは非推奨となり、8月17日に停止されます。移行の期限をご確認いただければと思います
記事一覧/開発ツール
開発ツール/2026-07-03上級

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

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

Gemini API189TTS2ストリーミング11音声生成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-07-18
難読化されたスタックトレースを Gemini に渡していました — retrace を前段に置くまで、診断はもっともらしく外れ続けます
release ビルドのスタックトレースは R8 で名前が潰れています。それをそのまま Gemini に渡すと、診断は落ち着いた文体のまま外れます。retrace を前段に置き、mapping を versionCode で突合し、復元できないときは断定させない。42件で数え直した記録です。
開発ツール2026-07-16
生成ログを丸ごと残すのをやめました — 3層の保持設計とプロンプト指紋で追跡性だけを残す
障害調査のために Gemini API のリクエストとレスポンスを丸ごと保存していました。3層の保持設計とプロンプト指紋に切り替え、本文を消しても原因を辿れる状態を保った記録です。
開発ツール2026-07-09
例外にならない失敗を型で閉じる — Gemini API のレスポンスを判別可能ユニオンに正規化する
HTTP 200 なのに本文が空、という失敗は try/catch では捕まりません。finishReason と blockReason を判別可能ユニオンに正規化し、never による網羅性チェックで処理漏れをコンパイル時に潰す設計をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →