symfony/ai-eleven-labs-platform
Symfony AI bridge for the ElevenLabs Platform API. Provides integration for ElevenLabs authentication plus text-to-speech (convert/stream) and speech-to-text endpoints, enabling voice generation and transcription in Symfony applications.
Install the Package
composer require symfony/ai-eleven-labs-platform
Configure API Key
Add your ElevenLabs API key to your Symfony .env:
ELEVENLABS_API_KEY=your_api_key_here
Basic TTS Usage
use Symfony\AI\ElevenLabs\ElevenLabsClient;
use Symfony\AI\ElevenLabs\Voice;
$client = new ElevenLabsClient($_ENV['ELEVENLABS_API_KEY']);
$voice = new Voice('Rachel'); // ElevenLabs voice ID
$audio = $client->convert('Hello, world!', $voice);
file_put_contents('output.mp3', $audio->getContent());
First Use Case: Dynamic Audio Generation
Use the convert() method to generate audio on-demand (e.g., for notifications or IVR systems). Example:
$client = new ElevenLabsClient($_ENV['ELEVENLABS_API_KEY']);
$voices = $client->getModelCatalog()->getVoices();
$selectedVoice = $voices->first(); // Pick a voice dynamically
$audio = $client->convert("Your order #12345 is confirmed.", $selectedVoice);
// Send $audio to user via email/SMS
$client = new ElevenLabsClient($_ENV['ELEVENLABS_API_KEY']);
$audio = $client->convert("Hello, user!", new Voice('Antoni'));
file_put_contents('greeting.mp3', $audio->getContent());
$stream = $client->stream("Hello, user!", new Voice('Antoni'));
while ($chunk = $stream->getChunk()) {
// Send chunk to browser via SSE or WebSocket
echo $chunk;
}
$messages = ["Order confirmed", "Thank you for your purchase"];
foreach ($messages as $message) {
$audio = $client->convert($message, new Voice('Bella'));
// Store in database or queue for delivery
}
$transcription = $client->transcribe('audio.mp3');
echo $transcription->getText(); // "Hello, world!"
use Symfony\Component\Messenger\MessageBusInterface;
$bus->dispatch(new TranscribeMessage('long_audio.mp3'));
Define a handler:
class TranscribeHandler
{
public function __invoke(TranscribeMessage $message, ElevenLabsClient $client)
{
$transcription = $client->transcribe($message->getFilePath());
// Save result or trigger follow-up actions
}
}
Fetch available voices and filter by criteria (e.g., language, similarity):
$voices = $client->getModelCatalog()->getVoices();
$englishVoices = $voices->filter(fn($voice) => $voice->getLabels()['language'] === 'en');
Wrap API calls in a retry mechanism:
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
try {
$audio = $client->convert("Hello", new Voice('Rachel'));
} catch (ClientExceptionInterface | ServerExceptionInterface $e) {
// Implement retry logic (e.g., exponential backoff)
$this->retryWithBackoff(fn() => $client->convert("Hello", new Voice('Rachel')));
}
Dependency Injection
Register the client as a service in services.yaml:
services:
Symfony\AI\ElevenLabs\ElevenLabsClient:
arguments:
$apiKey: '%env(ELEVENLABS_API_KEY)%'
Inject it into controllers/services:
public function __construct(private ElevenLabsClient $elevenLabs) {}
Messenger for Async STT Create a message and handler for background transcription:
// src/Message/TranscribeMessage.php
class TranscribeMessage
{
public function __construct(private string $filePath) {}
public function getFilePath(): string { return $this->filePath; }
}
// src/MessageHandler/TranscribeHandler.php
class TranscribeHandler
{
public function __invoke(TranscribeMessage $message, ElevenLabsClient $client)
{
$transcription = $client->transcribe($message->getFilePath());
// Save to database or notify user
}
}
Event Listeners for Post-Processing Trigger actions after transcription (e.g., update CRM):
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: 'elevenlabs.transcription.completed', method: 'onTranscriptionCompleted')]
public function onTranscriptionCompleted(TranscriptionEvent $event)
{
$this->crmService->updateNote($event->getTranscription()->getText());
}
If using Laravel, leverage the package’s standalone HTTP client usage:
use Symfony\AI\ElevenLabs\ElevenLabsClient;
use Symfony\Contracts\HttpClient\HttpClientInterface;
// Laravel's HTTP client implements HttpClientInterface
$client = new ElevenLabsClient($_ENV['ELEVENLABS_API_KEY'], app(HttpClientInterface::class));
Use provided test fixtures (Tests/Fixtures/audio.mp3) for local testing:
public function testTranscription()
{
$client = new ElevenLabsClient($_ENV['ELEVENLABS_API_KEY']);
$transcription = $client->transcribe(__DIR__.'/../../Tests/Fixtures/audio.mp3');
$this->assertStringContainsString('test', $transcription->getText());
}
API Key Management
ParameterBag or Laravel’s .env).Rate Limiting
429 Too Many Requests errors.use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
try {
$audio = $client->convert("Hello", new Voice('Rachel'));
} catch (TransportExceptionInterface $e) {
if ($e->getCode() === 429) {
sleep(2); // Wait before retry
$audio = $client->convert("Hello", new Voice('Rachel'));
}
}
Streaming Quirks
HttpClient defaults to a 30-second timeout.$client = new ElevenLabsClient(
$_ENV['ELEVENLABS_API_KEY'],
HttpClient::create(['timeout' => 300]) // 5-minute timeout
);
Voice Selection
$voice = new Voice('Rachel');
if (!$voice->supportsStreaming()) {
throw new \RuntimeException("Voice does not support streaming.");
}
Error Handling
ElevenLabsApiException, but some edge cases may slip through.$client->getHttpClient()->on(
['error' => function (ResponseInterface $response, Throwable $exception) {
if ($response->getStatusCode() === 401) {
throw new \RuntimeException("Invalid API key.");
}
}]
);
How can I help you explore Laravel packages today?