symfony/ai-amazee-ai-platform
Symfony AI bridge for the amazee.ai Platform. Connect Symfony AI to LiteLLM proxy endpoints and OpenAI-compatible providers through amazee.ai, enabling centralized AI access and management. Links to docs, issues, and contributions in the main Symfony AI repo.
Install Dependencies:
composer require symfony/ai-amazeeai-platform
Ensure symfony/ai is also installed (required).
Configure Provider:
Add amazee.ai/LiteLLM API key to your Symfony config (e.g., .env):
AI_AMAZEEAI_API_KEY=your_amazee_ai_key
AI_AMAZEEAI_PROXY_URL=https://proxy.amazee.ai/v1
Basic Usage: Inject the client into a service and make a completion request:
use Symfony\AI\Client\ClientInterface;
use Symfony\AI\Client\OpenAI\ChatCompletion;
public function __construct(private ClientInterface $aiClient) {}
public function generateResponse(): string {
$chat = new ChatCompletion('gpt-3.5-turbo', [
new ChatMessage('user', 'Hello!'),
]);
return $this->aiClient->complete($chat)->getContent();
}
Verify Integration:
"Tell me a joke").Replace a direct OpenAI call in a chatbot service:
// Before (direct OpenAI)
$response = Http::withHeaders(['Authorization' => 'Bearer '.$apiKey])
->post('https://api.openai.com/v1/chat/completions', [...]);
// After (amazee.ai bridge)
$chat = new ChatCompletion('gpt-3.5-turbo', [new ChatMessage('user', $input)]);
$response = $this->aiClient->complete($chat)->getContent();
Define supported models in a Provider class (extend Symfony\AI\Client\ProviderInterface):
use Symfony\AI\Client\ProviderInterface;
use Symfony\AI\Client\OpenAI\ChatCompletion;
class AmazeeAIProvider implements ProviderInterface {
public function complete(ChatCompletion $completion): ChatCompletion {
$response = Http::post($this->proxyUrl, [
'body' => $completion->toArray(),
'headers' => ['Authorization' => 'Bearer '.$this->apiKey],
]);
return ChatCompletion::fromArray($response->toArray());
}
}
Register the provider in Symfony’s services:
# config/services.yaml
services:
Symfony\AI\Client\ClientInterface:
arguments:
$provider: '@amazee_ai.provider'
Use FallbackModelCatalog to define fallback logic (e.g., gpt-4 → mistral-7b):
use Symfony\AI\Client\FallbackModelCatalog;
$catalog = new FallbackModelCatalog([
'gpt-4' => ['primary' => 'gpt-4', 'fallback' => 'mistral-7b'],
'gpt-3.5-turbo' => ['primary' => 'gpt-3.5-turbo'],
]);
$this->aiClient->setModelCatalog($catalog);
Handle streaming with DeltaInterface:
use Symfony\AI\Client\Streaming\StreamingResponse;
$response = $this->aiClient->streamComplete($chat);
foreach ($response as $delta) {
if ($delta instanceof DeltaInterface) {
echo $delta->getContent(); // Process incremental updates
}
}
Wrap Symfony’s Client in a Laravel service:
// app/Services/AmazeeAIService.php
namespace App\Services;
use Symfony\AI\Client\ClientInterface;
use Symfony\Component\HttpClient\HttpClient;
class AmazeeAIService {
public function __construct() {
$client = HttpClient::create();
$this->aiClient = new ClientInterface(
new AmazeeAIProvider($client, config('amazee.ai.key'))
);
}
public function generate(string $prompt): string {
return $this->aiClient->complete(
new ChatCompletion('gpt-3.5-turbo', [new ChatMessage('user', $prompt)])
)->getContent();
}
}
ClientInterface.config/packages/ai.yaml:
amazee_ai:
api_key: '%env(AI_AMAZEEAI_API_KEY)%'
proxy_url: '%env(AI_AMAZEEAI_PROXY_URL)%'
AiEvent for observability (e.g., log completions):
use Symfony\AI\Event\AiEvent;
$dispatcher->addListener(AiEvent::COMPLETION, function (AiEvent $event) {
logger()->info('AI Completion', ['model' => $event->getModel()]);
});
$app->singleton(ClientInterface::class, function ($app) {
return new ClientInterface(new AmazeeAIProvider(
HttpClient::create(),
$app['config']['amazee.ai.key']
));
});
// app/Facades/AmazeeAI.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class AmazeeAI extends Facade {
protected static function getFacadeAccessor() {
return 'amazee.ai.client';
}
}
Usage:
$response = AmazeeAI::generate('Hello!');
FallbackModelCatalog for custom logic:
class CostOptimizedCatalog extends FallbackModelCatalog {
public function getModel(string $requestedModel): string {
if (str_contains($requestedModel, 'gpt-4') && auth()->user()->isPremium()) {
return $requestedModel;
}
return 'mistral-7b'; // Default fallback
}
}
MockClient for unit tests:
use Symfony\AI\Client\MockClient;
$mockClient = new MockClient();
$mockClient->expects($this)
->complete($chat)
->willReturn(new ChatCompletion('gpt-3.5-turbo', [new ChatMessage('assistant', 'Mocked response')]));
$this->aiClient->setClient($mockClient);
ProviderInterface expects OpenAI-compatible responses. Non-compliant providers (e.g., custom LLMs) may break.ChatCompletion::fromArray() or extend the trait:
use Symfony\AI\Client\OpenAI\CompletionsConversionTrait;
class CustomProvider implements ProviderInterface {
use CompletionsConversionTrait;
public function complete(ChatCompletion $completion): ChatCompletion {
$response = $this->callCustomLlm($completion);
return $this->convertCompletionsResponse($response);
}
}
DeltaInterface may not handle all provider-specific streaming formats (e.g., non-OpenAI-compatible chunks).public function streamComplete(ChatCompletion $completion): StreamingResponse {
$stream = $this->callStreamingEndpoint($completion);
yield from $this->normalizeStream($stream);
}
private function normalizeStream(iterable $stream): iterable {
foreach ($stream as $chunk) {
yield new DeltaInterface($chunk['content'] ?? '');
}
}
HttpClient may conflict with Laravel’s Http facade.use Symfony\Component\HttpClient\HttpClient;
$client = HttpClient::create();
$this->aiClient = new ClientInterface(new AmazeeAIProvider($client, $apiKey));
try {
return $this->aiClient->complete($chat);
} catch (RateLimitException $e) {
$chat->setModel('mistral-7b'); // Force fallback
return $this->aiClient->complete($chat);
}
How can I help you explore Laravel packages today?