텍스트 음성 변환 생성 (TTS)

Gemini API는 Gemini 텍스트 음성 변환 (TTS) 생성 기능을 사용하여 텍스트 입력을 단일 화자 또는 다중 화자 오디오로 변환할 수 있습니다. 텍스트 음성 변환 생성은 제어 가능합니다. 즉, 구조화된 턴 메타데이터 (speech_metadata)와 인라인 음성 태그를 결합하여 오디오의 스타일, 억양, 속도, 어조를 안내할 수 있습니다.

TTS 기능은 대화형, 구조화되지 않은 오디오, 멀티모달 입력 및 출력을 위해 설계된 Live API를 통해 제공되는 음성 생성과 다릅니다. Live API는 동적 대화 컨텍스트에 적합하지만 Gemini API를 통한 TTS는 포드캐스트 또는 오디오북 생성과 같이 스타일과 사운드를 세부적으로 제어하여 정확한 텍스트 암송이 필요한 시나리오에 맞게 설계되었습니다.

이 가이드에서는 Gemini 3.8 Flash TTS(gemini-3.8-flash-tts) 및 Gemini 3.8 Flash-Lite TTS(gemini-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))

자바스크립트

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에서 두 화자를 구성하고 각 턴을 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))

자바스크립트

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 파일을 반환함)과 달리 스트리밍 요청은 기본적으로 헤더가 없는 원시 16비트 부호 있는 little-endian 선형 PCM (audio/l16, 24kHz, 모노) 청크를 반환하므로 컨테이너 헤더 없이 오디오 청크를 연속으로 재생하거나 연결할 수 있습니다.

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)

자바스크립트

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 헤더 (24kHz, 모노, 16비트 부호 있는 little-endian PCM)가 포함된 완전한 WAV (audio/wav) 오디오를 반환합니다. WAV 헤더를 수동으로 추가하지 않고 디코딩된 오디오 바이트를 .wav 파일에 직접 저장할 수 있습니다.
  • 스트리밍 요청 (stream=True): 각 청크에 컨테이너 헤더가 없어도 청크를 연속으로 스트리밍하거나 연결할 수 있도록 기본적으로 헤더가 없는 원시 선형 PCM(audio/l16) 청크 (24kHz, 모노, 16비트 부호 있는 little-endian PCM)를 반환합니다.

다른 오디오 인코딩 또는 샘플링 레이트를 요청하려면 response_format 내에서 mime_type 및 선택적 sample_rate를 구성합니다.

형식 mime_type 설명
WAV (단항 기본값) "audio/wav" RIFF 헤더가 있는 비압축 WAV 파일 (16비트 부호 little-endian PCM, 모노, 24kHz 기본값) 단항 요청의 기본값입니다.
원시 PCM (L16) (스트리밍 기본값) "audio/l16" 비압축, 헤더 없는 16비트 부호 little-endian 선형 PCM 오디오 (24kHz, 모노) 스트리밍 요청의 기본값입니다.
Mu-law "audio/mulaw" 8비트 G.711 mu-law 인코딩 오디오 (북미 및 일본 전화 통신/IVR 시스템에서 흔히 사용됨)
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))

자바스크립트

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 (CreateVoiceGetVoice에서 지속적인 voice_... ID와 sample_audio WAV 미리보기를 반환하는 type="prompted")를 사용하여 맞춤 음성 페르소나를 생성합니다.
  4. 음성 복제: Google AI Studio에서 참조 및 동의 오디오를 사용하거나 POST /v1beta/voices (type="replicated", 기본적으로 영구 store=True 또는 선택적 상태 비저장 store=False)를 사용하여 화자의 음성을 복제합니다.

맞춤 음성 한도 및 TTL

음성 유형 저장 모드 할당량 / 한도 보관 (TTL)
스테이트풀(Stateful) 음성(voice_..., 프롬프트 또는 복제) store=True 프로젝트당 200개의 음성 (프롬프트 음성 및 복제된 음성 간에 공유) 1년
스테이트리스(Stateless) 음성 키(voicekey_..., 복제됨) store=False 클라이언트 관리 7일

기본 제공 음성

Zephyr -- Bright Puck - 경쾌함 카론 - 유용한 정보
Kore - Firm Fenrir - Excitable Leda - Youthful
Orus -- Firm Aoede -- Breezy Callirrhoe - 느긋함
Autonoe -- 밝음 엔셀라두스 -- 숨소리 Iapetus -- Clear
Umbriel - 느긋함 Algieba -- Smooth Despina - Smooth
Erinome - 맑음 Algenib - 자갈 Rasalgethi - 유용한 정보를 전달함
Laomedeia - 경쾌함 Achernar -- Soft Alnilam -- Firm
Schedar -- Even Gacrux - 성인용 Pulcherrima - 앞으로
Achird - 친근함 Zubenelgenubi -- 캐주얼 Vindemiatrix - 온화함
Sadachbia - 활기참 Sadaltager -- 지식이 풍부함 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 (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}"
    )

자바스크립트

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)는 101개 언어를 지원합니다.

언어 Gemini 3.8 Flash TTS Gemini 3.8 Flash-Lite TTS
아체어 (아랍어 스크립트) ✔️ ✔️
아프리칸스어 ✔️ ✔️
아칸어 ✔️ ✔️
암하라어 ✔️ ✔️
아르메니아어 ✔️ ✔️
아삼어 ✔️ ✔️
아와디어 ✔️ ✔️
발리어 ✔️ ✔️
벵골어 ✔️ ✔️
반자르어 (아랍어 스크립트) ✔️
반자르어 (라틴 문자) ✔️ ✔️
바시키르어 ✔️
바스크어 ✔️ ✔️
벨라루스어 ✔️ ✔️
벰바어 ✔️
보지푸리어 ✔️ ✔️
보스니아어 ✔️ ✔️
부기어 ✔️ ✔️
불가리아어 ✔️ ✔️
버마어 ✔️
광둥어 ✔️ ✔️
카탈로니아어 ✔️ ✔️
세부아노어 ✔️ ✔️
소라니어 ✔️ ✔️
차티스가르어 ✔️ ✔️
중국어 (한스 스크립트) ✔️ ✔️
중국어 (Hant 스크립트) ✔️ ✔️
크림 타타르어 ✔️
크로아티아어 ✔️ ✔️
체코어 ✔️ ✔️
덴마크어 ✔️ ✔️
네덜란드어 ✔️ ✔️
드율라어 ✔️
종카어 ✔️
이집트 아랍어 ✔️ ✔️
영어 ✔️ ✔️
에스토니아어 ✔️ ✔️
필리핀어 ✔️ ✔️
핀란드어 ✔️
프랑스어 ✔️ ✔️
갈리시아어 ✔️ ✔️
간다어 ✔️ ✔️
조지아어 ✔️ ✔️
독일어 ✔️ ✔️
그리스어 ✔️ ✔️
과라니어 ✔️
구자라트어 ✔️ ✔️
아이티 크리올어 ✔️ ✔️
할흐 몽골어 ✔️ ✔️
하우사어 ✔️ ✔️
히브리어 ✔️ ✔️
힌디어 ✔️ ✔️
헝가리어 ✔️ ✔️
아이슬란드어 ✔️ ✔️
이그보어 ✔️
일로카노어 ✔️ ✔️
인도네시아어 ✔️ ✔️
이란 페르시아어 ✔️ ✔️
이탈리아어 ✔️ ✔️
일본어 ✔️ ✔️
자바어 ✔️ ✔️
커바일어 ✔️
캄바어 ✔️ ✔️
칸나다어 ✔️ ✔️
카슈미르어 (아랍어 스크립트) ✔️ ✔️
카슈미르어 (데바 문자) ✔️ ✔️
카자흐어 ✔️ ✔️
크메르어 ✔️ ✔️
키쿠유어 ✔️ ✔️
키냐르완다어 ✔️ ✔️
콩고어 ✔️ ✔️
한국어 ✔️ ✔️
키르기스어 ✔️ ✔️
라오어 ✔️ ✔️
라트갈레어 ✔️
링갈라어 ✔️ ✔️
리투아니아어 ✔️
룩셈부르크어 ✔️
마케도니아어 ✔️ ✔️
마가히어 ✔️ ✔️
마이틸리어 ✔️ ✔️
말라얄람어 ✔️ ✔️
몰타어 ✔️ ✔️
마니푸르어 ✔️ ✔️
마라타어 ✔️ ✔️
미낭카바우어 (아랍어 스크립트) ✔️ ✔️
미낭카바우어 (라틴 문자) ✔️
미조어 ✔️ ✔️
네팔어 (개별 언어) ✔️ ✔️
나이지리아 풀풀데어 ✔️ ✔️
북아제르바이잔어 ✔️ ✔️
소토어(북부) ✔️ ✔️
북부 우즈베크어 ✔️ ✔️
노르웨이어(보크말) ✔️ ✔️
노르웨이어(뉘노르스크) ✔️ ✔️
니안자어 ✔️ ✔️
오크어 ✔️
오리야어 (개별 언어) ✔️ ✔️
팡가시난어 ✔️
페르시아어(아프가니스탄) ✔️ ✔️
폴란드어 ✔️ ✔️
포르투갈어 ✔️ ✔️
펀자브어 ✔️ ✔️
루마니아어 ✔️ ✔️
러시아어 ✔️ ✔️
산탈어 ✔️ ✔️
세르비아어 ✔️ ✔️
신드어 ✔️
싱할라어 ✔️ ✔️
슬로바키아어 ✔️ ✔️
슬로베니아어 ✔️
소말리어 ✔️
남아제르바이잔어 ✔️ ✔️
남부 파슈토어 ✔️ ✔️
소토어(남부) ✔️
스페인어 ✔️ ✔️
표준 아랍어 (아랍어 스크립트) ✔️ ✔️
표준 아랍어 (라틴 문자) ✔️ ✔️
표준 라트비아어 ✔️ ✔️
표준 말레이어 ✔️ ✔️
스와힐리어 (개별 언어) ✔️
스와티어 ✔️
스웨덴어 ✔️
타지크어 ✔️
타밀어 ✔️ ✔️
텔루구어 ✔️ ✔️
태국어 ✔️
티그리냐어 ✔️
토스크 알바니아어 ✔️
위구르어 ✔️

지원되는 모델

모델 단일 화자 다중 화자 음성 디자인 음성 복제
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 프리뷰 TTS ✔️ ✔️

어떤 모델을 언제 사용해야 하나요?

두 Gemini 3.8 TTS 모델은 정확히 동일한 API 스키마와 프롬프트 형식을 공유하므로 단일 파라미터 변경으로 모델 간에 전환할 수 있습니다.

  • 최고의 음향 충실도, 섬세한 연기, 표현력 있는 제어가 최우선 순위인 경우 Gemini 3.8 Flash TTS(gemini-3.8-flash-tts)를 사용하세요. 스튜디오급 창작 작업, 복잡한 다중 화자 대화, 과도한 보컬 버스트 태그, 어려운 발음, 지역 또는 소수 언어 방언, 안정적인 음성과 룸톤이 필요한 긴 형식의 내레이션에 적합합니다.
  • gemini-3.1-flash-tts-preview을 대체하는 빠르고 비용 효율적인 작업용 모델로 Gemini 3.8 Flash-Lite TTS(gemini-3.8-flash-lite-tts)를 사용하세요. 대량 생산, 대화형 음성 에이전트 캐스케이드, 읽어주기 기능, 안정적인 음성 복제, 주요 언어의 일상적인 단일 화자 음성에 최적화되어 있습니다.

이전 가이드

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. Voice 디자인으로 미리 페르소나 디자인: 여러 단락으로 된 "Audio Profile" 또는 "Director's Notes" 블록을 Voice 디자인에서 만든 맞춤 음성으로 바꾼 다음 style 문자열이 최소화되거나 비어 있는 TTS 요청을 통해 voice_... ID를 전달합니다.
  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, 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")과 같은 지속적인 전달 속성을 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..."

속도 조절 및 일시중지

다음 세 가지 수준의 세부사항으로 리듬과 무음을 제어할 수 있습니다.

  • 구두점 및 줄임표: 자연스러운 대화의 망설임을 위해 쉼표, 대시 (--), 줄임표 (...)를 사용합니다.
  • 인라인 일시중지 태그: 화자가 일시중지해야 하는 스크립트의 정확한 지점에 <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."
  • 중복 및 인터리브된 음성: 여러 파이프 세그먼트를 사용하여 두 화자 간의 동시 또는 인터리브된 음성을 시뮬레이션합니다 (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_... 페르소나를 생성한 다음 TTS 호출을 통해 해당 음성 ID를 전달합니다.
  • 안정성을 위해 음성 참조 사용 (메타 지침 생략): 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 텍스트 청크가 도착하면 턴당 TTS 호출을 한 번 실행합니다.
  • 구성된 voice (사전 빌드, 설계된 voice_... 또는 복제된 voice_... / voicekey_...)가 턴마다 화자의 ID를 전달하도록 합니다. 턴마다 긴 캐릭터 페르소나를 다시 전송하지 마세요.
  • 턴별 style 필드를 비워 두거나 전체 대화에 대해 짧은 상수 문자열(예: "casual, friendly") 하나를 보냅니다.
  • 강한 스타일 프롬프트를 사용하는 대신 긴 상담사 응답을 짧은 턴으로 분할하세요.

제한사항

  • TTS 모델은 텍스트 전용 입력을 허용하고 오디오 전용 출력을 생성합니다.
  • 단일 요청 다중 화자 생성 (multiSpeakerVoiceConfig/다중 화자 speakers)은 사전 제작된 음성을 사용하여 최대 2명의 화자를 지원합니다. 여러 캐릭터 대화에서 맞춤 설계된 (voice_...) 또는 복제된 (voicekey_...) 음성을 결합하려면 각 화자의 턴을 개별적으로 합성하고 24kHz PCM 오디오 프레임을 연결하세요.
  • 맞춤 음성 저장소 한도 및 TTL:
    • 상태 저장 음성 (store=True, 프롬프트 또는 복제): 1년 TTL (수명)이 적용되는 프로젝트당 최대 200개의 음성
    • 상태 비저장 음성 키 (store=False, voicekey_...): 7일 TTL(수명)
  • 지원되는 언어 섹션에서 언어 지원 범위를 검토하세요.

다음 단계