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 모델을 사용하고 최신 Google 생성형 AI SDK (Python의 경우 google-genai >= 2.25.0, JavaScript/TypeScript의 경우 @google/genai >= 2.24.0)로 업그레이드하거나 REST API를 사용해야 합니다.
최적의 결과를 얻으려면 어떤 모델을 언제 사용해야 하는지를 검토하여 워크로드에 가장 적합한 모델을 선택하세요.
빌드를 시작하기 전에 AI Studio에서 Gemini TTS 모델을 테스트하는 것이 좋습니다.
단일 화자 TTS
Gemini 3.8 TTS 모델을 사용하여 텍스트를 단일 화자 오디오로 변환하려면 input에 축어 스크립트를 전달하고, speech_metadata 주석을 사용하여 발화 수준 스타일을 연결하고, generation_config.speech_config에서 음성을 구성합니다. 사전 빌드된 음성 옵션, 확장 음성 라이브러리(GET /v1beta/voices), 커스텀 음성 디자인 ID(voice_...) 또는 음성 복제 ID(voice_... 또는 선택적 스테이트리스(Stateless) 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();
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
Python 및 JavaScript SDK에서는 interaction.output_audio 편의 속성을 사용하여 생성된 오디오 데이터를 가져올 수 있습니다. 이 속성은 마지막으로 생성된 오디오 블록을 반환합니다 (원시 REST JSON 응답에서 base64 인코딩된 오디오는 steps[].content[].data에 저장됨). 편의 속성에 관한 자세한 내용은 상호작용 개요를 참고하세요.
다중 화자 TTS
여러 화자가 등장하는 대화의 경우 speech_config.speakers에서 두 화자를 구성하고 각 턴을 speaker 및 선택적 턴 수준 style를 지정하는 speech_metadata 주석이 있는 별도의 텍스트 항목으로 전달합니다. speech_config는 단일 화자 생성을 위해 배열 ([{"voice": "..."}])을 허용하고 다중 화자 생성을 위해 객체 ({"speakers": [...]})를 허용합니다.
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": {
"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: {
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();
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...")를 사용하여 스크립트 내에 순간적인 비음성 보컬 버스트 또는 일시중지를 직접 배치합니다.
포괄적인 권장사항은 프롬프트 가이드를 참조하세요.
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": "Wait... <short pause> look under that fallen log! Is that a blue-spotted salamander?",
"annotations": [{
"type": "speech_metadata",
"speaker": "Dr. Anya",
"style": "whispered urgently",
}],
},
{
"type": "text",
"text": "<gasp> No way! <laugh> We've been searching for this species all season!",
"annotations": [{
"type": "speech_metadata",
"speaker": "Liam",
"style": "warm and enthusiastic",
}],
},
],
}],
response_format={"type": "audio"},
generation_config={
"speech_config": {
"speakers": [
{"speaker": "Dr. Anya", "voice": "Kore"},
{"speaker": "Liam", "voice": "Puck"},
],
}
},
)
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: 'Wait... <short pause> look under that fallen log! Is that a blue-spotted salamander?',
annotations: [{
type: 'speech_metadata',
speaker: 'Dr. Anya',
style: 'whispered urgently',
}],
},
{
type: 'text',
text: "<gasp> No way! <laugh> We've been searching for this species all season!",
annotations: [{
type: 'speech_metadata',
speaker: 'Liam',
style: 'warm and enthusiastic',
}],
},
],
}],
response_format: { type: 'audio' },
generation_config: {
speech_config: {
speakers: [
{ speaker: 'Dr. Anya', voice: 'Kore' },
{ speaker: 'Liam', voice: 'Puck' },
],
},
},
});
if (interaction.output_audio?.data) {
const audioBuffer = Buffer.from(interaction.output_audio.data, 'base64');
fs.writeFileSync('out.wav', audioBuffer);
}
}
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" \
-d '{
"model": "gemini-3.8-flash-tts",
"input": [{
"type": "user_input",
"content": [
{
"type": "text",
"text": "Wait... <short pause> look under that fallen log! Is that a blue-spotted salamander?",
"annotations": [{
"type": "speech_metadata",
"speaker": "Dr. Anya",
"style": "whispered urgently"
}]
},
{
"type": "text",
"text": "<gasp> No way! <laugh> We'\''ve been searching for this species all season!",
"annotations": [{
"type": "speech_metadata",
"speaker": "Liam",
"style": "warm and enthusiastic"
}]
}
]
}],
"response_format": {
"type": "audio"
},
"generation_config": {
"speech_config": {
"speakers": [
{ "speaker": "Dr. Anya", "voice": "Kore" },
{ "speaker": "Liam", "voice": "Puck" }
]
}
}
}'
음성 생성 스트리밍
stream: true를 설정하여 생성된 오디오를 합성되는 대로 스트리밍할 수 있습니다. RIFF 헤더가 있는 완전한 WAV 파일을 반환하는 단항 요청과 달리 스트리밍 요청은 기본적으로 헤더가 없는 원시 16비트 부호 있는 리틀 엔디언 선형 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)
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 헤더 (24kHz, 모노, 16비트 부호 있는 little-endian PCM)가 있는 완전한 WAV (audio/wav) 오디오를 반환합니다. 디코딩된 오디오 바이트를 WAV 헤더를 수동으로 추가하지 않고.wav파일에 직접 저장할 수 있습니다. - 스트리밍 요청 (
stream=True): 기본적으로 헤더 없는 원시 선형 PCM(audio/l16) 청크 (24kHz, 모노, 16비트 부호 있는 리틀 엔디안 PCM)를 반환하므로 각 청크에 컨테이너 헤더 없이 청크를 연속적으로 스트리밍하거나 연결할 수 있습니다.
다른 오디오 인코딩 또는 샘플링 레이트를 요청하려면 response_format 내에서 mime_type 및 선택적 sample_rate를 구성합니다.
| 형식 | mime_type 값 |
설명 |
|---|---|---|
| WAV (단항 기본값) | "audio/wav" |
RIFF 헤더가 있는 비압축 WAV 파일 (16비트 부호 리틀 엔디안 PCM, 모노, 24kHz 기본값) 단일 요청의 기본값입니다. |
| 원시 PCM (L16) (스트리밍 기본값) | "audio/l16" |
비압축, 헤더 없는 16비트 부호 리틀 엔디안 선형 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))
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();
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는 음성을 선택하거나 생성하는 네 가지 방법을 지원합니다.
- 사전 제작된 스튜디오 음성: 다음 표에 나열된 30개의 선별된 음성입니다.
- 확장된 음성 라이브러리:
client.voices.list()(GET /v1beta/voices)를 사용하여 액세스할 수 있는 언어, 억양, 캐릭터 원형에 걸친 수백 개의 추가 음성 - 음성 설계: Google AI Studio에서 자연어 설명으로 또는
POST /v1beta/voices(type="prompted",CreateVoice및GetVoice에서 영구voice_...ID와sample_audioWAV 미리보기를 반환함)를 사용하여 커스텀 음성 페르소나를 생성합니다. - 음성 복제: Google AI Studio에서 또는
POST /v1beta/voices(type="replicated", 기본적으로 영구store=True또는 선택적 스테이트리스(Stateless)store=False)를 사용하여 참조 및 동의 오디오에서 화자의 음성을 복제합니다.
맞춤 음성 한도 및 TTL
| 음성 유형 | 스토리지 모드 | 할당량 / 한도 | 보관 (TTL) |
|---|---|---|---|
스테이트풀(Stateful) 음성(voice_..., 프롬프트 또는 복제) |
store=True |
프로젝트당 음성 200개 (프롬프트 음성과 복제 음성 간에 공유됨) | 마지막 사용 후 1년* |
스테이트리스(Stateless) 음성 키(voicekey_..., 복제됨) |
store=False |
고객 관리 | 7일 |
* TTL 연장: 음성을 적극적으로 사용할 때마다 (음성으로 음성을 합성하거나 리믹스를 위한 기본 음성으로 사용하는 경우) 1년 보관 기간이 재설정됩니다. 1년 동안 활동이 없는 음성은 자동으로 삭제됩니다.
기본 제공 음성
| Zephyr -- Bright | 퍽 - 경쾌함 | 카론 - 유용한 정보 |
| Kore -- Firm | Fenrir - 흥분 | Leda -- Youthful |
| Orus -- 회사 | Aoede -- Breezy | Callirrhoe - 느긋함 |
| Autonoe -- Bright | 엔셀라두스 - 숨소리 | Iapetus - Clear |
| Umbriel -- Easy-going | Algieba -- Smooth | Despina - Smooth |
| Erinome -- Clear | Algenib - 자갈 | Rasalgethi -- 유용한 정보를 전달함 |
| Laomedeia -- Upbeat | Achernar -- Soft | Alnilam -- Firm |
| Schedar -- Even | Gacrux - 성인용 | Pulcherrima - Forward |
| Achird - 친절함 | Zubenelgenubi - 캐주얼 | Vindemiatrix -- Gentle |
| Sadachbia -- Lively | 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_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 |
|---|---|---|
| 아체어 (아랍어 스크립트) | ✔️ | ✔️ |
| 아프리칸스어 | ✔️ | ✔️ |
| 아칸어 | ✔️ | ✔️ |
| 암하라어 | ✔️ | ✔️ |
| 아르메니아어 | ✔️ | ✔️ |
| 아삼어 | ✔️ | ✔️ |
| 아와디어 | ✔️ | ✔️ |
| 발리어 | ✔️ | ✔️ |
| 벵골어 | ✔️ | ✔️ |
| 반자르어 (아랍어 스크립트) | ✔️ | — |
| 반자르어 (라틴 문자) | ✔️ | ✔️ |
| 바시키르어 | ✔️ | — |
| 바스크어 | ✔️ | ✔️ |
| 벨라루스어 | ✔️ | ✔️ |
| 벰바어 | ✔️ | — |
| 보지푸리어 | ✔️ | ✔️ |
| 보스니아어 | ✔️ | ✔️ |
| 부기어 | ✔️ | ✔️ |
| 불가리아어 | ✔️ | ✔️ |
| 버마어 | ✔️ | — |
| 광둥어 | ✔️ | ✔️ |
| 카탈로니아어 | ✔️ | ✔️ |
| 세부아노어 | ✔️ | ✔️ |
| 소라니어 | ✔️ | ✔️ |
| 차티스가르어 | ✔️ | ✔️ |
| 중국어 (한자 스크립트) | ✔️ | ✔️ |
| 중국어 (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로 마이그레이션하는 경우:
- 턴 수준 지시를
speech_metadata로 이동: Gemini 3.8 TTS는 입력 텍스트를 엄격하게 축자 스크립트로 처리합니다. 스크립트 텍스트에 무대 지시를 삽입하는 대신 지속적 전송 안내 (style, 예:"whispering","out of breath","speaking slowly") 및 발화자 라벨 (speaker)을 구조화된speech_metadata주석으로 이동합니다. - 특정 시점의 음성 이벤트에만 꺾쇠괄호 인라인 태그 사용: 꺾쇠괄호 (예:
<laugh>,<sigh>,<cough>,<breath>,<short pause>)를 사용하여 스크립트에서 일시적인 비음성 발성 및 일시중지를 인라인으로 유지합니다. 음향 효과 태그 (예: 박수 또는 쿵 소리)를 피하고 전달 스타일을speech_metadata.style에 넣습니다. - 다중 화자 요청의 모든 턴에
speaker지정: 다중 화자 요청의 모든 턴에는 구성된 화자 중 하나와 일치하는speech_metadata내에speaker가 명시적으로 포함되어야 합니다. - Voice 디자인으로 미리 페르소나 디자인: 여러 단락으로 된
"Audio Profile"또는"Director's Notes"블록을 Voice 디자인에서 만든 맞춤 음성으로 바꾼 다음style문자열이 최소화되거나 비어 있는 TTS 요청을 통해voice_...ID를 전달합니다. - 단항 요청의 기본 WAV(
audio/wav) 출력 고려: 기본적으로 헤더가 없는 원시 PCMaudio/l16을 반환하는gemini-3.1-flash-tts-preview및 이전 TTS 모델과 달리 Gemini 3.8 TTS는 단항 요청에 대해 기본적으로 표준 RIFF 헤더가 있는 WAV 오디오(audio/wav)를 반환합니다.- 이전에 코드가 WAV 헤더에 원시 PCM 바이트를 래핑한 경우 (예: Python의
wave모듈 또는ffmpeg사용) 수동 헤더 래퍼를 삭제하고 반환된 바이트를.wav파일에 직접 작성합니다. - 파이프라인에 헤더 없는 원시 PCM, mu-law 또는 A-law 오디오가 필요한 경우
response_format.mime_type를"audio/l16","audio/mulaw"또는"audio/alaw"로 명시적으로 설정합니다 (예: Interactions API의{"response_format": {"type": "audio", "mime_type": "audio/l16"}}또는generateContent의AUDIO_L16). 오디오 출력 형식을 참조하세요.
- 이전에 코드가 WAV 헤더에 원시 PCM 바이트를 래핑한 경우 (예: Python의
프롬프트 작성 가이드
Gemini 3.8 TTS 모델은 입력 텍스트를 엄격하게 축어 스크립트로 처리합니다.
이전 미리보기 모델에서는 무대 지시가 일반 텍스트에 삽입되었지만 Gemini 3.8 TTS에서는 지속적인 턴 수준 지시 (speech_metadata)가 특정 시점의 인라인 음성 태그와 분리됩니다.
스타일 필드와 인라인 태그
실적 안내를 범위별로 분할합니다.
- 대화 수준 전달 (
speech_metadata.style): 감정, 운율, 전반적인 속도, 전달 스타일 (예:"whispering","out of breath","muttering","sarcastic")과 같은 지속적인 전달 속성을speech_metadata의style필드에 입력합니다. 차례마다 안정적인 캐릭터와 성능을 만들려면 음성 디자인에서 페르소나를 미리 설계하고 선택적인 차례 수준 조정에만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?" - 두 번째 발화 (발화자 B):
"Ready enough |oh really?| The last blocker cleared this morning." - 발화 3 (발화자 A):
"Then let's ship it |absolutely| and watch the dashboards."
- 발화 1 (발화자 A):
- 중복 및 인터리브된 음성: 여러 파이프 세그먼트를 사용하여 두 화자 간의 동시 또는 인터리브된 음성을 시뮬레이션합니다 (
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에 연령, 성별, 이름 또는 영구적인 억양 변화를 넣지 마세요. 대신 확장 음성 라이브러리에서 지역 음성을 선택하거나 음성 디자인으로 음성을 만드세요.
권장 워크플로
- 한 번만 캐릭터 빌드: 음성 디자인에서 캐릭터를 만들거나 확장 음성 라이브러리에서 타겟 언어 및 페르소나와 일치하는 지역 음성을 선택합니다.
- 비유창성을 포함하여 자연스러운 음성 스크립트 작성: 최대한 자연스럽게 표현하려면 자연스러운 대화형 비유창성과 망설임 (예:
"Oh uh yeah I think... hm, so that's interesting")을 포함하여text를 실제 음성 스크립트로 작성합니다. - 먼저 일반 TTS 테스트: 먼저 빈
style필드로 스크립트를 합성합니다. 대부분의 요청에는style명령어가 전혀 필요하지 않습니다. - 조정할 때만 짧은
style프롬프트 추가: 특정 전달 조정이 필요한 차례에만 간결한style문자열(예:"casual, friendly"또는"muttering, then reassuring")을 추가하고 일관된 기준을 원할 때는 차례 전반에서 정확한 짧은 문자열을 재사용합니다.
멀티턴 대화 및 음성 에이전트
실시간 대화형 음성 에이전트 또는 멀티턴 애플리케이션을 빌드할 때:
- LLM 텍스트 청크가 도착하면 차례당 TTS 호출을 한 번 합니다.
- 구성된
voice(사전 빌드, 설계된voice_...또는 복제된voice_.../voicekey_...)가 대화 차례 간에 화자의 ID를 전달하도록 합니다. 각 차례에 긴 문자 페르소나를 다시 전송하지 마세요. - 턴별
style필드를 비워 두거나 전체 대화에 대해 짧은 상수 문자열(예:"casual, friendly")을 하나 보냅니다. - 더 강력한 스타일 프롬프트를 사용하기보다는 긴 에이전트 대답을 짧은 차례로 분할합니다.
제한사항
- TTS 모델은 텍스트 전용 입력을 허용하고 오디오 전용 출력을 생성합니다.
- 단일 요청 다중 화자 생성 (
speech_config.speakers)은 사전 빌드된 음성을 사용하여 최대 2명의 화자를 지원합니다. 여러 캐릭터의 대화에서 커스텀 설계(voice_...) 또는 복제 (voice_.../voicekey_...) 음성을 결합하려면 각 화자의 차례를 개별적으로 합성합니다. 단항 요청은 기본적으로 44바이트 RIFF 헤더와 함께audio/wav를 반환하므로 24kHz PCM 오디오 프레임을 연결하기 전에 원시 PCM ({"type": "audio", "mime_type": "audio/l16"})을 요청하거나 각 턴에서 WAV 헤더를 삭제하세요. - 커스텀 음성 스토리지 한도 및 TTL:
- 상태 저장 음성 (
store=True, 프롬프트 또는 복제): 1년 TTL (수명)이 적용되는 프로젝트당 최대 200개의 음성 - 상태 비저장 음성 키 (
store=False,voicekey_...): 7일 TTL(수명)
- 상태 저장 음성 (
- 언어 범위는 지원되는 언어 섹션을 참조하세요.
다음 단계
- 음성 디자인을 사용하여 자연어에서 맞춤 음성 페르소나를 만드세요.
- 음성 복제에서 기존 화자의 음성을 복제합니다.
- Gemini 3.8 Flash TTS 및 Gemini 3.8 Flash-Lite TTS 모델 페이지에서 모델 사양을 비교하세요.
- Live API를 사용하여 대화형 양방향 오디오를 탐색하세요.