Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ai Open Ai Platform Laravel Package

symfony/ai-open-ai-platform

OpenAI platform integration for Symfony AI Platform, adding GPT chat completions, embeddings, DALL-E image generation, Whisper audio transcription, and text-to-speech support.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require symfony/ai-open-ai-platform
    
  2. Configure API key in .env:
    AI_OPEN_AI_KEY="your-openai-api-key"
    
  3. Basic usage in a controller:
    use Symfony\AI\OpenAI\Client\ChatCompletionClientInterface;
    
    class ChatController extends AbstractController
    {
        public function __construct(
            private ChatCompletionClientInterface $chatClient
        ) {}
    
        public function ask(ChatMessage $message): Response
        {
            $response = $this->chatClient->complete(
                'gpt-4',
                [$message]
            );
            return $this->json($response->getContent());
        }
    }
    

First Use Case: Chatbot Endpoint

// src/Controller/AiChatController.php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class AiChatController extends AbstractController
{
    public function __invoke(
        Request $request,
        ChatCompletionClientInterface $chatClient
    ): Response {
        $prompt = $request->request->get('prompt');
        $response = $chatClient->complete(
            'gpt-3.5-turbo',
            [new ChatMessage(ChatRole::User, $prompt)]
        );
        return $this->json(['reply' => $response->getContent()]);
    }
}

Route it:

# config/routes.yaml
ai_chat:
    path: /ai/chat
    controller: App\Controller\AiChatController
    methods: POST

Implementation Patterns

Core Workflows

  1. Chat Completions

    // Single turn
    $response = $chatClient->complete(
        'gpt-4',
        [new ChatMessage(ChatRole::User, 'Explain quantum computing')]
    );
    
    // Multi-turn conversation
    $messages = [
        new ChatMessage(ChatRole::System, 'You are a helpful assistant'),
        new ChatMessage(ChatRole::User, 'What is PHP?'),
        new ChatMessage(ChatRole::Assistant, 'PHP is a server-side scripting language...'),
        new ChatMessage(ChatRole::User, 'Give me an example')
    ];
    $response = $chatClient->complete('gpt-3.5-turbo', $messages);
    
  2. Streaming Responses

    use Symfony\AI\OpenAI\Client\StreamingChatCompletionClientInterface;
    
    $stream = $streamingChatClient->stream(
        'gpt-3.5-turbo',
        [new ChatMessage(ChatRole::User, 'Tell me a joke')]
    );
    
    foreach ($stream as $delta) {
        echo $delta->getContent();
    }
    
  3. Embeddings

    $embeddingClient = $container->get(EmbeddingClientInterface::class);
    $embeddings = $embeddingClient->create('text-embedding-ada-002', ['Your text here']);
    
  4. Batch Requests (v0.14.0)

    // Submit many chat jobs at once via the asynchronous jobs API
    $batch = $batchClient->submit([
        new ChatMessage(ChatRole::User, 'Summarise document A'),
        new ChatMessage(ChatRole::User, 'Summarise document B'),
        new ChatMessage(ChatRole::User, 'Summarise document C'),
    ], 'gpt-3.5-turbo');
    
    // Persist the batch id; poll later from a worker/console command
    $batchId = $batch->getId();
    
    // In a scheduled command
    $result = $batchClient->retrieve($batchId);
    foreach ($result->getResponses() as $response) {
        $this->logger->info($response->getContent());
    }
    
  5. Realtime Sessions — Voice/Audio Agents (v0.14.0)

    use Symfony\AI\OpenAI\Client\RealtimeClientInterface;
    
    $session = $realtimeClient->createSession([
        'model' => 'gpt-4o-realtime-preview',
        'voice' => 'alloy',
        'modalities' => ['audio', 'text'],
    ]);
    
    // Wire $session->getUrl() / ephemeral token to your browser WebRTC client
    return $this->json([
        'url' => $session->getUrl(),
        'token' => $session->getClientSecret(),
    ]);
    
  6. Cost Tracking via TokenUsage (v0.14.0)

    $response = $chatClient->complete('gpt-4', $messages);
    $usage = $response->getUsage();
    $cost = $this->costCalculator->estimate(
        $usage->getModel(),         // NEW: model now attached to usage
        $usage->getPromptTokens(),
        $usage->getCompletionTokens()
    );
    

Integration Patterns

  1. Service Layer Abstraction

    // src/Service/AiChatService.php
    class AiChatService
    {
        public function __construct(
            private ChatCompletionClientInterface $chatClient
        ) {}
    
        public function generateResponse(string $prompt): string
        {
            $response = $this->chatClient->complete(
                'gpt-3.5-turbo',
                [new ChatMessage(ChatRole::User, $prompt)]
            );
            return $response->getContent();
        }
    }
    
  2. Event-Driven Architecture

    $eventDispatcher->addListener(
        ChatCompletionEvent::class,
        function (ChatCompletionEvent $event) {
            $this->logger->info('AI Response:', ['content' => $event->getContent()]);
        }
    );
    
  3. Async Batch Processing

    // src/Command/DispatchBatchCommand.php
    class DispatchBatchCommand extends Command
    {
        protected static string $defaultName = 'app:ai:dispatch-batch';
    
        public function __construct(
            private BatchClientInterface $batchClient,
            private EntityManagerInterface $em
        ) { parent::__construct(); }
    
        protected function execute(InputInterface $input, OutputInterface $output): int
        {
            $jobs = $this->em->getRepository(PromptJob::class)->findPending();
            $batch = $this->batchClient->submit(
                array_map(fn($j) => new ChatMessage(ChatRole::User, $j->getPrompt()), $jobs)
            );
            $this->em->flush(); // store $batch->getId() against jobs
            return Command::SUCCESS;
        }
    }
    
  4. Realtime Voice Agent Endpoint

    // Return an ephemeral session to the frontend; never expose your real API key
    class RealtimeTokenController extends AbstractController
    {
        public function __invoke(RealtimeClientInterface $realtimeClient): Response
        {
            return $this->json($realtimeClient->createEphemeralSession('gpt-4o-realtime-preview'));
        }
    }
    

Configuration Patterns

  1. Environment-Specific Config

    # config/packages/ai_open_ai.yaml
    ai_open_ai:
        client:
            api_key: '%env(AI_OPEN_AI_KEY)%'
            base_uri: '%env(AI_OPEN_AI_BASE_URI)%'
            timeout: 30
            retries: 3
            model_routing:
                default: 'gpt-3.5-turbo'
                premium: 'gpt-4'
                realtime: 'gpt-4o-realtime-preview'
    
  2. Model Routing

    $model = $user->isPremium() ? 'gpt-4' : 'gpt-3.5-turbo';
    $response = $chatClient->complete($model, $messages);
    
  3. Model Catalog Pinning

    • v0.14.0 ships a refreshed model catalog. If you rely on a specific model string (e.g. gpt-4), verify it's still listed and pin it in your config rather than relying on defaults.

Gotchas and Tips

Common Pitfalls

  1. API Key Management

    • ❌ Hardcoding keys in config files
    • ✅ Use environment variables
    ai_open_ai:
        client:
            api_key: '%env(AI_OPEN_AI_KEY)%'
    
  2. Rate Limiting

    • OpenAI enforces rate limits
    • Batch requests count against a separate, higher quota — good for large volumes.
    try {
        $response = $httpClient->request('POST', $url);
    } catch (TransportExceptionInterface | ClientExceptionInterface $e) {
        if ($e->getCode() === 429) {
            sleep(2);
            retry();
        }
    }
    
  3. Token Limits

    • GPT-4 has an 8192 token limit (4097 for chat)
    $tokenCount = $this->countTokens($prompt);
    if ($tokenCount > 4000) {
        throw new \RuntimeException('Prompt too long');
    }
    
  4. Streaming Quirks

    • Streams emit DeltaInterface objects, not raw strings
    $stream = $streamingChatClient->stream('gpt-3.5-turbo', [$message]);
    $fullResponse = '';
    foreach ($stream as $delta) {
        $fullResponse .= $delta->getContent();
    }
    
  5. Batch Requests Are Asynchronous (v0.14.0)

    • submit() returns immediately with a batch id — it does not return results.
    • Always persist the batch id and poll from a scheduled command; don't block a web request on it.
    • Results may arrive out of order relative to input; map by custom_id if you need correlation.
  6. Realtime Sessions Are Stateful (v0.14.0)

    • Realtime is WebSocket/WebRTC, not HTTP request/response. Your normal PHP worker won't keep the connection alive.
    • Use ephemeral client secrets for browsers; never ship your server-side API key.
    • Costs are billed per audio token — track TokenUsage aggressively on realtime sessions.
  7. TokenUsage Now Carries the Model (v0.14.0)

    • getUsage()->getModel() is now populated — use it for accurate per-model cost reporting instead of inferring the model from your request.
    • Older cached/recorded usage objects won't have the model; backfill or default if null.

Debugging Tips

  1. Enable Debug Mode

    ai_open_ai:
        client:
            debug: true
    
    • Logs raw API requests/responses to var/log/dev.log
  2. Inspect API Errors

    try {
        $response = $chatClient->complete('invalid-model', [$message]);
    } catch (ApiErrorException $e) {
        $error = $e->getError();
        if ($error->getType() === 'invalid_request_error') {
            // Model not found, etc. — often after a model catalog update
        }
    }
    
  3. Token Counting

    use Symfony\AI\OpenAI\Tokenizer\TokenizerInterface;
    
    $tokenizer = $container->get(TokenizerInterface::class);
    $tokenCount = $tokenizer->countTokens($prompt);
    
  4. Cassette Verification (v0.14.0)

    • HTTP record/replay is now stricter: cassettes are verified before replay. Stale cassettes will fail your test suite with a request-mismatch error.
    • Re-record cassettes after upgrading or after any prompt/model change. This catches drift between tests and production traffic.

Extension Points

  1. Custom Model Clients

    // src/OpenAI/CustomChatClient.php
    class CustomChatClient implements ChatCompletionClientInterface
    {
        public function __construct(
            private ChatCompletionClientInterface $decorated
        ) {}
    
        public function complete(string $model, array $messages, ?array $options = null): ChatCompletionResponseInterface
        {
            if (str_contains($messages[0]->getContent(), 'hack')) {
                throw new \RuntimeException('Blocked prompt');
            }
            return $this->decorated->complete($model, $messages, $options);
        }
    }
    

    Register as service:

    services:
        Symfony\AI\OpenAI\Client\ChatCompletionClientInterface: '@App\OpenAI\CustomChatClient'
    
  2. Custom Batch Client Decoration

    • Wrap BatchClientInterface to add metrics, idempotency keys, or a DB-backed ledger of submitted batches.
  3. Realtime Session Hooks

    • Wrap RealtimeClientInterface to enforce per-user session caps and inject moderation on emitted audio.
  4. Response Transformers

    // src/OpenAI/ResponseTransformer.php
    class ResponseTransformer
    {
        public function transform(ChatCompletionResponseInterface $response): array
        {
            $usage = $response->getUsage();
            return [
                'content' => $response->getContent(),
                'model'   => $usage?->getModel(),
                'cost'    => $usage ? $this->costFor($usage) : null,
            ];
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin