テキスト読み上げ生成(TTS)

Gemini API は、Gemini のテキスト読み上げ(TTS)生成機能を使用して、テキスト入力を単一話者または複数話者の音声に変換できます。テキスト読み上げの生成は制御可能です。つまり、構造化されたターン メタデータ(speech_metadata)とインライン音声タグを組み合わせて、音声のスタイルアクセントペーストーンを制御できます。

TTS 機能は、インタラクティブな非構造化音声とマルチモーダルな入力と出力用に設計された Live API を介して提供される音声生成とは異なります。Live API は動的な会話コンテキストに優れていますが、Gemini API を介した TTS は、ポッドキャストやオーディオブックの生成など、スタイルやサウンドを細かく制御して正確なテキスト朗読が必要なシナリオ向けに調整されています。

このガイドでは、Gemini 3.8 Flash TTSgemini-3.8-flash-tts)と Gemini 3.8 Flash-Lite TTSgemini-3.8-flash-lite-tts)を使用して、テキストから単一話者と複数話者の音声を生成する方法について説明します。

始める前に

サポートされているモデル セクションに記載されている Gemini TTS モデルを使用してください。最適な結果を得るには、どのモデルをいつ使用するかを確認して、ワークロードに最適なモデルを選択してください。

構築を開始する前に、AI Studio で Gemini TTS モデルをテストすることをおすすめします。

単一話者 TTS

Gemini 3.8 TTS モデルを使用してテキストを単一話者の音声に変換するには、input で文字起こしを渡し、speech_metadata アノテーションを使用してターンレベルのスタイルを適用し、generation_config.speech_config で音声を構成します。音声は、事前構築済みの音声オプション、拡張音声ライブラリ(GET /v1beta/voices)、カスタム音声デザイン ID(voice_...)、ボイス レプリケーション ID(voice_...、またはオプションのステートレス voicekey_...)から選択できます。

次の例では、モデルのデフォルトの WAV 出力音声(audio/wav)をファイルに直接保存します。

Python

import base64
from google import genai

client = genai.Client()

interaction = client.interactions.create(
    model="gemini-3.8-flash-tts",
    input=[{
        "type": "user_input",
        "content": [{
            "type": "text",
            "text": "Have a wonderful day!",
            "annotations": [{
                "type": "speech_metadata",
                "style": "cheerful and friendly",
            }],
        }],
    }],
    response_format={"type": "audio"},
    generation_config={
        "speech_config": [
            {"voice": "Kore"},
        ]
    },
)

with open("out.wav", "wb") as f:
    f.write(base64.b64decode(interaction.output_audio.data))

JavaScript

import * as fs from 'node:fs';
import {GoogleGenAI} from '@google/genai';

async function main() {
   const client = new GoogleGenAI({});

   const interaction = await client.interactions.create({
      model: 'gemini-3.8-flash-tts',
      input: [{
         type: 'user_input',
         content: [{
            type: 'text',
            text: 'Have a wonderful day!',
            annotations: [{
               type: 'speech_metadata',
               style: 'cheerful and friendly',
            }],
         }],
      }],
      response_format: { type: 'audio' },
      generation_config: {
         speech_config: [
            { voice: 'Kore' },
         ],
      },
   });

   const audioBuffer = Buffer.from(interaction.output_audio.data, 'base64');
   fs.writeFileSync('out.wav', audioBuffer);
}
await main();

Go

package main

import (
    "context"
    "encoding/base64"
    "encoding/binary"
    "log"
    "os"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func saveWaveFile(filename string, pcmData []byte) error {
    f, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer f.Close()

    sampleRate := uint32(24000)
    numChannels := uint16(1)
    bitsPerSample := uint16(16)
    byteRate := sampleRate * uint32(numChannels) * uint32(bitsPerSample/8)
    blockAlign := numChannels * (bitsPerSample / 8)
    dataSize := uint32(len(pcmData))

    f.WriteString("RIFF")
    binary.Write(f, binary.LittleEndian, uint32(36+dataSize))
    f.WriteString("WAVEfmt ")
    binary.Write(f, binary.LittleEndian, uint32(16))
    binary.Write(f, binary.LittleEndian, uint16(1))
    binary.Write(f, binary.LittleEndian, numChannels)
    binary.Write(f, binary.LittleEndian, sampleRate)
    binary.Write(f, binary.LittleEndian, byteRate)
    binary.Write(f, binary.LittleEndian, blockAlign)
    binary.Write(f, binary.LittleEndian, bitsPerSample)
    f.WriteString("data")
    binary.Write(f, binary.LittleEndian, dataSize)
    _, err = f.Write(pcmData)
    return err
}

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    generationConfig := &interactions.GenerationConfig{
        SpeechConfig: genai.Ptr(interactions.NewSpeechConfigUnion([]interactions.SpeechConfig{
            {Voice: genai.Ptr("Kore")},
        })),
    }

    res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
            Model: interactions.Model("gemini-3.1-flash-tts-preview"),
            Input: interactions.NewInteractionsInput("Say cheerfully: Have a wonderful day!"),
            ResponseFormat: genai.Ptr(interactions.NewCreateModelInteractionResponseFormat(
                interactions.NewResponseFormat(interactions.AudioResponseFormat{}),
            )),
            GenerationConfig: generationConfig,
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    if res.Interaction.OutputAudio != nil && res.Interaction.OutputAudio.Data != nil {
        pcmBytes, err := base64.StdEncoding.DecodeString(*res.Interaction.OutputAudio.Data)
        if err != nil {
            log.Fatal(err)
        }
        if err := saveWaveFile("out.wav", pcmBytes); err != nil {
            log.Fatal(err)
        }
    }
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.8-flash-tts",
    "input": [{
      "type": "user_input",
      "content": [{
        "type": "text",
        "text": "Have a wonderful day!",
        "annotations": [{
          "type": "speech_metadata",
          "style": "cheerful and friendly"
        }]
      }]
    }],
    "response_format": {
      "type": "audio"
    },
    "generation_config": {
      "speech_config": [
        { "voice": "Kore" }
      ]
    }
  }'

生成された音声データは、最後に生成された音声ブロックを返す interaction.output_audio プロパティを使用して取得できます。コンビニエンス プロパティの詳細については、インタラクションの概要をご覧ください。

マルチスピーカー TTS

複数話者の会話の場合は、speech_config.speakers で 2 人の話者を構成し、各発話を speaker と発話レベルの style(省略可)を指定する speech_metadata アノテーションを含む個別のテキスト アイテムとして渡します。自然なターン交代のケイデンスには "mode": "conversational" を使用します。

Python

import base64
from google import genai

client = genai.Client()

interaction = client.interactions.create(
    model="gemini-3.8-flash-tts",
    input=[{
        "type": "user_input",
        "content": [
            {
                "type": "text",
                "text": "How's it going today Jane?",
                "annotations": [{
                    "type": "speech_metadata",
                    "speaker": "Joe",
                    "style": "cheerful and friendly",
                }],
            },
            {
                "type": "text",
                "text": "Not too bad, how about you? Ready to test these new voices?",
                "annotations": [{
                    "type": "speech_metadata",
                    "speaker": "Jane",
                    "style": "calm and relaxed",
                }],
            },
        ],
    }],
    response_format={"type": "audio"},
    generation_config={
        "speech_config": {
            "mode": "conversational",
            "speakers": [
                {"speaker": "Joe", "voice": "Puck"},
                {"speaker": "Jane", "voice": "Kore"},
            ],
        }
    },
)

with open("out.wav", "wb") as f:
    f.write(base64.b64decode(interaction.output_audio.data))

JavaScript

import * as fs from 'node:fs';
import {GoogleGenAI} from '@google/genai';

async function main() {
   const client = new GoogleGenAI({});

   const interaction = await client.interactions.create({
      model: 'gemini-3.8-flash-tts',
      input: [{
         type: 'user_input',
         content: [
            {
               type: 'text',
               text: "How's it going today Jane?",
               annotations: [{
                  type: 'speech_metadata',
                  speaker: 'Joe',
                  style: 'cheerful and friendly',
               }],
            },
            {
               type: 'text',
               text: 'Not too bad, how about you? Ready to test these new voices?',
               annotations: [{
                  type: 'speech_metadata',
                  speaker: 'Jane',
                  style: 'calm and relaxed',
               }],
            },
         ],
      }],
      response_format: { type: 'audio' },
      generation_config: {
         speech_config: {
            mode: 'conversational',
            speakers: [
               { speaker: 'Joe', voice: 'Puck' },
               { speaker: 'Jane', voice: 'Kore' },
            ],
         },
      },
   });

   const audioBuffer = Buffer.from(interaction.output_audio.data, 'base64');
   fs.writeFileSync('out.wav', audioBuffer);
}

await main();

Go

package main

import (
    "context"
    "encoding/base64"
    "encoding/binary"
    "log"
    "os"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func saveWaveFile(filename string, pcmData []byte) error {
    f, err := os.Create(filename)
    if err != nil {
        return err
    }
    defer f.Close()

    sampleRate := uint32(24000)
    numChannels := uint16(1)
    bitsPerSample := uint16(16)
    byteRate := sampleRate * uint32(numChannels) * uint32(bitsPerSample/8)
    blockAlign := numChannels * (bitsPerSample / 8)
    dataSize := uint32(len(pcmData))

    f.WriteString("RIFF")
    binary.Write(f, binary.LittleEndian, uint32(36+dataSize))
    f.WriteString("WAVEfmt ")
    binary.Write(f, binary.LittleEndian, uint32(16))
    binary.Write(f, binary.LittleEndian, uint16(1))
    binary.Write(f, binary.LittleEndian, numChannels)
    binary.Write(f, binary.LittleEndian, sampleRate)
    binary.Write(f, binary.LittleEndian, byteRate)
    binary.Write(f, binary.LittleEndian, blockAlign)
    binary.Write(f, binary.LittleEndian, bitsPerSample)
    f.WriteString("data")
    binary.Write(f, binary.LittleEndian, dataSize)
    _, err = f.Write(pcmData)
    return err
}

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    prompt := "TTS the following conversation between Joe and Jane:\n" +
        "Joe: How's it going today Jane?\n" +
        "Jane: Not too bad, how about you?"

    generationConfig := &interactions.GenerationConfig{
        SpeechConfig: genai.Ptr(interactions.NewSpeechConfigUnion([]interactions.SpeechConfig{
            {Speaker: genai.Ptr("Joe"), Voice: genai.Ptr("Kore")},
            {Speaker: genai.Ptr("Jane"), Voice: genai.Ptr("Puck")},
        })),
    }

    res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
            Model: interactions.Model("gemini-3.1-flash-tts-preview"),
            Input: interactions.NewInteractionsInput(prompt),
            ResponseFormat: genai.Ptr(interactions.NewCreateModelInteractionResponseFormat(
                interactions.NewResponseFormat(interactions.AudioResponseFormat{}),
            )),
            GenerationConfig: generationConfig,
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    if res.Interaction.OutputAudio != nil && res.Interaction.OutputAudio.Data != nil {
        pcmBytes, err := base64.StdEncoding.DecodeString(*res.Interaction.OutputAudio.Data)
        if err != nil {
            log.Fatal(err)
        }
        if err := saveWaveFile("out.wav", pcmBytes); err != nil {
            log.Fatal(err)
        }
    }
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.8-flash-tts",
    "input": [{
      "type": "user_input",
      "content": [
        {
          "type": "text",
          "text": "How'\''s it going today Jane?",
          "annotations": [{
            "type": "speech_metadata",
            "speaker": "Joe",
            "style": "cheerful and friendly"
          }]
        },
        {
          "type": "text",
          "text": "Not too bad, how about you? Ready to test these new voices?",
          "annotations": [{
            "type": "speech_metadata",
            "speaker": "Jane",
            "style": "calm and relaxed"
          }]
        }
      ]
    }],
    "response_format": {
      "type": "audio"
    },
    "generation_config": {
      "speech_config": {
        "mode": "conversational",
        "speakers": [
          { "speaker": "Joe", "voice": "Puck" },
          { "speaker": "Jane", "voice": "Kore" }
        ]
      }
    }
  }'

メタデータとタグを使用して音声スタイルを制御する

Gemini 3.8 TTS は、text フィールドを厳密に文字起こしとして扱います。ト書きを読み上げずに配信を制御するには、スコープごとに指示を分割します。

  • ターンレベルの持続的な配信(speech_metadata.style): ターン全体に適用される感情、配信スタイル、韻律、ペース、音量を style フィールドに入れます("style": "whispered urgently""style": "out of breath""style": "warm and enthusiastic" など)。
  • 特定の時点のイベント(インライン タグ): 一時的な発話以外の音声のバーストやポーズを、山かっこ("Wait... <short pause> did you hear that? <sigh>""Excuse me <cough> as I was saying..." など)を使用して文字起こしの中に直接配置します。

包括的なベスト プラクティスについては、プロンプト ガイドをご覧ください。

Go

package main

import (
    "context"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    transcriptRes, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
            Model: interactions.Model("gemini-3.8-flash"),
            Input: interactions.NewInteractionsInput(
                "Generate a short transcript around 100 words that reads " +
                    "like it was clipped from a podcast by excited herpetologists. " +
                    "The hosts names are Dr. Anya and Liam.",
            ),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    var transcript string
    if transcriptRes.Interaction.OutputText != nil {
        transcript = *transcriptRes.Interaction.OutputText
    }

    generationConfig := &interactions.GenerationConfig{
        SpeechConfig: genai.Ptr(interactions.NewSpeechConfigUnion([]interactions.SpeechConfig{
            {Speaker: genai.Ptr("Dr. Anya"), Voice: genai.Ptr("Kore")},
            {Speaker: genai.Ptr("Liam"), Voice: genai.Ptr("Puck")},
        })),
    }

    ttsRes, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
            Model: interactions.Model("gemini-3.1-flash-tts-preview"),
            Input: interactions.NewInteractionsInput(transcript),
            ResponseFormat: genai.Ptr(interactions.NewCreateModelInteractionResponseFormat(
                interactions.NewResponseFormat(interactions.AudioResponseFormat{}),
            )),
            GenerationConfig: generationConfig,
        }),
    })
    if err != nil {
        log.Fatal(err)
    }
    _ = ttsRes
}

ストリーミング音声生成

stream: true を設定すると、生成された音声が合成されると同時にストリーミングできます。単項リクエスト(RIFF ヘッダーを含む完全な WAV ファイルを返す)とは異なり、ストリーミング リクエストはデフォルトでヘッダーなしの RAW 16 ビット符号付きリトル エンディアン リニア PCM(audio/l16、24 kHz、モノラル)チャンクを返すため、コンテナ ヘッダーなしでオーディオ チャンクを連続して再生または連結できます。

Python

import base64
from google import genai

client = genai.Client()

stream = client.interactions.create(
    model="gemini-3.8-flash-tts",
    input=[{
        "type": "user_input",
        "content": [{
            "type": "text",
            "text": "Have a wonderful day!",
            "annotations": [{
                "type": "speech_metadata",
                "style": "cheerful and friendly",
            }],
        }],
    }],
    response_format={"type": "audio"},
    generation_config={
        "speech_config": [
            {"voice": "Kore"},
        ]
    },
    stream=True,
)

for event in stream:
    if event.event_type == "step.delta":
        if event.delta.type == "audio":
            audio_data = base64.b64decode(event.delta.data)
            # Process the audio chunk (e.g. play it or write to a file)

JavaScript

import {GoogleGenAI} from '@google/genai';

async function main() {
   const client = new GoogleGenAI({});

   const stream = await client.interactions.create({
      model: 'gemini-3.8-flash-tts',
      input: [{
         type: 'user_input',
         content: [{
            type: 'text',
            text: 'Have a wonderful day!',
            annotations: [{
               type: 'speech_metadata',
               style: 'cheerful and friendly',
            }],
         }],
      }],
      response_format: { type: 'audio' },
      generation_config: {
         speech_config: [
            { voice: 'Kore' },
         ],
      },
      stream: true,
   });

   for await (const event of stream) {
      if (event.event_type === 'step.delta') {
         if (event.delta.type === 'audio') {
            const audioBuffer = Buffer.from(event.delta.data, 'base64');
            // Process the audio buffer
         }
      }
   }
}
await main();

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  --no-buffer \
  -d '{
    "model": "gemini-3.8-flash-tts",
    "input": [{
      "type": "user_input",
      "content": [{
        "type": "text",
        "text": "Have a wonderful day!",
        "annotations": [{
          "type": "speech_metadata",
          "style": "cheerful and friendly"
        }]
      }]
    }],
    "response_format": {
      "type": "audio"
    },
    "generation_config": {
      "speech_config": [
        { "voice": "Kore" }
      ]
    },
    "stream": true
  }'

オーディオ出力形式

Gemini 3.8 TTS モデルは、リクエストが単項かストリーミングかによって、異なるデフォルトの音声形式を使用します。

  • 単項リクエスト(stream=False): 標準 RIFF ヘッダー(24 kHz、モノラル、16 ビット符号付きリトル エンディアン PCM)を含む完全な WAV(audio/wav音声を返します。デコードされた音声バイトを .wav ファイルに直接保存できます。WAV ヘッダーを手動で付加する必要はありません。
  • ストリーミング リクエスト(stream=True): デフォルトでヘッダーなしの RAW リニア PCM(audio/l16チャンク(24 kHz、モノラル、16 ビット符号付きリトル エンディアン PCM)を返します。これにより、各チャンクにコンテナ ヘッダーがなくても、チャンクをストリーミングまたは連続して連結できます。

別の音声エンコードまたはサンプリング レートをリクエストするには、response_format 内で mime_type とオプションの sample_rate を構成します。

形式 mime_type 説明
WAV (単項デフォルト) "audio/wav" RIFF ヘッダー付きの非圧縮 WAV ファイル(16 ビット符号付きリトル エンディアン PCM、モノラル、24 kHz がデフォルト)。単項リクエストのデフォルト。
Raw PCM(L16) (ストリーミングのデフォルト) "audio/l16" 非圧縮、ヘッダーレスの 16 ビット符号付きリトル エンディアン リニア PCM 音声(24 kHz、モノラル)。ストリーミング リクエストのデフォルト。
Mu-law "audio/mulaw" 8 ビットの G.711 mu-law エンコード音声(北米と日本の電話/IVR システムで一般的に使用されています)。
A-law "audio/alaw" 8 ビットの G.711 A-law エンコード音声(ヨーロッパおよび国際的な電話システムで一般的に使用されます)。

sample_rate をヘルツ単位で指定することもできます(24000160008000 など)。

Python

import base64
from google import genai

client = genai.Client()

interaction = client.interactions.create(
    model="gemini-3.8-flash-tts",
    input=[{
        "type": "user_input",
        "content": [{
            "type": "text",
            "text": "Have a wonderful day!",
            "annotations": [{
                "type": "speech_metadata",
                "style": "cheerful and friendly",
            }],
        }],
    }],
    response_format={
        "type": "audio",
        "mime_type": "audio/l16",  # "audio/wav" (default), "audio/l16", "audio/mulaw", or "audio/alaw"
        "sample_rate": 24000,
    },
    generation_config={
        "speech_config": [
            {"voice": "Kore"},
        ]
    },
)

with open("out.pcm", "wb") as f:
    f.write(base64.b64decode(interaction.output_audio.data))

JavaScript

import * as fs from 'node:fs';
import {GoogleGenAI} from '@google/genai';

async function main() {
   const client = new GoogleGenAI({});

   const interaction = await client.interactions.create({
      model: 'gemini-3.8-flash-tts',
      input: [{
         type: 'user_input',
         content: [{
            type: 'text',
            text: 'Have a wonderful day!',
            annotations: [{
               type: 'speech_metadata',
               style: 'cheerful and friendly',
            }],
         }],
      }],
      response_format: {
         type: 'audio',
         mime_type: 'audio/l16', // 'audio/wav' (default), 'audio/l16', 'audio/mulaw', or 'audio/alaw'
         sample_rate: 24000,
      },
      generation_config: {
         speech_config: [
            { voice: 'Kore' },
         ],
      },
   });

   const audioBuffer = Buffer.from(interaction.output_audio.data, 'base64');
   fs.writeFileSync('out.pcm', audioBuffer);
}
await main();

Go

package main

import (
    "context"
    "encoding/base64"
    "log"

    "google.golang.org/genai"
    "google.golang.org/genai/interactions/models/interactions"
    "google.golang.org/genai/interactions/models/operations"
)

func main() {
    ctx := context.Background()
    client, err := genai.NewClient(ctx, nil)
    if err != nil {
        log.Fatal(err)
    }

    generationConfig := &interactions.GenerationConfig{
        SpeechConfig: genai.Ptr(interactions.NewSpeechConfigUnion([]interactions.SpeechConfig{
            {Voice: genai.Ptr("Kore")},
        })),
    }

    res, err := client.Interactions.Create(ctx, operations.CreateInteractionRequest{
        Body: operations.NewCreateInteractionRequestBody(interactions.CreateModelInteraction{
            Model: interactions.Model("gemini-3.1-flash-tts-preview"),
            Input: interactions.NewInteractionsInput("Say cheerfully: Have a wonderful day!"),
            ResponseFormat: genai.Ptr(interactions.NewCreateModelInteractionResponseFormat(
                interactions.NewResponseFormat(interactions.AudioResponseFormat{}),
            )),
            GenerationConfig: generationConfig,
            Stream:           genai.Ptr(true),
        }),
    })
    if err != nil {
        log.Fatal(err)
    }

    stream := res.InteractionSSEStreamEvent
    defer stream.Close()

    for stream.Next() {
        event := stream.Value()
        if stepDelta := event.GetDataStepDelta(); stepDelta != nil {
            if audioDelta := stepDelta.GetDeltaAudio(); audioDelta != nil && audioDelta.Data != nil {
                audioData, err := base64.StdEncoding.DecodeString(*audioDelta.Data)
                if err != nil {
                    log.Fatal(err)
                }
                // Process the audio chunk (e.g. play it or write to a file)
                _ = audioData
            }
        }
    }
    if err := stream.Err(); err != nil {
        log.Fatal(err)
    }
}

REST

curl -X POST "https://generativelanguage.googleapis.com/v1beta/interactions" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.8-flash-tts",
    "input": [{
      "type": "user_input",
      "content": [{
        "type": "text",
        "text": "Have a wonderful day!",
        "annotations": [{
          "type": "speech_metadata",
          "style": "cheerful and friendly"
        }]
      }]
    }],
    "response_format": {
      "type": "audio",
      "mime_type": "audio/l16",
      "sample_rate": 24000
    },
    "generation_config": {
      "speech_config": [
        { "voice": "Kore" }
      ]
    }
  }'

音声オプション

Gemini 3.8 TTS は、音声を選択または作成する 4 つの方法をサポートしています。

  1. プリビルドのスタジオ音声: 次の表に記載されている 30 種類の厳選された音声。
  2. 拡張音声ライブラリ: client.voices.list()GET /v1beta/voices)を使用してアクセスできる、言語、アクセント、キャラクターのアーキタイプにわたる数百もの追加の音声。
  3. 音声設計: Google AI Studio の自然言語の説明から、または POST /v1beta/voicestype="prompted"、永続的な voice_... ID と CreateVoiceGetVoicesample_audio WAV プレビューを返します)を使用して、カスタム音声ペルソナを生成します。
  4. ボイス レプリケーション: Google AI Studio の参照音声と同意音声から、または POST /v1beta/voices(デフォルトでは永続的な type="replicated"store=Trueオプションでステートレスな store=False)を使用して、話者の音声を複製します。

カスタム音声の上限と TTL

音声タイプ ストレージ モード 割り当て / 上限 保持(TTL)
ステートフル音声voice_...、プロンプトまたは複製) store=True プロジェクトあたり 200 個の声(プロンプトと複製された声で共有) 1 年
ステートレス音声キーvoicekey_...、複製) store=False クライアント管理 7 日

事前構築済みの音声

Zephyr -- Bright Puck - Upbeat Charon - Informative
Kore -- Firm Fenrir -- Excitable Leda -- Youthful
Orus -- Firm Aoede -- Breezy Callirrhoe - のんびり屋
Autonoe -- Bright Enceladus -- Breathy Iapetus -- Clear
Umbriel -- Easy-going Algieba -- Smooth Despina - Smooth
Erinome -- 晴れ Algenib -- Gravelly Rasalgethi - 情報が豊富
Laomedeia - アップビート Achernar -- Soft Alnilam -- Firm
Schedar -- Even Gacrux -- 成人向け Pulcherrima - Forward
Achird -- Friendly Zubenelgenubi -- Casual Vindemiatrix - Gentle
Sadachbia -- Lively Sadaltager -- 知識が豊富 Sulafat -- Warm

拡張音声ライブラリとフィルタリング

上記の表に記載されている 30 種類のスタジオ音声に加えて、拡張音声ライブラリでは、言語、地域アクセント、キャラクター ペルソナ、ドメインにわたる数百種類の音声が提供されています。Google AI Studio で音声ライブラリ全体をインタラクティブに閲覧、フィルタ、試聴したり、client.voices.list()google-genai 2.25.0+ / @google/genai 2.24.0+ を使用する GET /v1beta/voices)を使用してプログラムでクエリしたりできます。

ListVoices は、フィルタ条件に一致する事前構築済みカタログ音声の後に、カスタム保存済み音声(新しい順)を返します。リスト フィルタに複数の値が渡された場合、そのフィルタ内のいずれかの値に一致する音声が返されます(OR)。一方、個別のフィルタ パラメータは AND と組み合わされます。

パラメータ 説明
language_code list[str] BCP-47 言語タグ(例: ["en-US", "en-GB"])。大文字と小文字を区別しない完全一致。
region_code list[str] ISO 3166-1 alpha-2 または国連 M.49 地域コード(["US", "GB"] など)。
accent list[str] 地域アクセント記述子(["American", "British"] など)。
gender list[str] 認識された性別の表現("female""male""neutral")。
pitch list[str] 音声のピッチ分類("low""medium""high")。
persona list[str] 音声のペルソナまたはキャラクターのアーキタイプ(["Warm, Friendly"]["Narrator"] など)。
contexts(REST の context list[str] 最適な使用量ドメイン(例: ["Audiobook", "Conversational", "News"])。
type(Python の場合は type_ list[str] 音声ソース("prebuilt""prompted"音声デザイン)、"replicated"ボイス レプリケーション))でフィルタします。
search str フリーテキストの部分文字列検索では、display_namedescription の両方に対して大文字と小文字を区別せずに照合が行われました。
page_size int ページごとに返される音声の最大数(デフォルトは 50、最大は 1000)。
page_token str response.next_page_token からのトークン。結果の次のページを取得します。

Python

from google import genai

client = genai.Client()

# Filter the Voice Library by language, gender, pitch, domain context, and keyword
response = client.voices.list(
    language_code=["en-US", "en-GB"],
    gender=["female"],
    pitch=["medium", "low"],
    contexts=["Audiobook", "Conversational"],
    type_=["prebuilt"],
    search="warm",
    page_size=50,
)

for voice in response.voices or []:
    print(
        f"{voice.id} | {voice.display_name} ({voice.language_code},"
        f" {voice.accent}, {voice.gender}, pitch={voice.pitch}):"
        f" {voice.description}"
    )

JavaScript

import { GoogleGenAI } from "@google/genai";

const ai = new GoogleGenAI();

// Filter the Voice Library by language, gender, pitch, domain context, and keyword
const response = await ai.voices.list({
  language_code: ["en-US", "en-GB"],
  gender: ["female"],
  pitch: ["medium", "low"],
  contexts: ["Audiobook", "Conversational"],
  type: ["prebuilt"],
  search: "warm",
  page_size: 50,
});

for (const voice of response.voices ?? []) {
  console.log(
    `${voice.id} | ${voice.display_name} (${voice.language_code}, ${voice.accent}, ${voice.gender}, pitch=${voice.pitch}): ${voice.description}`
  );
}

REST

curl -G "https://generativelanguage.googleapis.com/v1beta/voices" \
  -H "x-goog-api-key: $GEMINI_API_KEY" \
  --data-urlencode "language_code=en-US" \
  --data-urlencode "language_code=en-GB" \
  --data-urlencode "gender=female" \
  --data-urlencode "pitch=medium" \
  --data-urlencode "context=Audiobook" \
  --data-urlencode "type=prebuilt" \
  --data-urlencode "search=warm" \
  --data-urlencode "page_size=50"

サポートされている言語

TTS モデルは入力言語を自動的に検出します。Gemini 3.8 Flash TTSgemini-3.8-flash-tts)は 130 言語をサポートし、Gemini 3.8 Flash-Lite TTSgemini-3.8-flash-lite-tts)は 101 言語をサポートしています。

言語 Gemini 3.8 Flash TTS Gemini 3.8 Flash-Lite TTS
アチェ語(アラビア文字) ✔️ ✔️
アフリカーンス語 ✔️ ✔️
アカン語 ✔️ ✔️
アムハラ語 ✔️ ✔️
アルメニア語 ✔️ ✔️
アッサム語 ✔️ ✔️
アワディー語 ✔️ ✔️
バリ文字 ✔️ ✔️
ベンガル語 ✔️ ✔️
バンジャール語(アラビア文字) ✔️
バンジャール語(ラテン文字) ✔️ ✔️
バシキール語 ✔️
バスク語 ✔️ ✔️
ベラルーシ語 ✔️ ✔️
ベンバ語 ✔️
ボージュプリー語 ✔️ ✔️
ボスニア語 ✔️ ✔️
ブギス文字 ✔️ ✔️
ブルガリア語 ✔️ ✔️
ビルマ語 ✔️
広東語 ✔️ ✔️
カタルーニャ語 ✔️ ✔️
セブアノ語 ✔️ ✔️
中央クルド語 ✔️ ✔️
チャッティースガリー語 ✔️ ✔️
中国語(漢字) ✔️ ✔️
中国語(繁体字) ✔️ ✔️
クリミア タタール語 ✔️
クロアチア語 ✔️ ✔️
チェコ語 ✔️ ✔️
デンマーク語 ✔️ ✔️
オランダ語 ✔️ ✔️
ジュラ語 ✔️
ゾンカ語 ✔️
エジプト アラビア語 ✔️ ✔️
英語 ✔️ ✔️
エストニア語 ✔️ ✔️
フィリピン語 ✔️ ✔️
フィンランド語 ✔️
フランス語 ✔️ ✔️
ガリシア語 ✔️ ✔️
ガンダ語 ✔️ ✔️
ジョージア語 ✔️ ✔️
ドイツ語 ✔️ ✔️
ギリシャ語 ✔️ ✔️
グアラニ語 ✔️
グジャラート語 ✔️ ✔️
ハイチ語 ✔️ ✔️
ハルハ モンゴル語 ✔️ ✔️
ハウサ語 ✔️ ✔️
ヘブライ語 ✔️ ✔️
ヒンディー語 ✔️ ✔️
ハンガリー語 ✔️ ✔️
アイスランド語 ✔️ ✔️
イボ語 ✔️
イロカノ語 ✔️ ✔️
インドネシア語 ✔️ ✔️
イランのペルシャ語 ✔️ ✔️
イタリア語 ✔️ ✔️
日本語 ✔️ ✔️
ジャワ語 ✔️ ✔️
カビル語 ✔️
カンバ語 ✔️ ✔️
カンナダ語 ✔️ ✔️
カシミール語(アラビア文字) ✔️ ✔️
カシミール語(デーヴァナーガリー文字) ✔️ ✔️
カザフ語 ✔️ ✔️
クメール語 ✔️ ✔️
キクユ語 ✔️ ✔️
キニヤルワンダ語 ✔️ ✔️
コンゴ語 ✔️ ✔️
韓国語 ✔️ ✔️
キルギス語 ✔️ ✔️
ラオ語 ✔️ ✔️
ラトガリア語 ✔️
リンガラ語 ✔️ ✔️
リトアニア語 ✔️
ルクセンブルク語 ✔️
マケドニア語 ✔️ ✔️
マガヒー語 ✔️ ✔️
マイティリー語 ✔️ ✔️
マラヤーラム語 ✔️ ✔️
マルタ語 ✔️ ✔️
マニプリ語 ✔️ ✔️
マラーティー語 ✔️ ✔️
ミナンカバウ語(アラビア文字) ✔️ ✔️
ミナンカバウ語(ラテン文字) ✔️
ミゾ語 ✔️ ✔️
ネパール語(個別の言語) ✔️ ✔️
ナイジェリアン フルフルディ語 ✔️ ✔️
北アゼルバイジャン語 ✔️ ✔️
北ソト語 ✔️ ✔️
ウズベク語北部方言 ✔️ ✔️
ノルウェー語(ブークモール) ✔️ ✔️
ノルウェー語(ニーノシク) ✔️ ✔️
ニャンジャ語 ✔️ ✔️
オック語 ✔️
オディア語(個別の言語) ✔️ ✔️
パンガシナン語 ✔️
ペルシャ語(アフガニスタン) ✔️ ✔️
ポーランド語 ✔️ ✔️
ポルトガル語 ✔️ ✔️
パンジャブ語 ✔️ ✔️
ルーマニア語 ✔️ ✔️
ロシア語 ✔️ ✔️
サンタル語 ✔️ ✔️
セルビア語 ✔️ ✔️
シンド語 ✔️
シンハラ語 ✔️ ✔️
スロバキア語 ✔️ ✔️
スロベニア語 ✔️
ソマリ語 ✔️
南アゼルバイジャン語 ✔️ ✔️
南部パシュトー語 ✔️ ✔️
南ソト語 ✔️
スペイン語 ✔️ ✔️
標準アラビア語(アラビア文字) ✔️ ✔️
標準アラビア語(ラテン文字) ✔️ ✔️
標準ラトビア語 ✔️ ✔️
標準マレー語 ✔️ ✔️
スワヒリ語(個別の言語) ✔️
スワート語 ✔️
スウェーデン語 ✔️
タジク語 ✔️
タミル語 ✔️ ✔️
テルグ語 ✔️ ✔️
タイ語 ✔️
ティグリニャ語 ✔️
トスク アルバニア語 ✔️
ウイグル語 ✔️

サポートされているモデル

モデル 単一話者 マルチスピーカー 音声デザイン ボイス レプリケーション
Gemini 3.8 Flash TTSgemini-3.8-flash-tts ✔️ ✔️ ✔️ ✔️
Gemini 3.8 Flash-Lite TTSgemini-3.8-flash-lite-tts ✔️ ✔️ ✔️ ✔️
Gemini 3.1 Flash TTS プレビュー ✔️ ✔️
Gemini 2.5 Pro プレビュー TTS ✔️ ✔️

どのモデルをいつ使用するか

Gemini 3.8 TTS モデルはどちらも同じ API スキーマとプロンプト形式を共有しているため、1 つのパラメータを変更するだけで切り替えることができます。

  • 音響忠実度、ニュアンスのある演技、表現力豊かな制御を最優先する場合は、Gemini 3.8 Flash TTSgemini-3.8-flash-ttsを使用します。スタジオ品質のクリエイティブな作業、複数の話者による複雑な会話、大量のボーカル バーストタグ、難しい発音、地域や少数派の言語、音声とルームトーンの安定性が求められる長文のナレーションに最適です。
  • Gemini 3.8 Flash-Lite TTSgemini-3.8-flash-lite-ttsを、gemini-3.1-flash-tts-preview の高速で費用対効果の高いワークホースの代替として使用します。大量の一括生成、会話型音声エージェントのカスケード、読み上げ機能、信頼性の高いボイス レプリケーション、主要言語での日常的な単一話者の音声に最適化されています。

移行ガイド

gemini-3.1-flash-tts-preview 以前の Gemini TTS モデルから Gemini 3.8 TTS に移行する場合:

  1. ターンレベルの指示を speech_metadata に移動: Gemini 3.8 TTS は、入力テキストを厳密に逐語録として扱います。持続的な配信指示(style - "whispering""out of breath""speaking slowly" など)とスピーカー ラベル(speaker)を、トランスクリプト テキストに舞台指示を埋め込むのではなく、構造化された speech_metadata アノテーションに移動します。
  2. 山かっこインライン タグは、特定の時点での音声イベントにのみ使用する: 一時的な発話以外の音声や一時停止は、山かっこ(<laugh><sigh><cough><breath><short pause> など)を使用して、文字起こしの中でインラインで保持します。効果音タグ(拍手やドスンという音など)は使用せず、話し方のスタイルは speech_metadata.style に入れます。
  3. 複数話者のリクエストのすべてのターンで speaker を指定する: 複数話者のリクエストのすべてのターンで、構成された話者のいずれかに一致する speech_metadata 内に speaker を明示的に含める必要があります。
  4. 音声設計でペルソナを事前に設計する: "Audio Profile" または "Director's Notes" の複数段落のブロックを、音声設計で作成したカスタム音声に置き換え、その voice_... ID を TTS リクエストに渡します。style 文字列は最小限にするか、空にします。
  5. 単項リクエストのデフォルトの WAV(audio/wav)出力を考慮する: gemini-3.1-flash-tts-preview 以前の TTS モデル(デフォルトでヘッダーなしの未加工 PCM audio/l16 を返した)とは異なり、Gemini 3.8 TTS は、単項リクエストに対してデフォルトで標準 RIFF ヘッダー付きの WAV 音声(audio/wav)を返します。
    • 以前のコードで、未加工の PCM バイトを WAV ヘッダーでラップしていた場合(たとえば、Python の wave モジュールまたは ffmpeg を使用していた場合)、手動のヘッダー ラッパーを削除し、返されたバイトを .wav ファイルに直接書き込みます。
    • パイプラインでヘッダーレスの生の PCM、μ-law、A-law のオーディオが必要な場合は、response_format"audio/l16""audio/mulaw"、または "audio/alaw" に明示的に設定します。オーディオ出力形式をご覧ください。

プロンプト ガイド

Gemini 3.8 TTS モデルは、入力テキストを厳密に逐語録として扱います。以前のプレビュー モデルでは、ト書きがプレーン テキストに埋め込まれていましたが、Gemini 3.8 TTS では、継続的なターンレベルの指示(speech_metadata)がポイントインタイムのインライン音声タグから分離されています。

スタイル フィールドとインライン タグ

パフォーマンスに関する指示をスコープごとに分割します。

  • ターンレベルのデリバリー(speech_metadata.style): 感情、韻律、全体的なペース、デリバリー スタイル("whispering""out of breath""muttering""sarcastic" など)などの持続的なデリバリー属性を speech_metadatastyle フィールドに入れます。ターン全体で安定したキャラクターとパフォーマンスを作成するには、音声デザインでペルソナを事前に設計し、style はオプションのターンレベルの調整にのみ使用します。
  • ポイントインタイム イベント(インライン タグ): 一瞬の音声以外の発声、呼吸、一時停止を、山かっこ(<cough><breath><sigh><short pause>)を使用して文字起こしの中にインラインで挿入します。最高の音質を実現するには、山かっこ(<...>)を使用し、音声以外の効果音ではなく、人間の発声に限定します。
スコープ 設置場所
ターンレベル(ターン全体で維持される) speech_metadata.style "angry tone""speaking rapidly""out of breath""whispers""sarcastic"
ポイントインタイム(特定の単語で発生) text<...>)でインライン "<cough> Thank you all for coming tonight! <throat-clearing> As I was saying..."

ペースと一時停止

リズムと無音は、次の 3 つの粒度レベルで制御できます。

  • 句読点と省略記号: カンマ、ダッシュ(--)、省略記号(...)を使用して、自然な会話の躊躇を表現します。
  • インライン一時停止タグ: 話者が一時停止するスクリプトの正確な位置に <short pause> または <long pause> を挿入します。 text Hold on, let me think... <short pause> Alright, I've got it.
  • ターンレベルのペース: speech_metadata"style": "speaking rapidly" または "style": "speaking slowly" を設定して、ターン全体の発話速度を制御します。

プロソディとピッチ

speech_metadata.style を使用して、ターン全体で韻律、ピッチ、イントネーションを制御します("style": "high pitch, cheerful and excited inflection""style": "monotone and flat" など)。感情や韻律が会話の途中で変化する場合は、スクリプトを別々のターンに分割し、各ターンに異なる style 値を設定します。

強調

文字起こしで特定の単語を大文字にし、句読点とインライン音声タグを組み合わせて、キーワードに自然な音声の強調を付けます。

This is a VERY important point!
It was a VERY long day <sigh> ... nobody listens anymore.

発声と会話以外の音声

音声以外の人の発声は、音が鳴る正確な位置に山かっこ(<...>)を使用してインラインで配置します。推奨される音声タグは次のとおりです。

<argh> <breath> <heavy breath> <exhales>
<cackle> <cheer> <chuckle> / <chuckles> <cough>
<cry> <gasp> <giggle> <groan>
<growl> <grunt> <grr> <hiss>
<laugh> / <laughter> <moan> <pant> <pff> / <phew>
<scream> <shout> <shriek> <sigh> / <sighs>
<sneeze> <snicker> <snort> <sob>
<throat-clearing> <tsk> <whimper> <whispers> / <whispering>
<yawn> <short pause> <long pause>

バックチャネルと音声の重複

複数話者の会話では、話者のターン内でリスナーの反応をパイプ文字(|reaction|)で囲み、反応ごとに別のターンに分割することなく、自然なバックチャネルや重複する発話を作成します。

  • 短いバックチャネルのやり取り: 発言者のターン内の短いリスナーの反応(|oh hmm||oh really?||absolutely|):
    • ターン 1(スピーカー A): "So the launch is Thursday |oh hmm| Are we actually ready?"
    • ターン 2(発言者 B): "Ready enough |oh really?| The last blocker cleared this morning."
    • ターン 3(話者 A): "Then let's ship it |absolutely| and watch the dashboards."
  • 重複する発話とインターリーブされた発話: 複数のパイプ セグメントを使用して、2 人の話者の同時発話またはインターリーブされた発話をシミュレートします(gemini-3.8-flash-tts で最適に動作します)。
    • 同時カウントダウン/コーラス: "Let's surprise him on three |ok| ready?" の後に "one. two. three. |happy| happy |birthday| birthday!"
    • スピーカーの完全な重複: "Hello |oh| there |my| it |goodness| must |gracious| be |would| almost |you| time |look| for |at that| dinner"

世代間の整合性と避けるべきこと

発話者 ID をターン間で安定させるには、次のガイドラインに沿って操作します。

  • 長いスタイル ブロックではなく、音声設計でペルソナを事前に設計する: 以前のモデルから引き継がれた長い "Audio Profile" 段落と複数の箇条書き "Director's Notes" は、音声のずれの最も一般的な原因です。音声設計で同じクリエイティブな直感を使用して、永続的なカスタム voice_... ペルソナを生成し、その音声 ID を TTS 呼び出しに渡します。
  • 安定性のために音声リファレンスに依存する(メタ指示を省略): Gemini 3.8 TTS モデルは、最初に音声リファレンスにアンカーするようにトレーニングされています。音声の安定をモデルに指示する("do not switch speaker identity""maintain identical timbre" など)指示を含めないでください。プロンプト テキストを追加すると、ドリフトが増加します。不要なスタイル指示を削除し、音声参照によって提供される安定点の周りでモデルが自然に変化するようにします。
  • style で不変の発話者特性を変更しようとしない: 年齢、性別、名前、永続的なアクセントの変更を speech_metadata.style に入れないでください。代わりに、拡張音声ライブラリから地域音声を選択するか、音声デザインで作成します。
  1. キャラクターを一度作成する: 音声デザインでキャラクターを作成するか、ターゲット言語とペルソナに一致する地域音声を選択します。
  2. 自然な話し言葉の文字起こしを不流暢さを含めて記述する: 自然さを最大限に高めるには、text を実際の話し言葉の文字起こしとして記述します。会話の不流暢さやためらい("Oh uh yeah I think... hm, so that's interesting" など)も記述します。
  3. まずプレーン TTS をテストする: まず、空の style フィールドを使用して文字起こしを合成します。ほとんどのリクエストでは style 指示は必要ありません。
  4. 調整のみに短い style プロンプトを追加する: 特定の配信調整が必要なターンにのみ、簡潔な style 文字列("casual, friendly""muttering, then reassuring" など)を追加します。一貫したベースラインが必要な場合は、ターン間で同じ短い文字列を再利用します。

マルチターンの対話と音声エージェント

リアルタイムの会話型音声エージェントまたはマルチターン アプリケーションを構築する場合:

  • LLM テキスト チャンクが到着したら、ターンごとに 1 回の TTS 呼び出しを行います。
  • 構成された voice(事前構築、設計された voice_...、複製された voice_... / voicekey_...)に、発言者の ID をターン間で保持させます。各ターンで長い文字のペルソナを再送信しないでください。
  • ターンごとの style フィールドを空のままにするか、会話全体に対して 1 つの短い定数文字列("casual, friendly" など)を送信します。
  • 強いスタイルのプロンプトを使用するのではなく、長いエージェントのレスポンスを短いターンに分割します。

制限事項

  • TTS モデルはテキストのみの入力を受け取り、音声のみの出力を生成します。
  • 単一リクエストの複数話者生成(multiSpeakerVoiceConfig / 複数話者 speakers)は、事前構築済みの音声を使用する最大 2 人の話者をサポートします。マルチキャラクターの会話でカスタム設計(voice_...)または複製(voicekey_...)された音声を組み合わせるには、各話者のターンを個別に合成し、24 kHz の PCM 音声フレームを連結します。
  • カスタム音声の保存容量の上限と TTL:
    • ステートフル音声(store=True、プロンプトまたは複製): プロジェクトあたり最大 200 個の音声1 年間の TTL(有効期間)。
    • ステートレス音声キー(store=Falsevoicekey_...): 7 日間の TTL(有効期間)。
  • 言語の対応状況については、サポートされている言語のセクションをご覧ください。

次のステップ