🐙

GeminiTTSのはじめかた

に公開

概要

この記事の対象者: Gemini TTS触ったことないけど、興味ある人(逆に細かな設定、最新情報が気になる方はドキュメント見た方がいいかもです!)

この記事を読むとわかること: 対応モデル・基本コード・英語指示(Say/Wait等)・声質/話法/複数話者設定の要点

この記事を読むとできること: Pythonで音声を生成・再生し、声・間・話者を調整したTTSをすぐに動かせる

序説

みなさんTTSはご存知でしょうか?

Google社のNotebookLMツールにもAudio機能がありそこでもTTSが使われています
https://notebooklm.google/

しかも、従来のTTSがSSMLという専門的なタグで制御していたのに対し、Gemini TTSは「ささやいて」「5秒待って」といった自然言語(プロンプト)で直感的に操作できるのが最大の特徴です。

今日はその紹介をしたいと思います!

Gemini TTSとは

TTSとは、「Text to Speech」の略から分かるように文章を音声に変換する技術です。
ユースケースとしてポッドキャスト、オーディオブック、ナレーションなど、高品質で細かな設定をしたい時に最適みたいです。
(リアルタイム性が求められる場合は、Gemini Live APIの音声出力を使うと良いらしいです)

現在はpro版とflash版の2つのモデルが用意されています。
使い分けとして以下のように記載がありました。
https://blog.google/technology/google-deepmind/gemini-2-5-native-audio/?utm_source=chatgpt.com

choose Gemini 2.5 Pro Preview for state-of-the-art quality on complex prompts, or Gemini 2.5 Flash Preview for cost-efficient everyday applications.

指示を忠実に守って高いクオリティにしたい場合はpro,安くしたい場合はflahsという感じみたいです。
flahsでも十分指示を守り、質も高いように思いますので、まずはflahs版から試してみるのがおすすめです!

料金について

https://ai.google.dev/gemini-api/docs/pricing?hl=ja

最新の料金についてはドキュメントを参考ください。
2025年現在は以下の設定になっていました。

他Geminiモデルと同様に無料枠、有料枠ありますがここでは有料枠で計算してみます。

- gemini-2.5-flash-preview-tts gemini-2.5-pro-preview-tts
入力 $0.5/Mtok $1.0/Mtok
出力 $10.0/Mtok $20.0/Mtok
1分間の概算 $0.0016/min $0.0032/min
60分間の概算 $0.0945/h $0.189/h

音声なので、話す速度によってトークン数は変わるのですが、
1分間に150トークン消費するとすると、[1]
gemini-2.5-flash-preview-tts
入力:150 × $0.5 / 1,000,000 = $0.000075
出力:150 × $10 / 1,000,000 = $0.0015
合計:約 $0.001575/分

gemini-2.5-pro-preview-tts
入力:150 × $1 / 1,000,000 = $0.00015
出力:150 × $20 / 1,000,000 = $0.003
合計:約 $0.00315/分

1ドル=150円換算で、flashは約14円/h、proは約28円/hぐらいに収まりそうです。

コードについて

基本編

まずライブラリのimportと、genaiを初期化します。
あと音声を再生させるヘルパー関数も作成しておきます。

from google import genai
from google.genai import types

client = genai.Client(api_key=GOOGLE_API_KEY)

# (Google Colabで音声を再生するためのヘルパー関数)
import contextlib
import wave
from IPython.display import Audio

file_index = 0

@contextlib.contextmanager
def wave_file(filename, channels=1, rate=24000, sample_width=2):
    with wave.open(filename, "wb") as wf:
        wf.setnchannels(channels)
        wf.setsampwidth(sample_width)
        wf.setframerate(rate)
        yield wf

def play_audio_blob(blob):
  global file_index
  file_index += 1

  fname = f'audio_{file_index}.wav'
  with wave_file(fname) as wav:
    wav.writeframes(blob.data)

  return Audio(fname, autoplay=True)

def play_audio(response):
    return play_audio_blob(response.candidates[0].content.parts[0].inline_data)

どのモデルを使用するかMODEL_IDを設定、読んでほしい文章と指示contentsに設定します。
現在対応しているモデルはgemini-2.5-flash-preview-ttsgemini-2.5-pro-preview-tts2つです[2]

MODEL_ID = "gemini-2.5-flash-preview-tts" 
response = client.models.generate_content(
  model=MODEL_ID,
  contents="Say 'こんにちは, TTSのテストだよ!'",
  config={"response_modalities": ['Audio']},
)

出力結果は、以下のinline_dataパスにaudioデータ(blob)が格納されます。[3]
play_audio_blobを使用しGoogle Colabで音声を確認します。
または、play_audioを使用しresponseそのものを使って音声生成することもできます。
こちらは先ほどのヘルパー関数を使用しています。

# blob使用する場合
blob = response.candidates[0].content.parts[0].inline_data
play_audio_blob(blob)

# responseを使用する場合
play_audio(response)


1〜2秒くらいで生成されます。めっちゃ簡単ですね!

指示のやり方

指示はズバリ、contentsに直接書くのみです。
まずは以下のコードを見てみましょう

response = client.models.generate_content(
  model=MODEL_ID,
  contents="""Say "生きてるだけで偉い!", wait 5 seconds then say "そう思いませんか?" """,
  config={
      "response_modalities": ['Audio'],
      "speech_config": {
          "voice_config": {
              "prebuilt_voice_config": {
                  "voice_name": 'Sadaltager'
              }
          }
      }
  },
)

play_audio(response)

話スタイルの指定

例えばcontentsにwait 5 seconds then sayを入れてみることで5秒空白を開けたいなど細かな指示ができます。
contentを日本語で指示すると上手くできないこともありましたので、ドキュメント記載通り
SayreadTTSといった指示は英語で与える方が良さそうです。
また、会話文もカギカッコ「」ではなくダブルクオーてション""を使う方が良さそうです。[4]

もちろんwait in 5 secといった他の書き方もできますので、ご自由にという感じです。

あと、ささやくように話して欲しい場合は以下のようにも書けます

contents="""
Say in an spooky whisper:
"なんかさ...地球は丸いらしいよ"
"""

逆に早口で賢そうな口調にしたい場合は以下のように書くこともできますね

contents="""
Read this disclaimer in as fast a voice as possible while remaining intelligible:

[The author] なまむぎ なまごめ なまたまご!
東京特許許可局!!
隣の客はよく柿食う客だ!!!
バスガス爆発!!!!
"""

そのほかにも「感情」や「アクセント(なまり)」の指定もすることができるみたいです

# 感情を込める
contents="""
Say angrily:
"何度言ったらわかるんだ!"
"""

# アクセントを指定する (英語の場合)
contents="""
Say with a British accent:
"Hello, this is a test of the text-to-speech system."
"""

話者の指定

さてお気づきの方もいらっしゃるでしょうが、
さっきのコードでvoice_nameという項目が増えてますね。
ここでは、話者を指定することができます。
例えば男性の声や女性の声といった分類だけでなく、若い声、大人な声、明るい声、温かみのある声など30種類を選択することができます。

サンプル音声は以下のドキュメントやAI Studioから確認できます。
https://cloud.google.com/text-to-speech/docs/gemini-tts?hl=ja
言葉だけ見ても判断しずらいと思うので、実際に声を聞いてみて判断するのが良さそうです。
30種類もあるので迷ってしまいますが、個人的には以下のような使い分けができそうかなと思いました。

  • ナレーション向き(情報が豊富・落ち着いた声):
    • Charon
    • Rasalgethi
  • 会話・ポッドキャスト向き(明るい・若々しい声):
    • Puck
    • Leda
  • 特徴的な声:
    • Enceladus
    • Algenib

複数人のやり方

次に複数人の声の設定方法を紹介します。
まずはコードをご確認ください!

response = client.models.generate_content(
  model=MODEL_ID,
  contents="""
    Make Speaker1 sound tired and bored, and Speaker2 sound excited and happy:

    Speaker1: ここはどこ?私は誰?
    Speaker2: ここは、地球、あなたは人間!
  """,
  config={"response_modalities": ['Audio']},
)

play_audio(response)

Speaker1, Speaker2と明示し、基本の指定はcontentsで指定ができます。

また、gemini2.5-flash(テキスト生成)とgemini-2.5-flash-preview-tts(音声生成)を組み合わせることで、「AIが書いた台本を、AIが読み上げる」という強力なワークフローを構築できます。

以下の例では、次の3ステップで落語の音声を生成します。

  1. Step 1: 台本生成
    gemini-2.5-flash に、指定したURLを要約する落語の台本を生成させます。
  2. Step 2: 話者設定
    MultiSpeakerVoiceConfig を使い、「八っつぁん」と「熊さん」に別々の声 (Achernar, Algenib) を割り当てる設定オブジェクトを作ります。
  3. Step 3: 音声化
    gemini-2.5-flash-preview-tts に、Step 1の台本とStep 2の設定を渡し、会話音声を生成させます。
transcript = client.models.generate_content(
    model='gemini-2.5-flash',
    contents="""
以下のURLを要約して落語を200文字くらいで生成して。
登場人物は、八っつぁんと熊さんです。
https://cloud.google.com/text-to-speech/docs/gemini-tts
    """
  ).text

print(transcript)
config = types.GenerateContentConfig(
    response_modalities=["AUDIO"],
    speech_config=types.SpeechConfig(
        multi_speaker_voice_config=types.MultiSpeakerVoiceConfig(
            speaker_voice_configs=[
                types.SpeakerVoiceConfig(
                    speaker='八っつぁん',
                    voice_config=types.VoiceConfig(
                        prebuilt_voice_config=types.PrebuiltVoiceConfig(
                            voice_name='Achernar',
                        )
                    )
                ),
                types.SpeakerVoiceConfig(
                    speaker='熊さん',
                    voice_config=types.VoiceConfig(
                        prebuilt_voice_config=types.PrebuiltVoiceConfig(
                            voice_name='Algenib',
                        )
                    )
                ),
            ]
        )
    )
)

response = client.models.generate_content(
  model=MODEL_ID,
  contents="TTS the following conversation between 八っつぁん and 熊さん in 落語: "+transcript,
  config=config,
)

play_audio(response)

出力されたテキストは以下です。

八っつぁん「熊さん、聞いたか? グーグルってぇところが、また妙なもん出しやがった」
熊さん「へぇ、何ですかい?」
八っつぁん「文字を声にする技術なんだが、これがまぁ、まるで人間が喋ってるみてぇなんだと! 感情までこもりやがるってんだから驚きだ」
熊さん「へぇ! じゃあ、八っつぁんの声もそっくりにできちまうんですかい?」
八っつぁん「馬鹿野郎! 俺は唯一無二の声だ! でもな、あんまりリアルだから、誰が機械で誰が本物だか、そのうち分からなくなるってんで、世の中も面白くなりそうだ」
熊さん「そりゃまた、ややこしい話ですなぁ」

キーとしては、
MultiSpeakerVoiceConfig複数話者の設定を行なっています
speakerで登場人物名を指定し、voice_nameでどの話者スタイルでするか設定をします。

Gemini TTSは最大2名まで複数人の対応ができます。
実際に3名以上指定すると確かに以下のエラーが出ました。[5]

ClientError: 400 INVALID_ARGUMENT. 
{'error': {
'code': 400, 
'message':'*GenerateContentRequest.generation_config.speech_config.multi_speaker_voice_config.speaker_voice_configs: the number of enabled_voices must equal 2.\n',
'status': 'INVALID_ARGUMENT'
}}

公式には話者(voice_name)の割り当ては2名までですが、
落語のように「1人の話者が声色を変えて複数の役をする」アプローチは可能です。
完全に別人の声にはならないですが、声のトーンや質が変わる感じです。
またこの時modelはproの方が良さそうです。(flashだとやや単調な音声になっていました)

# 単一話者として設定
config = types.GenerateContentConfig(
    response_modalities=["AUDIO"],
    speech_config=types.SpeechConfig(
        voice_config=types.VoiceConfig(
            prebuilt_voice_config=types.PrebuiltVoiceConfig(
                voice_name='Leda' # 一人の声優に設定
            )
        )
    )
)
response = client.models.generate_content(
  model="gemini-2.5-pro-preview-tts",
  contents="""
  Read the following script like a voice actor playing three different roles (Hattuan, Kuma-san, and Goinkyo)
  Hattuan is fast and high voice
  Kumasan is low and slow voice
  Goinkyo is old man voice
  :

  八っつぁん: "おい、熊さん!"
  熊さん: "なんだい、八っつぁん"
  ご隠居: "まあまあ、二人とも落ち着きなさい"
  """,
  config=config,
)

play_audio(response)

参考資料

詳しい実装は以下のcoockbookを参考にすると良さそうです
https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Get_started_TTS.ipynb?hl=ja

詳しい説明は以下のドキュメントを参考にすると良さそうです
https://cloud.google.com/text-to-speech/docs/gemini-tts?hl=ja

結言

皆さんもぜひ、お気に入りのvoice_nameを見つけて、オリジナルのオーディオコンテンツ制作に挑戦してみてください。

ちなみに本当は、Gemini TTS使ったアプリの技術記事書く予定だったのですが、
文章多くなってきたので記事を切り出してみました。
次回:TTSを使ったアプリ開発に挑戦(仮)

脚注
  1. 以前60分の議事録のトークン数を調べたところ約9000トークンという経験則的に150と設定しました。よくアナウンサーも1分間に300文字で話すと聞きますが、1トークン1.5~2単語と考えると150/minは妥当かなと思います。 ↩︎

  2. ちなみにモデル名をgemini-2.5-flash-ttsにすると404エラーになりました。

    一部ドキュメントにはgemini-2.5-flash-ttsも書かれていましたが、まだpreview版しかなさそうでした。(もう少しでstable版が出ることに期待!)
    https://cloud.google.com/text-to-speech/docs/gemini-tts ↩︎

  3. ちなみにblobはBinary Large OBjectの略で音声や動画などのデータを扱う時に使われます ↩︎

  4. 以下contentsを日本語に直して実験をしました。
    contents="""次の文章を言ってください「生きてるだけで偉い」(5秒待つ)「そう思いませんか?」""",
    結果「生きてるだけで偉い、そう思いませんか、、、そう思いませんか」となぜか同じ単語が繰り返されてました。まだpreview版でもあり調整中なのかもしれないですが、ドキュメントにあるよう英語でやる方が無難だなあと判断しました。
    Note that the model can only do TTS, so you should always tell it to "say", "read", "TTS" something, otherwise it won't do anything.
    https://colab.research.google.com/github/google-gemini/cookbook/blob/main/quickstarts/Get_started_TTS.ipynb?hl=ja#scrollTo=MRWi6kgQQB7l ↩︎

  5. 使用したコード例
    config = types.GenerateContentConfig(
    response_modalities=["AUDIO"],
    speech_config=types.SpeechConfig(
    multi_speaker_voice_config=types.MultiSpeakerVoiceConfig(
    speaker_voice_configs=[
    types.SpeakerVoiceConfig(
    speaker='八っつぁん',
    voice_config=types.VoiceConfig(
    prebuilt_voice_config=types.PrebuiltVoiceConfig(
    voice_name='Achernar',
    )
    )
    ),
    types.SpeakerVoiceConfig(
    speaker='熊さん',
    voice_config=types.VoiceConfig(
    prebuilt_voice_config=types.PrebuiltVoiceConfig(
    voice_name='Algenib',
    )
    )
    ),
    types.SpeakerVoiceConfig(
    speaker='ご隠居',
    voice_config=types.VoiceConfig(
    prebuilt_voice_config=types.PrebuiltVoiceConfig(
    voice_name='Algenib',
    )
    )
    ),
    ]
    )
    )
    )
    response = client.models.generate_content(
    model=MODEL_ID,
    contents="TTS the following conversation between 八っつぁん、 熊さん and ご隠居 in 落語: "+transcript,
    config=config,
    )
    play_audio(response) ↩︎

ちゅらデータ株式会社

Discussion