יצירת המרת טקסט לדיבור (TTS)

‫Gemini API יכול להפוך קלט טקסט לאודיו עם דובר אחד או כמה דוברים באמצעות יכולות יצירת הטקסט לדיבור (TTS) של Gemini. הפקת טקסט לדיבור היא ניתנת לשליטה, כלומר אפשר לשלב מטא-נתונים מובְנים של תור (speech_metadata) ותגי קול מוטבעים כדי להגדיר את הסגנון, המבטא, הקצב והטון של האודיו.

יכולת ה-TTS שונה מיצירת דיבור שמתבצעת באמצעות Live API, שנועד לאודיו אינטראקטיבי ולא מובנה, ולתשומות ולתפוקות מולטי-מודאליות. ‫Live API מצטיין בהקשרים דינמיים של שיחות, אבל TTS דרך Gemini API מותאם לתרחישים שבהם נדרש דיבור מדויק של טקסט עם שליטה מפורטת בסגנון ובצליל, כמו יצירת פודקאסטים או ספרי אודיו.

במדריך הזה מוסבר איך ליצור אודיו עם דובר אחד או עם כמה דוברים מטקסט באמצעות Gemini 3.8 Flash TTS (gemini-3.8-flash-tts) ו-Gemini 3.8 Flash-Lite TTS (gemini-3.8-flash-lite-tts).

לפני שמתחילים

חשוב לוודא שאתם משתמשים במודל Gemini TTS שמופיע בקטע מודלים נתמכים. כדי לקבל את התוצאות הטובות ביותר, כדאי לעיין במאמר מתי כדאי להשתמש באיזה מודל כדי לבחור את המודל המתאים ביותר לעומס העבודה שלכם.

מומלץ לבדוק את מודלי ה-TTS של Gemini ב-AI Studio לפני שמתחילים לפתח.

TTS עם דובר יחיד

כדי להמיר טקסט לאודיו של דובר יחיד באמצעות מודלים של Gemini 3.8 TTS, מעבירים את התמליל המילולי ב-input, מצרפים סגנון ברמת התור באמצעות הערה speech_metadata ומגדירים את הקול ב-generation_config.speech_config. אפשר לבחור קול מתוך אפשרויות הקול המובנות, מתוך ספריית הקולות המורחבת (GET /v1beta/voices), מתוך מזהה של עיצוב קול בהתאמה אישית (voice_...), או מתוך מזהה של רפליקציה של קולות (voice_..., או voicekey_... אם רוצים להשתמש באפשרות בלי שמירת מצב).

בדוגמה הזו, פלט האודיו (audio/wav) בפורמט 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" }
      ]
    }
  }' | jq -r '[.steps[] | select(.type=="model_output") | .content[] | select(.type=="audio")] | last | .data' | base64 --decode > out.wav

ב-SDK של Python ו-JavaScript, אפשר לאחזר נתוני אודיו שנוצרו באמצעות מאפיין הנוחות interaction.output_audio, שמחזיר את בלוק האודיו האחרון שנוצר (בתגובות JSON של REST גולמיות, האודיו בקידוד base64 מאוחסן ב-steps[].content[].data). פרטים על מאפייני נוחות זמינים בסקירה הכללית על אינטראקציות.

המרת טקסט לדיבור (TTS) עם כמה דוברים

בדיאלוג עם כמה דוברים, מגדירים שני דוברים ב-speech_config.speakers ומעבירים כל תור כפריט טקסט נפרד עם הערה speech_metadata שמציינת את speaker ואת style האופציונלי ברמת התור. שימוש ב-"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. בשונה מבקשות unary (שמחזירות קובץ WAV מלא עם כותרת RIFF), בקשות סטרימינג מחזירות נתחי PCM לינאריים גולמיים של 16 ביט בפורמט little-endian (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 משתמשים בפורמטים שונים של אודיו כברירת מחדל, בהתאם לסוג הבקשה: unary או streaming:

  • בקשות unary ‏ (stream=False): החזרת אודיו מלא בפורמט WAV ‏ (audio/wav) עם כותרת RIFF רגילה (24 kHz, מונו, 16-bit signed little-endian PCM). אפשר לשמור את בייטים של האודיו המפוענח ישירות בקובץ .wav בלי להוסיף ידנית כותרת של WAV.
  • בקשות סטרימינג (stream=True): החזרת נתחים של Linear PCM גולמי ללא כותרת (audio/l16) (24 kHz, מונו, 16-bit signed little-endian PCM) כברירת מחדל, כדי שאפשר יהיה להזרים או לשרשר נתחים ברציפות ללא כותרות של קונטיינר בכל נתח.

כדי לבקש קידוד אודיו או קצב דגימה שונים, מגדירים את mime_type ואת sample_rate האופציונליים בתוך response_format:

פורמט ערך של mime_type תיאור
‫WAV (ברירת מחדל אונרית) "audio/wav" קובץ WAV לא דחוס עם כותרת RIFF (PCM עם סימן של 16 ביט, little-endian, מונו, ברירת מחדל של 24 kHz). ברירת המחדל לבקשות unary.
‫Raw PCM (L16) (ברירת מחדל לסטרימינג) "audio/l16" אודיו PCM ליניארי לא דחוס, ללא כותרת, 16 ביט, חתום, little-endian ‏ (24 kHz, מונו). ברירת המחדל לבקשות סטרימינג.
Mu-law "audio/mulaw" אודיו מקודד ב-8 ביט G.711 mu-law (בשימוש נפוץ במערכות טלפוניה/תגובה קולית אינטראקטיבית בצפון אמריקה וביפן).
A-law "audio/alaw" אודיו מוצפן ב-8 ביט G.711 A-law (בשימוש נפוץ במערכות טלפוניה אירופאיות ובינלאומיות).

אפשר גם לציין את sample_rate בהרץ (לדוגמה, 24000,‏ 16000 או 8000).

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 תומך בארבע דרכים לבחור או ליצור קולות:

  1. קולות מוכנים מראש: 30 קולות שנבחרו בקפידה ומפורטים בטבלה הבאה.
  2. ספריית קולות מורחבת: מאות קולות נוספים בשפות, במבטאים ובארכיטיפים של דמויות שניתן לגשת אליהם באמצעות client.voices.list() (GET /v1beta/voices).
  3. עיצוב קול: יצירת דמות קולית מותאמת אישית מתיאור בשפה טבעית ב-Google AI Studio או באמצעות POST /v1beta/voices (type="prompted", שמחזירה מזהה קבוע voice_... ותצוגה מקדימה של sample_audio WAV ב-CreateVoice וב-GetVoice).
  4. רפליקציה של קולות: שכפול של קול הדובר מאודיו של הפניה והסכמה ב-Google AI Studio או באמצעות POST /v1beta/voices (type="replicated", store=True מתמשך כברירת מחדל או store=False אופציונלי בלי שמירת מצב).

מגבלות וערכי TTL של קולות מותאמים אישית

הכתבה מצב אחסון מכסה / מגבלה שמירה (TTL)
קולות עם מצב (voice_..., בהנחיה או בשכפול) store=True 200 קולות לכל פרויקט (משותפים בין קולות שנוצרו מהנחיות וקולות ששוכפלו) שנה אחת
מפתחות קוליים ללא מצב (voicekey_..., משוכפלים) store=False בניהול של לקוח 7 ימים

קולות שנוצרו מראש

Zephyr -- Bright Puck -- Upbeat ‫Charon -- אינפורמטיבי
Kore -- Firm ‫Fenrir – מתלהב ‫Leda -- Youthful
‫Orus -- Firm ‫Aoede – Breezy ‫Callirrhoe – נינוח
Autonoe -- Bright ‫Enceladus -- Breathy ‫Iapetus -- Clear
Umbriel -- Easy-going ‫Algieba – Smooth Despina -- Smooth
‫Erinome -- Clear ‫Algenib -- מחוספס ‫Rasalgethi -- Informative
‫Laomedeia -- Upbeat ‫Achernar -- Soft ‫Alnilam -- Firm
‫Schedar – Even ‫Gacrux -- Mature ‫Pulcherrima -- Forward
Achird -- Friendly ‫Zubenelgenubi – רגוע ‫Vindemiatrix – עדין
Sadachbia -- Lively Sadaltager -- Knowledgeable ‫Sulafat – חמה

ספריית קולות מורחבת וסינון

בנוסף ל-30 הקולות המוצגים בטבלה שלמעלה, ספריית הקולות המורחבת כוללת מאות קולות נוספים בשפות שונות, עם מבטאים אזוריים, דמויות וסגנונות שונים. אתם יכולים לעיין בספריית הקולות המלאה, לסנן אותה ולשמוע דוגמאות שלה באופן אינטראקטיבי ב-Google AI Studio, או לשלוח אליה שאילתות באופן פרוגרמטי באמצעות client.voices.list() (GET /v1beta/voices, באמצעות google-genai גרסה 2.25.0 ואילך / @google/genai גרסה 2.24.0 ואילך).

‫ListVoices מחזירה את הקולות המותאמים אישית ששמרתם (בסדר מהחדש לישן), ואחריהם את הקולות המוכנים מראש שמתאימים לקריטריונים של המסנן. כשמעבירים כמה ערכים למסנן רשימה, המערכת מחזירה את הקולות שתואמים לכל ערך במסנן הזה (OR), ואילו פרמטרים נפרדים של מסנן משולבים עם AND:

פרמטר סוג תיאור
language_code list[str] תגי שפה בתקן BCP-47 (לדוגמה, ["en-US", "en-GB"]). התאמה מדויקת לא תלוית-רישיות.
region_code list[str] קודים אזוריים לפי תקן ISO 3166-1 alpha-2 או UN 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 (context ב-REST) list[str] דומיין לשימוש אופטימלי (לדוגמה, ["Audiobook", "Conversational", "News"]).
‫type (type_ ב-Python) list[str] סינון לפי מקור הקול: "prebuilt",‏ "prompted" (עיצוב קול) או "replicated" (רפליקציה של קולות).
search str חיפוש מחרוזת משנה בטקסט חופשי התאים ל-display_name ול-description ללא הבחנה בין אותיות רישיות לאותיות קטנות.
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 TTS (gemini-3.8-flash-tts) תומך ביותר מ-130 שפות, ו-Gemini 3.8 Flash-Lite TTS (gemini-3.8-flash-lite-tts) תומך ביותר מ-100 שפות:

שפה Gemini 3.8 Flash TTS Gemini 3.8 Flash-Lite TTS
אצ'ה (כתב ערבי) ✔️ ✔️
אפריקאנס ✔️ ✔️
אקאן ✔️ ✔️
אמהרית ✔️ ✔️
ארמנית ✔️ ✔️
אסאמית ✔️ ✔️
עוואדי ✔️ ✔️
באלינזית ✔️ ✔️
בנגלית ✔️ ✔️
בנג'אר (כתב ערבי) ✔️ —
בנג'אר (כתב לטיני) ✔️ ✔️
בשקירית ✔️ —
בסקית ✔️ ✔️
בלארוסית ✔️ ✔️
במבה ✔️ —
בוג'פורי ✔️ ✔️
בוסנית ✔️ ✔️
בוגינזית ✔️ ✔️
בולגרית ✔️ ✔️
בורמזית ✔️ —
קנטונזית ✔️ ✔️
קטלאנית ✔️ ✔️
סבואנו ✔️ ✔️
כורדית מרכזית ✔️ ✔️
צ'אטיסגארי ✔️ ✔️
סינית (כתב האן) ✔️ ✔️
סינית (כתב האנט) ✔️ ✔️
טטארית של חצי האי קרים ✔️ —
קרואטית ✔️ ✔️
צ'כית ✔️ ✔️
דנית ✔️ ✔️
הולנדית ✔️ ✔️
דיולה ✔️ —
דזונקה ✔️ —
ערבית מצרית ✔️ ✔️
אנגלית ✔️ ✔️
אסטונית ✔️ ✔️
פיליפינית ✔️ ✔️
פינית ✔️ —
צרפתית ✔️ ✔️
גליציאנית ✔️ ✔️
גאנדה ✔️ ✔️
גאורגית ✔️ ✔️
גרמנית ✔️ ✔️
יוונית ✔️ ✔️
גוארני ✔️ —
גוג'ראטי ✔️ ✔️
קריאולית האיטית ✔️ ✔️
מונגולית חלחה ✔️ ✔️
האוסה ✔️ ✔️
עברית ✔️ ✔️
הינדי ✔️ ✔️
הונגרית ✔️ ✔️
איסלנדית ✔️ ✔️
איגבו ✔️ —
אילוקו ✔️ ✔️
אינדונזית ✔️ ✔️
פרסית איראנית ✔️ ✔️
איטלקית ✔️ ✔️
יפנית ✔️ ✔️
ג'אווה ✔️ ✔️
קביל ✔️ —
קאמבה ✔️ ✔️
קנאדה ✔️ ✔️
קשמירית (כתב ערבי) ✔️ ✔️
קשמירית (כתב דוונאגרי) ✔️ ✔️
קזחית ✔️ ✔️
חמרית ✔️ ✔️
קיקויו ✔️ ✔️
קינירואנדה ✔️ ✔️
קונגו ✔️ ✔️
קוריאנית ✔️ ✔️
קירגיזית ✔️ ✔️
לאו ✔️ ✔️
לטגאלית ✔️ —
לינגלה ✔️ ✔️
ליטאית ✔️ —
לוקסמבורגית ✔️ —
מקדונית ✔️ ✔️
מגאהי ✔️ ✔️
מאיטילית ✔️ ✔️
מליאלאם ✔️ ✔️
מלטית ✔️ ✔️
מניפורית ✔️ ✔️
מראטהית ✔️ ✔️
מיננגקבאו (כתב ערבי) ✔️ ✔️
מיננגקבאו (כתב לטיני) ✔️ —
מיזו ✔️ ✔️
נפאלית (שפה ספציפית) ✔️ ✔️
פולפולדה ניגרית ✔️ ✔️
צפון אזרית ✔️ ✔️
סוטו צפונית ✔️ ✔️
אוזבקית צפונית ✔️ ✔️
‏נורבגית ספרותית ✔️ ✔️
נורווגית (Nynorsk) ✔️ ✔️
ניאנג'ה ✔️ ✔️
אוקסיטנית ✔️ —
אורייה (שפה נפרדת) ✔️ ✔️
פנגסינאן ✔️ —
פרסית (אפגניסטן) ✔️ ✔️
פולנית ✔️ ✔️
פורטוגזית ✔️ ✔️
פנג'אבי ✔️ ✔️
רומנית ✔️ ✔️
רוסית ✔️ ✔️
סנטלי ✔️ ✔️
סרבית ✔️ ✔️
סינדהית ✔️ —
סינהאלה ✔️ ✔️
סלובקית ✔️ ✔️
סלובנית ✔️ —
סומלית ✔️ —
אזרית דרומית ✔️ ✔️
פאשטו דרומית ✔️ ✔️
ססוטו ✔️ —
ספרדית ✔️ ✔️
ערבית רגילה (כתב ערבי) ✔️ ✔️
ערבית רגילה (תסריט Latn) ✔️ ✔️
לטבית רגילה ✔️ ✔️
מלאית תקנית ✔️ ✔️
סוואהילי (שפה נפרדת) ✔️ —
סוואטי ✔️ —
שוודית ✔️ —
טג'יקית ✔️ —
טמילית ✔️ ✔️
טלוגו ✔️ ✔️
תאית ✔️ —
תיגרינית ✔️ —
אלבנית טוסק ✔️ —
טורקית ✔️ ✔️
אויגור ✔️ —
וייטנאמית ✔️ ✔️

מודלים נתמכים

מודל דובר יחיד מערכת רמקולים עיצוב קולי רפליקציה של קולות
‫Gemini 3.8 Flash TTS (gemini-3.8-flash-tts) ✔️ ✔️ ✔️ ✔️
‫Gemini 3.8 Flash-Lite TTS ‏ (gemini-3.8-flash-lite-tts) ✔️ ✔️ ✔️ ✔️
תצוגה מקדימה של Gemini 3.1 Flash TTS ✔️ ✔️ — —
Gemini 2.5 Pro Preview TTS ✔️ ✔️ — —

מתי כדאי להשתמש בכל מודל

שני מודלי ה-TTS של Gemini 3.8 חולקים את אותה סכימת API ואת אותו פורמט הנחיות, כך שאפשר לעבור ביניהם באמצעות שינוי של פרמטר אחד:

  • משתמשים ב-Gemini 3.8 Flash TTS (gemini-3.8-flash-tts) כשחשובים לכם במיוחד איכות אקוסטית מקסימלית, משחק ניואנסי ושליטה בהבעה. הוא אידיאלי לעבודות יצירתיות ברמה של אולפן, לדיאלוגים מורכבים עם כמה דוברים, לתגי קול חזקים, להגייה מסובכת, לניבים אזוריים או של מיעוטים ולקריינות ארוכות שדורשות יציבות מושלמת של הקול ושל טון החדר.
  • שימוש ב-Gemini 3.8 Flash-Lite TTS (gemini-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 בכל תור בבקשות עם כמה דוברים: בכל תור בבקשה עם כמה דוברים צריך לציין במפורש את speaker בתוך speech_metadata שמתאים לאחד מהדוברים שהוגדרו.
  4. עיצוב פרסונות מראש באמצעות עיצוב קול: מחליפים בלוקים של "Audio Profile" או "Director's Notes" עם כמה פסקאות בקול מותאם אישית שנוצר בעיצוב קול, ואז מעבירים את מזהה voice_... הזה דרך בקשות ה-TTS עם מחרוזות style מינימליות או ריקות.
  5. הסבר על פלט WAV (audio/wav) שמוגדר כברירת מחדל בבקשות unary: בניגוד למודלים של TTS מגרסה gemini-3.1-flash-tts-preview ומגרסאות קודמות (שבהם הוחזר PCM גולמי audio/l16 ללא כותרת כברירת מחדל), במודל Gemini 3.8 TTS מוחזר אודיו בפורמט WAV (audio/wav) עם כותרת RIFF רגילה כברירת מחדל לבקשות unary.
    • אם הקוד שלכם עטף בעבר בייטים של PCM גולמיים בכותרת WAV (לדוגמה, באמצעות מודול wave של Python או ffmpeg), צריך להסיר את העטיפה הידנית של הכותרת ולכתוב את הבייטים שהוחזרו ישירות לקובץ .wav.
    • אם צינור עיבוד הנתונים דורש אודיו PCM,‏ mu-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") – לשדה style של speech_metadata. כדי ליצור דמות יציבה וביצועים עקביים לאורך התורות, צריך לעצב את האישיות מראש בעיצוב הקול ולהשתמש ב-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..."

קצב ופסק זמן

אתם יכולים לשלוט בקצב ובשקט בשלוש רמות של פירוט:

  • סימני פיסוק ושלוש נקודות: השתמשו בפסיקים, במקפים (--) ובשלוש נקודות (...) כדי ליצור היסוס טבעי בשיחה.
  • תגי השהיה בתוך השורה: מוסיפים את התגים <short pause> או <long pause> בנקודות המדויקות בתסריט שבהן הדובר צריך להשהות את הדיבור: text Hold on, let me think... <short pause> Alright, I've got it.
  • קצב ברמת התור: מגדירים את הערך "style": "speaking rapidly" או "style": "speaking slowly" ב-speech_metadata כדי לשלוט בקצב הדיבור לאורך כל התור.

פרוזודיה וגובה הצליל

משתמשים בתג 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 (דובר א'): "So the launch is Thursday |oh hmm| Are we actually ready?"
    • תור 2 (דובר ב'): "Ready enough |oh really?| The last blocker cleared this morning."
    • תור 3 (דובר א'): "Then let's ship it |absolutely| and watch the dashboards."
  • חפיפה ודיבור לסירוגין: כדי לדמות דיבור בו-זמני או לסירוגין בין שני דוברים, משתמשים בכמה מקטעים עם קו אנכי (האפשרות הזו מתאימה במיוחד ל-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"

עקביות בין יצירות ומה כדאי להימנע ממנו

כדי לשמור על יציבות הזהות הקולית לאורך השיחה, חשוב להקפיד על ההנחיות הבאות:

  • כדאי לעצב את פרסונות הקול מראש בעיצוב הקול במקום להשתמש בבלוקים ארוכים של סגנון: פסקה ארוכה "Audio Profile" ורשימה עם כמה תבליטים "Director's Notes" שהועברו ממודלים קודמים הם הגורם הכי נפוץ לשינוי בקול. אפשר להשתמש באותה אינטואיציה יצירתית מראש בעיצוב קול כדי ליצור דמות voice_... מותאמת אישית קבועה, ואז להשתמש במזהה הקול הזה בקריאות ל-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") רק לתפניות שבהן צריך לבצע התאמה ספציפית של התוצאה, ומשתמשים באותה מחרוזת קצרה בדיוק בתפניות שונות כשרוצים לקבל תוצאה עקבית.

סוכנים קוליים ודיאלוגים רב-שלביים

כשמפתחים סוכני קול לשיחות בזמן אמת או אפליקציות רב-שלביות:

  • להתקשר שיחת TTS אחת בכל תור כשהנתונים מגיעים בחלקים ממודל שפה גדול (LLM).
  • מאפשרים ל-voice שהוגדר (מוכן מראש, מתוכנן voice_... או משוכפל voice_... / voicekey_...) לשמור את זהות הדובר לאורך כל התורות – לא לשלוח מחדש תיאור ארוך של דמות בכל תור.
  • משאירים את השדה style לכל תור ריק, או שולחים מחרוזת קצרה וקבועה (למשל "casual, friendly") לכל השיחה.
  • לפצל תשובות ארוכות של נציגים לתשובות קצרות יותר, במקום להשתמש בהנחיות סגנון חזקות יותר.

מגבלות

  • מודלים של TTS מקבלים קלט של טקסט בלבד ומפיקים פלט של אודיו בלבד.
  • יצירה של כמה דוברים בבקשה אחת (speech_config.speakers) תומכת בעד 2 דוברים באמצעות קולות מוכנים מראש. כדי לשלב קולות מותאמים אישית (voice_...) או קולות משוכפלים (voice_... / voicekey_...) בדיאלוג של כמה דמויות, צריך לבצע סינתזה של כל תור דיבור בנפרד. בגלל שבקשות unary מחזירות audio/wav עם כותרת RIFF של 44 בייט כברירת מחדל, צריך לבקש PCM גולמי ({"type": "audio", "mime_type": "audio/l16"}) או להסיר את כותרת ה-WAV מכל תור לפני שמשלבים את פריימי האודיו של PCM ב-24kHz.
  • מכסות אחסון וערכי TTL של קולות בהתאמה אישית:
    • קולות עם מצב (store=True, בהנחיה או בשכפול): עד 200 קולות לכל פרויקט עם אורך חיים של שנה.
    • מפתחות קוליים ללא שמירת מצב (store=False, voicekey_...): אורך חיים (TTL) של 7 ימים (time-to-live).
  • בקטע שפות נתמכות מפורטות השפות הנתמכות.

המאמרים הבאים