Text-to-Speech w odpowiedziach agenta
API OpenAI TTS, ElevenLabs i Google TTS w potokach agentów.
Text-to-Speech w odpowiedziach agenta to bezpłatna lekcja AI Agents na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Agents, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Agents zawiera 4 lekcji w sumie.
Dlaczego agenci potrzebują TTS
Agent głosowy, który tylko słucha, ale odpowiada tekstem, nie jest prawdziwym agentem głosowym. Synteza mowy (TTS) konwertuje tekstowe odpowiedzi agenta na dźwięk mowy, zamykając pełną pętlę głosową.
Dwa wiodące interfejsy API to: OpenAI TTS (szybkie i przystępne cenowo, 6 głosów) oraz ElevenLabs (niezwykle realistyczne głosy, strumieniowanie i klonowanie głosu).
Podstawy OpenAI TTS
Interfejs API TTS firmy OpenAI konwertuje tekst na mowę w ciągu kilku sekund. Oferuje sześć wbudowanych głosów: alloy, echo, fable, onyx, nova, shimmer. Obsługuje formaty wyjściowe MP3, opus, AAC i 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, clearStrumieniowe TTS z OpenAI
Aby zmniejszyć odczuwalne opóźnienie, należy strumieniować dźwięk w miarę jego generowania, zamiast czekać na utworzenie całego pliku. Rozmówca może rozpocząć odtwarzanie dźwięku, gdy pozostała część jest nadal syntezowana.
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)ElevenLabs SDK: wysokiej jakości TTS
ElevenLabs tworzy jedne z najbardziej realistycznych dostępnych głosów. Obsługuje klonowanie głosu, sterowanie tonem emocjonalnym i strumieniowanie.
Instalacja: 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_pathStrumieniowe TTS z ElevenLabs
ElevenLabs obsługuje strumieniowanie — fragmenty dźwięku są odbierane, zanim zostanie zsyntezowany cały tekst. Ma to kluczowe znaczenie w przypadku agentów głosowych, dla których opóźnienie jest istotne.
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}')Odtwarzanie audio za pomocą sounddevice
Po wygenerowaniu dźwięku TTS należy odtworzyć go na urządzeniu lokalnym. Połączenie sounddevice z soundfile to najprostsza wieloplatformowa opcja dla agenta działającego na komputerze lokalnym.
Instalacja: 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?')Odtwarzanie audio za pomocą pygame
pygame zapewnia większą kontrolę: można sprawdzać, czy dźwięk jest nadal odtwarzany, zatrzymać go wcześniej i odtwarzać wiele dźwięków. Jest to przydatne do obsługi przerwań w agentach głosowych.
Instalacja: 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)')Buforowanie odpowiedzi TTS
Typowe frazy, takie jak powitania, komunikaty o błędach i monity menu, są syntezowane wielokrotnie. Należy buforować ich pliki audio, aby za syntezę płacić tylko raz dla każdej frazy.
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 zdanie po zdaniu na potrzeby strumieniowania
W przypadku długich odpowiedzi LLM należy podzielić tekst na zdania, a następnie syntezować je i odtwarzać jedno po drugim. Użytkownik usłyszy pierwsze zdanie w ciągu około 500 ms, podczas gdy reszta będzie nadal generowana.
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)Wybór głosu i modelu
Wybór głosu należy dopasować do osobowości agenta. Głębsze głosy (onyx, echo) sprawdzą się w przypadku agentów formalnych i profesjonalnych, a cieplejsze głosy (nova, shimmer) w przypadku przyjaznych asystentów.
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')Dostosowywanie tempa i wysokości głosu
Różne konteksty wymagają różnych właściwości mowy. Powiadomienia powinny być nieco szybsze, a opowiadanie historii — wolniejsze i bardziej ekspresyjne. Dźwięk TTS można przetworzyć po syntezie, aby dostosować szybkość bez zmiany wysokości głosu.
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 alertsSprawdzenie wiedzy
Jaka jest najważniejsza korzyść z używania syntezy TTS zdanie po zdaniu w agencie głosowym?
Podsumowanie: synteza mowy w odpowiedziach agenta
OpenAI TTS (tts-1, tts-1-hd) oferuje 6 głosów, szybką syntezę i obsługę strumieniowania — doskonale nadaje się do większości agentów głosowych. ElevenLabs zapewnia realistyczne głosy wyższej jakości dzięki eleven_turbo_v2, który umożliwia strumieniowanie z małym opóźnieniem.
Dźwięk można odtwarzać za pomocą sounddevice (proste rozwiązanie) lub pygame (obsługa przerywania). Typowe frazy należy buforować, aby wyeliminować powtarzające się koszty wywołań API. W przypadku długich odpowiedzi należy używać syntezy zdanie po zdaniu, aby zminimalizować odczuwalne opóźnienie. Buforowanie TTS z użyciem skrótów MD5 gwarantuje, że identyczny tekst zawsze zostanie pobrany z bufora.
Często zadawane pytania
Czy lekcja „Text-to-Speech w odpowiedziach agenta” jest bezpłatna?
Tak — pełny tekst „Text-to-Speech w odpowiedziach agenta” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Agents, przejdź na CoddyKit PRO. Kurs AI Agents zawiera 4 lekcji w sumie.
Co nauczysz się w „Text-to-Speech w odpowiedziach agenta”?
API OpenAI TTS, ElevenLabs i Google TTS w potokach agentów. Ćwiczysz AI Agents z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć AI Agents?
Nie wymagamy żadnego doświadczenia. AI Agents w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Text-to-Speech w odpowiedziach agenta”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji AI Agents?
Tak. Każda lekcja AI Agents zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Speech-to-Text z Whisper i Deepgram
- Text-to-Speech w odpowiedziach agenta
- Tworzenie pętli konwersacji głosowej
- Optymalizacja opóźnień agentów głosowych