symfony/ai-decart-platform
Symfony AI bridge for the Decart Platform. Connect to Decart’s APIs and models like Lucy through a Symfony-friendly integration, with links to platform documentation and contribution/issue resources in the main Symfony AI repository.
Install Dependencies
composer require symfony/ai symfony/ai-decart-platform
Ensure your Laravel app uses PHP 8.2+ and Symfony 6.4+ components.
Configure Decart Credentials
Add to .env:
DECART_API_KEY=your_key_here
DECART_API_URL=https://platform.decart.ai/api/v1
Register the Provider
Create a service provider (e.g., App\Providers\DecartAIServiceProvider) and bind the Decart provider:
use Symfony\Component\AI\Client\AiClient;
use Decart\Provider;
public function register(): void
{
$this->app->singleton(AiClient::class, function ($app) {
$client = new AiClient();
$client->addProvider(new Provider(
$app['config']['decart.api_key'],
$app['config']['decart.api_url']
));
return $client;
});
}
First Use Case: Text Generation
Inject AiClient into a controller or service:
use Symfony\Component\AI\Client\AiClient;
public function generateText(AiClient $aiClient)
{
$model = $aiClient->getModel('lucy');
$response = $model->chat('Summarize this article: "..."');
return $response->getContent();
}
Verify with a Test Use Laravel’s HTTP tests to validate the integration:
public function testDecartIntegration()
{
$response = $this->post('/generate', [
'prompt' => 'Hello, Decart!'
]);
$response->assertOk();
}
Leverage the Provider abstraction to decouple Decart-specific logic from your business layer:
// Define a custom provider interface
interface AiProviderInterface
{
public function getModel(string $modelName);
}
// Implement Decart-specific logic
class DecartProvider implements AiProviderInterface
{
public function getModel(string $modelName): AiModel
{
return match ($modelName) {
'lucy' => new LucyModel($this->client),
default => throw new \InvalidArgumentException("Model {$modelName} not supported"),
};
}
}
Route requests to Decart models dynamically using Laravel’s service container:
// config/ai.php
return [
'models' => [
'lucy' => [
'provider' => DecartProvider::class,
'type' => 'chat',
],
],
];
Create a facade to simplify usage in Blade or controllers:
// app/Facades/DecartAI.php
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class DecartAI extends Facade
{
protected static function getFacadeAccessor()
{
return 'ai.decart';
}
}
Register the facade in config/app.php and bind the service:
'AiDecart' => function ($app) {
return $app->make(AiClient::class)->getModel('lucy');
},
Offload long-running Decart calls to queues:
// app/Jobs/GenerateTextJob.php
use Symfony\Component\AI\Client\AiModel;
class GenerateTextJob implements ShouldQueue
{
public function handle(AiModel $model)
{
$response = $model->chat($this->prompt);
// Store or process response
}
}
Cache frequent Decart responses (e.g., embeddings) using Laravel’s cache:
public function getEmbedding(string $text)
{
return Cache::remember(
"decart_embedding_{$text}",
now()->addHours(1),
fn() => $this->aiClient->getModel('lucy')->embed($text)
);
}
Use Laravel’s retry mechanism for transient failures:
use Illuminate\Support\Facades\Http;
public function callDecartApi()
{
return Http::withOptions(['timeout' => 30])
->retry(3, 100)
->post('https://platform.decart.ai/api/v1/chat', [
'prompt' => '...',
]);
}
For semantic search, integrate Decart embeddings with Scout:
use Laravel\Scout\Searchable;
class Product extends Model implements Searchable
{
public function toSearchableArray()
{
return [
'title' => $this->title,
'embedding' => $this->aiClient->getModel('lucy')->embed($this->description),
];
}
}
API Key Management
.env and env() helper. Rotate keys periodically via laravel-env-editor.Rate Limiting
use Symfony\Component\AI\Exception\RateLimitExceededException;
try {
$response = $model->chat($prompt);
} catch (RateLimitExceededException $e) {
sleep(2 ** $attempt); // Exponential backoff
retry();
}
Model Availability
lucy) may have downtime or regional restrictions.try {
return $model->chat($prompt);
} catch (\Exception $e) {
return Cache::get('fallback_response') ?: 'Service unavailable';
}
Response Parsing
use JsonSchema\Validator;
$validator = new Validator();
$validator->validate($response->getContent(), (object) [
'type' => 'object',
'properties' => ['content' => ['type' => 'string']],
]);
Dependency Conflicts
symfony/ai may conflict with Laravel’s http-client or guzzle.HttpClient as a drop-in replacement:
$client = new \Symfony\Component\HttpClient\HttpClient([
'base_uri' => config('decart.api_url'),
'auth_bearer' => config('decart.api_key'),
]);
Streaming Quirks
StreamedResponse.$response = $model->chat($prompt)->stream();
$buffer = '';
while ($chunk = $response->getChunk()) {
$buffer .= $chunk;
}
return response($buffer);
Log API Requests/Responses Use Laravel’s logging to inspect Decart calls:
\Log::debug('Decart API Request', [
'url' => $request->getUri(),
'body' => $request->getContent(),
]);
Mock Decart in Tests Use Laravel’s HTTP mocking to avoid real API calls:
Http::fake([
'platform.decart.ai/api/v1/chat' => Http::response([
'content' => 'Mocked response',
]),
]);
Monitor Performance Track Decart API latency with Laravel Telescope or custom metrics:
$start = microtime(true);
$response = $model->chat($prompt);
\Log::info('Decart API latency', [
'time' => microtime(true) - $start,
'prompt' => $prompt,
]);
Custom Model Adapters
Extend the AiModel interface to add Decart-specific features:
class DecartModel extends AiModel
{
public function embed(string $text): array
{
return $this->client->postJson('/embed', ['text' => $text])->toArray();
}
}
Prompt Templates Create reusable prompt templates in Laravel’s config:
// config/decart-prompts.php
return [
'summarize' => 'Summarize the following in 3 bullet points: {{text}}',
];
Use them in services:
$prompt = str_replace('{{text
How can I help you explore Laravel packages today?