Conversão de texto em fala nas respostas de agentes
APIs de TTS da OpenAI, ElevenLabs e Google em pipelines de agentes.
Conversão de texto em fala nas respostas de agentes é uma aula grátis de AI Agents no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de AI Agents, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de AI Agents inclui 4 aulas no total.
Por que os agentes precisam de TTS
Um agente de voz que apenas escuta, mas responde em texto, não é um verdadeiro agente de voz. A conversão de texto em fala (TTS) converte as respostas textuais do agente em áudio falado, completando todo o ciclo de voz.
Duas APIs principais: OpenAI TTS (rápida, acessível, com 6 vozes) e ElevenLabs (vozes ultrarrealistas, transmissão em fluxo e clonagem de voz).
Fundamentos do OpenAI TTS
A API TTS da OpenAI converte texto em fala em segundos. Seis vozes integradas: alloy, echo, fable, onyx, nova, shimmer. Oferece suporte aos formatos de saída MP3, opus, AAC e FLAC.
import openai
import os
client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
def text_to_speech(text, voice='alloy', output_path='response.mp3'):
response = client.audio.speech.create(
model='tts-1', # tts-1 (fast) or tts-1-hd (higher quality)
voice=voice, # alloy, echo, fable, onyx, nova, shimmer
input=text,
response_format='mp3' # mp3, opus, aac, flac
)
with open(output_path, 'wb') as f:
f.write(response.content)
print(f'Audio saved to: {output_path}')
return output_path
# Available voices:
# alloy - neutral, balanced
# echo - warm, conversational
# fable - expressive
# onyx - deep, authoritative
# nova - friendly, upbeat
# shimmer - soft, clearTTS em fluxo com OpenAI
Para reduzir a latência percebida, transmita o áudio conforme ele é gerado, em vez de esperar pelo arquivo completo. A pessoa que está ligando pode começar a reproduzir o áudio enquanto o restante ainda está sendo sintetizado.
import openai
import os
client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
def stream_tts_to_file(text, output_path, voice='nova'):
with client.audio.speech.with_streaming_response.create(
model='tts-1',
voice=voice,
input=text
) as response:
response.stream_to_file(output_path)
return output_path
def stream_tts_to_bytes(text, voice='nova'):
audio_chunks = []
with client.audio.speech.with_streaming_response.create(
model='tts-1',
voice=voice,
input=text
) as response:
for chunk in response.iter_bytes(chunk_size=4096):
audio_chunks.append(chunk)
return b''.join(audio_chunks)SDK ElevenLabs: TTS de alta qualidade
ElevenLabs produz algumas das vozes mais realistas disponíveis. Oferece clonagem de voz, controle do tom emocional e transmissão em fluxo.
Instale com pip install elevenlabs.
from elevenlabs import ElevenLabs, VoiceSettings
import os
client = ElevenLabs(api_key=os.getenv('ELEVENLABS_API_KEY'))
def elevenlabs_tts(text, voice_id='pNInz6obpgDQGcFmaJgB', output_path='response.mp3'):
# Common voice IDs:
# Rachel: 21m00Tcm4TlvDq8ikWAM
# Adam: pNInz6obpgDQGcFmaJgB
# Bella: EXAVITQu4vr4xnSDxMaL
audio = client.generate(
text=text,
voice=voice_id,
model='eleven_multilingual_v2', # supports 29 languages
voice_settings=VoiceSettings(
stability=0.5, # 0.0-1.0: lower = more expressive
similarity_boost=0.8, # 0.0-1.0: higher = closer to original voice
style=0.3 # 0.0-1.0: style exaggeration
)
)
with open(output_path, 'wb') as f:
for chunk in audio:
f.write(chunk)
return output_pathTTS em fluxo com ElevenLabs
ElevenLabs oferece transmissão em fluxo: receba trechos de áudio antes que o texto completo seja sintetizado. Isso é fundamental para agentes de voz em que a latência é importante.
from elevenlabs import ElevenLabs
import os
client = ElevenLabs(api_key=os.getenv('ELEVENLABS_API_KEY'))
def streaming_tts(text, voice_id='pNInz6obpgDQGcFmaJgB'):
audio_stream = client.generate(
text=text,
voice=voice_id,
model='eleven_turbo_v2', # fastest model, optimized for streaming
stream=True
)
return audio_stream # yields audio chunks as they are generated
def stream_to_file(text, output_path, voice_id='pNInz6obpgDQGcFmaJgB'):
stream = streaming_tts(text, voice_id)
with open(output_path, 'wb') as f:
for chunk in stream:
if chunk:
f.write(chunk)
print(f'Streaming TTS complete: {output_path}')Reprodução de áudio com sounddevice
Depois de gerar o áudio TTS, reproduza-o no dispositivo local. sounddevice com soundfile é a opção multiplataforma mais simples para um agente executado em uma máquina local.
Instale com pip install sounddevice soundfile.
import sounddevice as sd
import soundfile as sf
import numpy as np
import tempfile
import os
def play_audio_file(audio_path):
data, sample_rate = sf.read(audio_path)
sd.play(data, sample_rate)
sd.wait() # block until playback finishes
def play_mp3_bytes(audio_bytes):
# Write to temp file then play (soundfile needs a file)
with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as f:
f.write(audio_bytes)
tmp_path = f.name
try:
play_audio_file(tmp_path)
finally:
os.unlink(tmp_path)
def say(text, voice='nova'):
audio_bytes = stream_tts_to_bytes(text, voice=voice)
play_mp3_bytes(audio_bytes)
# Usage
say('Hello! How can I help you today?')Reprodução de áudio com pygame
pygame oferece mais controle: é possível verificar se o áudio ainda está sendo reproduzido, interrompê-lo antes do fim e reproduzir vários sons. Isso é útil para lidar com interrupções em agentes de voz.
Instale com pip install pygame.
import pygame
import io
import tempfile
import os
pygame.mixer.init(frequency=44100, size=-16, channels=1, buffer=512)
def play_audio_pygame(audio_bytes):
with tempfile.NamedTemporaryFile(suffix='.mp3', delete=False) as f:
f.write(audio_bytes)
tmp_path = f.name
try:
pygame.mixer.music.load(tmp_path)
pygame.mixer.music.play()
while pygame.mixer.music.get_busy():
pygame.time.wait(50) # check every 50ms
finally:
pygame.mixer.music.stop()
os.unlink(tmp_path)
def stop_audio():
if pygame.mixer.music.get_busy():
pygame.mixer.music.stop()
print('Audio stopped (interrupt)')Armazenamento em cache de respostas TTS
Frases comuns, como saudações, mensagens de erro e instruções de menu, são sintetizadas repetidamente. Armazene os arquivos de áudio dessas frases em cache para pagar pela síntese apenas uma vez por frase.
import hashlib
import os
TTS_CACHE_DIR = '/tmp/tts_cache'
os.makedirs(TTS_CACHE_DIR, exist_ok=True)
def cached_tts(text, voice='nova'):
cache_key = hashlib.md5(f'{voice}:{text}'.encode()).hexdigest()
cache_path = os.path.join(TTS_CACHE_DIR, f'{cache_key}.mp3')
if os.path.exists(cache_path):
print('TTS cache hit')
return cache_path
# Generate and save
audio_bytes = stream_tts_to_bytes(text, voice=voice)
with open(cache_path, 'wb') as f:
f.write(audio_bytes)
print(f'TTS cached: {cache_path}')
return cache_path
# Pre-warm cache for common phrases on startup
COMMON_PHRASES = [
'Hello! How can I help you today?',
'I did not catch that. Could you repeat?',
'Let me look that up for you.',
'Thank you, goodbye!'
]
def prewarm_tts_cache():
for phrase in COMMON_PHRASES:
cached_tts(phrase)
print(f'Pre-warmed {len(COMMON_PHRASES)} phrases')TTS frase por frase para transmissão em fluxo
Para respostas longas do LLM, divida o texto em frases e sintetize e reproduza cada uma individualmente. O usuário ouve a primeira frase em cerca de 500 ms, enquanto o restante ainda está sendo gerado.
import re
def split_into_sentences(text):
sentences = re.split(r'(?<=[.!?])\s+', text.strip())
return [s.strip() for s in sentences if s.strip()]
def stream_response_as_voice(llm_response_text, voice='nova'):
sentences = split_into_sentences(llm_response_text)
print(f'Speaking {len(sentences)} sentences')
for i, sentence in enumerate(sentences):
if not sentence:
continue
print(f'Speaking ({i+1}/{len(sentences)}): {sentence[:60]}')
cache_path = cached_tts(sentence, voice=voice)
play_audio_file(cache_path)
# Example
response = 'The weather today is sunny and 22 degrees. Perfect for outdoor activities. Bring sunscreen if you plan to be outside for more than an hour.'
stream_response_as_voice(response)Escolhendo a voz e o modelo
Combine a escolha da voz com a personalidade do agente. Utilize vozes mais graves (onyx, echo) para agentes formais ou profissionais; e vozes mais acolhedoras (nova, shimmer) para assistentes amigáveis.
VOICE_PROFILES = {
'assistant': {'service': 'openai', 'voice': 'nova', 'model': 'tts-1'},
'professional': {'service': 'openai', 'voice': 'onyx', 'model': 'tts-1-hd'},
'narrator': {'service': 'openai', 'voice': 'fable', 'model': 'tts-1-hd'},
'premium': {'service': 'elevenlabs', 'voice_id': '21m00Tcm4TlvDq8ikWAM', 'model': 'eleven_multilingual_v2'}
}
def speak(text, persona='assistant'):
profile = VOICE_PROFILES.get(persona, VOICE_PROFILES['assistant'])
if profile['service'] == 'openai':
audio_bytes = stream_tts_to_bytes(text, voice=profile['voice'])
play_mp3_bytes(audio_bytes)
elif profile['service'] == 'elevenlabs':
output_path = elevenlabs_tts(text, voice_id=profile['voice_id'])
play_audio_file(output_path)
speak('Your meeting has been rescheduled.', persona='professional')Ajustando a velocidade e a altura da fala
Diferentes contextos exigem características de fala diferentes. Alertas de notificação devem ser um pouco mais rápidos; narrações, mais lentas e expressivas. Faça um pós-processamento do áudio TTS para ajustar a velocidade sem alterar a altura da voz.
from pydub import AudioSegment
from pydub.effects import speedup
import os
def adjust_speech_speed(audio_path, speed_factor=1.0, output_path=None):
if speed_factor == 1.0:
return audio_path
audio = AudioSegment.from_file(audio_path)
if speed_factor > 1.0:
# Speed up without changing pitch
audio = speedup(audio, playback_speed=speed_factor)
else:
# Slow down: overlay with silence (simple method)
# For production: use ffmpeg with atempo filter
slow_factor = 1.0 / speed_factor
audio = audio._spawn(
audio.raw_data,
overrides={'frame_rate': int(audio.frame_rate / slow_factor)}
).set_frame_rate(audio.frame_rate)
if output_path is None:
base = os.path.splitext(audio_path)[0]
output_path = f'{base}_speed{speed_factor}.mp3'
audio.export(output_path, format='mp3')
return output_path
# Usage
path = text_to_speech('Your meeting starts in 5 minutes.')
fast_path = adjust_speech_speed(path, speed_factor=1.2) # 20% faster for alertsVerificação de conhecimento
Qual é o principal benefício de utilizar a síntese TTS frase por frase em um agente de voz?
Recapitulação: conversão de texto em fala nas respostas do agente
OpenAI TTS (tts-1, tts-1-hd) oferece 6 vozes, síntese rápida e suporte à transmissão em fluxo, sendo ideal para a maioria dos agentes de voz. ElevenLabs oferece vozes realistas de maior qualidade com eleven_turbo_v2 para transmissão em fluxo com baixa latência.
Reproduza o áudio com sounddevice (simples) ou pygame (que permite interrupções). Armazene frases comuns em cache para eliminar custos repetidos de API. Utilize a síntese frase por frase em respostas longas para minimizar a latência percebida. O armazenamento de TTS em cache com hashes MD5 garante que textos idênticos sejam sempre servidos a partir do cache.
Perguntas Frequentes
A aula “Conversão de texto em fala nas respostas de agentes” é grátis?
Sim — o texto completo de “Conversão de texto em fala nas respostas de agentes” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de AI Agents, atualize para CoddyKit PRO. O curso de AI Agents inclui 4 aulas no total.
O que vou aprender em “Conversão de texto em fala nas respostas de agentes”?
APIs de TTS da OpenAI, ElevenLabs e Google em pipelines de agentes. Você pratica AI Agents com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar AI Agents?
Nenhuma experiência prévia é necessária. AI Agents no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Conversão de texto em fala nas respostas de agentes”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de AI Agents?
Sim. Cada aula de AI Agents inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Conversão de fala em texto com Whisper e Deepgram
- Conversão de texto em fala nas respostas de agentes
- Criando um ciclo de conversação por voz
- Otimização da latência para agentes de voz