droath / edenai
Modern, type-safe PHP SDK for the EdenAI API with PSR compliance and immutable DTOs
Fund package maintenance!
Droath
Installs: 5
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/droath/edenai
Requires
- php: ^8.3
- php-http/discovery: ^1.20
- psr/http-client: ^1.0
- psr/http-factory: ^1.1
- psr/http-message: ^2.0
Requires (Dev)
- guzzlehttp/guzzle: ^7.10
- laravel/pint: ^1.14
- mockery/mockery: ^1.6
- nyholm/psr7: ^1.8
- pestphp/pest: ^3.0|^4.0
- pestphp/pest-plugin-arch: ^3.0|^4.0
- php-http/mock-client: ^1.6
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- vlucas/phpdotenv: ^5.6
Suggests
- guzzlehttp/guzzle: Required for making HTTP requests if no other PSR-18 client is provided
README
A modern, type-safe PHP SDK for the EdenAI API. Built with strict type safety, immutability, and PSR standards compliance, this SDK provides a robust foundation for integrating AI capabilities into your PHP applications.
Features:
- Fully typed with PHP 8.3+ features (readonly properties, enums, strict types)
- PSR-compliant (PSR-7, PSR-17, PSR-18)
- Extensible middleware pipeline architecture
- Automatic retry logic with exponential backoff
- Comprehensive exception handling
- Immutable DTOs for type-safe request/response handling
Requirements
- PHP 8.3 or higher
- A PSR-18 HTTP client (e.g., Guzzle)
- PSR-17 HTTP factories
Installation
Install the package via Composer:
composer require droath/edenai
You'll also need a PSR-18 HTTP client. We recommend Guzzle:
composer require guzzlehttp/guzzle
Configuration
Set your EdenAI API credentials as environment variables:
# .env file
EDENAI_BASE_URL=https://api.edenai.run
EDENAI_API_KEY=your-api-key-here
Or configure them directly when instantiating the client (see Basic Usage below).
Basic Usage
Quick Start
The simplest way to get started is to use environment variables:
<?php declare(strict_types=1); use Droath\Edenai\Http\ApiClient; use Droath\Edenai\Resources\AudioResource; // Client auto-discovers HTTP client and loads config from environment $client = new ApiClient(); // Use a resource to make API calls $audioResource = new AudioResource($client);
Explicit Configuration
You can also configure the client explicitly:
<?php declare(strict_types=1); use GuzzleHttp\Client as GuzzleClient; use Droath\Edenai\Http\ApiClient; $httpClient = new GuzzleClient(); $client = new ApiClient( httpClient: $httpClient, baseUrl: 'https://api.edenai.run', apiKey: 'your-api-key-here', );
Audio Resources
The SDK provides comprehensive support for Eden AI's audio processing endpoints:
Speech-to-Text (Async)
Upload audio files for asynchronous transcription:
<?php declare(strict_types=1); use Droath\Edenai\Http\ApiClient; use Droath\Edenai\Resources\AudioResource; use Droath\Edenai\DTOs\Audio\SpeechToTextAsyncRequest; use Droath\Edenai\Enums\ServiceProviderEnum; $client = new ApiClient(); $audioResource = new AudioResource($client); // Create request with file upload $request = new SpeechToTextAsyncRequest( file: '/path/to/audio.mp3', providers: [ServiceProviderEnum::GOOGLE, ServiceProviderEnum::DEEPGRAM], language: 'en', ); // Upload file and get job ID for tracking $response = $audioResource->speechToTextAsync($request); echo "Job ID: {$response->jobId}"; echo "Providers: " . implode(', ', $response->providers); echo "Created: {$response->submittedAt->format('Y-m-d H:i:s')}";
Supported Audio Formats: mp3, wav, flac, ogg
Text-to-Speech (Sync)
Generate audio from text synchronously:
<?php declare(strict_types=1); use Droath\Edenai\Http\ApiClient; use Droath\Edenai\Resources\AudioResource; use Droath\Edenai\DTOs\Audio\TextToSpeechRequest; use Droath\Edenai\Enums\ServiceProviderEnum; $client = new ApiClient(); $audioResource = new AudioResource($client); // Create request with optional parameters $request = new TextToSpeechRequest( text: 'Hello world', providers: [ServiceProviderEnum::AMAZON], language: 'en', option: 'FEMALE', audioFormat: 'mp3', rate: 1, pitch: 0, volume: 1, ); // Get generated audio immediately $response = $audioResource->textToSpeech($request); // Save audio to file (already decoded from Base64) // Response contains results from all providers foreach ($response->results as $result) { file_put_contents("output_{$result->provider}.mp3", $result->audioData); echo "Provider: {$result->provider}, Voice type: {$result->voiceType}\n"; }
Text-to-Speech (Async)
Generate audio from text asynchronously:
<?php declare(strict_types=1); use Droath\Edenai\Http\ApiClient; use Droath\Edenai\Resources\AudioResource; use Droath\Edenai\DTOs\Audio\TextToSpeechAsyncRequest; use Droath\Edenai\Enums\ServiceProviderEnum; $client = new ApiClient(); $audioResource = new AudioResource($client); // Create async request $request = new TextToSpeechAsyncRequest( text: 'This is a longer text that will be processed asynchronously', providers: [ServiceProviderEnum::MICROSOFT, ServiceProviderEnum::AZURE], language: 'en-US', option: 'MALE', audioFormat: 'wav', ); // Get job ID for polling $response = $audioResource->textToSpeechAsync($request); echo "Job ID: {$response->jobId}"; echo "Created: {$response->submittedAt->format('Y-m-d H:i:s')}";
AI Service Providers
The ServiceProviderEnum provides type-safe provider selection:
<?php declare(strict_types=1); use Droath\Edenai\Enums\ServiceProviderEnum; // Available providers: ServiceProviderEnum::GOOGLE // Google Cloud ServiceProviderEnum::AMAZON // Amazon AWS ServiceProviderEnum::MICROSOFT // Microsoft Azure ServiceProviderEnum::OPENAI // OpenAI ServiceProviderEnum::DEEPGRAM // Deepgram ServiceProviderEnum::ASSEMBLY_AI // AssemblyAI ServiceProviderEnum::REV_AI // Rev.ai ServiceProviderEnum::SPEECHMATICS // Speechmatics ServiceProviderEnum::IBMWATSON // IBM Watson ServiceProviderEnum::AZURE // Azure Cognitive Services
Error Handling for Audio Endpoints
Audio operations include specific exceptions:
<?php declare(strict_types=1); use Droath\Edenai\Http\ApiClient; use Droath\Edenai\Resources\AudioResource; use Droath\Edenai\DTOs\Audio\SpeechToTextAsyncRequest; use Droath\Edenai\Enums\ServiceProviderEnum; use Droath\Edenai\Exceptions\FileUploadException; use Droath\Edenai\Exceptions\ValidationException; use InvalidArgumentException; $client = new ApiClient(); $audioResource = new AudioResource($client); try { $request = new SpeechToTextAsyncRequest( file: '/path/to/audio.mp3', providers: [ServiceProviderEnum::GOOGLE], language: 'en', ); $response = $audioResource->speechToTextAsync($request); } catch (InvalidArgumentException $e) { // Request DTO validation failed (e.g., empty text) echo 'Invalid request: ' . $e->getMessage(); } catch (FileUploadException $e) { // File not found or not readable echo 'File upload error: ' . $e->getMessage(); } catch (ValidationException $e) { // Unsupported audio format or API validation error echo 'Validation error: ' . $e->getMessage(); print_r($e->getErrors()); }
Advanced Usage
Custom Middleware
Extend the middleware pipeline with custom middleware:
<?php declare(strict_types=1); use Droath\Edenai\Http\ApiClient; use Droath\Edenai\Middleware\MiddlewareInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; final class LoggingMiddleware implements MiddlewareInterface { public function handle(RequestInterface $request, callable $next): ResponseInterface { // Log before request error_log('Request: ' . $request->getMethod() . ' ' . $request->getUri()); // Execute next middleware $response = $next($request); // Log after response error_log('Response: ' . $response->getStatusCode()); return $response; } } // Custom middleware is prepended before default middleware $client = new ApiClient( middleware: [new LoggingMiddleware()], );
The middleware pipeline executes in this order:
- Custom middleware (if provided)
- AuthenticationMiddleware (injects API key)
- ErrorHandlingMiddleware (maps HTTP errors to exceptions)
- RetryMiddleware (retries transient failures)
- HTTP client (sends the request)
Exception Handling
The SDK provides typed exceptions for different error scenarios:
<?php declare(strict_types=1); use Droath\Edenai\Http\ApiClient; use Droath\Edenai\Resources\AudioResource; use Droath\Edenai\DTOs\Audio\TextToSpeechRequest; use Droath\Edenai\Enums\ServiceProviderEnum; use Droath\Edenai\Exceptions\AuthenticationException; use Droath\Edenai\Exceptions\ValidationException; use Droath\Edenai\Exceptions\RateLimitException; use Droath\Edenai\Exceptions\ServerException; use Droath\Edenai\Exceptions\NetworkException; $client = new ApiClient(); $audioResource = new AudioResource($client); try { $request = new TextToSpeechRequest( text: 'Hello world', providers: [ServiceProviderEnum::GOOGLE], ); $response = $audioResource->textToSpeech($request); } catch (AuthenticationException $e) { // 401 - Invalid or missing API credentials echo 'Authentication failed: ' . $e->getMessage(); echo 'Status: ' . $e->getStatusCode(); } catch (ValidationException $e) { // 422 - Request validation failed echo 'Validation errors: '; print_r($e->getErrors()); } catch (RateLimitException $e) { // 429 - Rate limit exceeded echo 'Rate limited. Retry after: ' . $e->getRetryAfter(); } catch (ServerException $e) { // 500+ - Server error echo 'Server error: ' . $e->getMessage(); } catch (NetworkException $e) { // Network/connection error echo 'Network error: ' . $e->getMessage(); }
Request DTOs
Request DTOs provide validation and type safety for API requests. All audio request DTOs validate their inputs at construction time:
<?php declare(strict_types=1); use Droath\Edenai\DTOs\Audio\TextToSpeechRequest; use Droath\Edenai\Enums\ServiceProviderEnum; use InvalidArgumentException; // Valid request $request = new TextToSpeechRequest( text: 'Hello world', providers: [ServiceProviderEnum::GOOGLE, ServiceProviderEnum::AMAZON], language: 'en', ); // Serialize to array for HTTP request $payload = $request->toArray(); // Invalid requests throw exceptions at construction time try { $invalid = new TextToSpeechRequest( text: '', // Empty text providers: [ServiceProviderEnum::GOOGLE], ); } catch (InvalidArgumentException $e) { echo 'Validation error: ' . $e->getMessage(); // Output: "Text cannot be empty" }
Response DTOs
Response DTOs parse API responses with type transformations:
<?php declare(strict_types=1); use Droath\Edenai\DTOs\Audio\SpeechToTextAsyncResponse; // Parse API response $data = [ 'job_id' => 'job-abc123', 'providers' => ['google', 'deepgram'], 'submitted_at' => '2024-11-09 15:30:00', 'unknown_field' => 'ignored', // Unknown fields are ignored ]; $response = SpeechToTextAsyncResponse::fromResponse($data); // Access typed properties echo $response->jobId; // string: "job-abc123" print_r($response->providers); // array: ['google', 'deepgram'] echo $response->submittedAt->format('Y-m-d'); // DateTimeImmutable: "2024-11-09" // Properties are readonly and immutable $response->jobId = 'xyz'; // Error: Cannot modify readonly property
Response Metadata
Access HTTP metadata separately from business data:
<?php declare(strict_types=1); use Droath\Edenai\DTOs\ResponseMetadata; use Psr\Http\Message\ResponseInterface; /** @var ResponseInterface $psrResponse */ $metadata = ResponseMetadata::fromResponse($psrResponse); // Access rate limit information echo 'Requests remaining: ' . $metadata->getRateLimitRemaining(); echo 'Rate limit resets at: ' . date('Y-m-d H:i:s', $metadata->getRateLimitReset()); // Access request ID for debugging echo 'Request ID: ' . $metadata->getRequestId(); // Access all headers $headers = $metadata->getHeaders();
Testing
Running the Test Suite
Run all tests (excluding sandbox tests):
composer test
This runs the complete test suite including unit tests, feature tests, integration tests, and architecture tests. Sandbox tests requiring real API credentials are excluded by default.
Running Sandbox Tests
Sandbox tests make real API calls to EdenAI and require valid API credentials. These tests are excluded from CI/CD to control API costs and rate limits.
To run sandbox tests locally:
- Create a
.env.testingfile in the project root:
cp .env.testing.example .env.testing
- Add your EdenAI API key to
.env.testing:
EDENAI_API_KEY=your-real-api-key-here
- Run sandbox tests:
vendor/bin/pest --group=sandbox-test
Important: Sandbox tests are excluded from automated CI/CD pipelines and must be run manually with your own API credentials. Never commit your .env.testing file to version control.
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.