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

Openai Laravel Package

blinq/openai

A Laravel-friendly wrapper around the OpenAI API, making it easy to send chat completions, generate embeddings, and call other endpoints from your PHP applications. It includes configuration, facades, and a clean, expressive interface that fits naturally into Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer and confirm the PHP constraint in composer.json before you commit (a Nov 2023 release typically targets PHP 8.0/8.1+ and Guzzle 7):

composer require blinq/openai

Where to look first

  1. README.md — the package is a thin wrapper, so the README is effectively the API surface. Skim it once, top to bottom.
  2. src/ — usually a single client class plus a handful of request/response DTOs. Read the constructor: that's where the API key, base URI, and HTTP client are injected.
  3. composer.json — note the exact Guzzle and PHP versions. You will be constrained by them.
  4. tests/ (if present) — the fastest way to see real request/response shapes without spending money on API calls.

Laravel wiring

There is almost certainly no service provider or auto-discovery. Wire it yourself:

// config/openai.php
return [
    'api_key' => env('OPENAI_API_KEY'),
    'base_uri' => env('OPENAI_BASE_URI', 'https://api.openai.com/v1'),
    'timeout' => (int) env('OPENAI_TIMEOUT', 60),
];
// app/Providers/OpenAiServiceProvider.php
public function register(): void
{
    $this->app->singleton(Client::class, fn () => new Client(
        config('openai.api_key'),
        // adjust to the real constructor signature
    ));
}

First use case — verify the shape before building on it

Prove the request/response cycle in php artisan tinker (or a throwaway Artisan command) against a chat completion. Confirm three things you'll depend on everywhere: how errors surface, whether responses are arrays or objects, and whether the usage block is returned intact:

$client = app(\Blinq\OpenAi\Client::class);
$response = $client->chat([/* ... */]);
dump($response);

Do this before writing any abstraction. The wrapper's value is convenience; if the ergonomics are wrong for your use case, replace it with Illuminate\Support\Facades\Http in an afternoon and lose nothing.

Implementation Patterns

Never call the vendor client from controllers. Wrap it in a single application service so you have one seam to fake, log, and swap:

final class ChatService
{
    public function __construct(private Client $client) {}

    public function complete(array $messages, string $model = 'gpt-4o-mini'): string
    {
        $response = $this->client->chat([
            'model' => $model,
            'messages' => $messages,
        ]);

        return $this->extractContent($response); // isolate the shape-parsing here
    }
}

That extractContent() method is the highest-value line in your codebase: it is the only place that knows the wrapper's response shape, so an API or package change touches one function.

Push everything non-interactive into a job. Chat calls routinely exceed a web request's comfort zone. A queued job with $timeout = 120 and $tries = 1 (retries handled explicitly, see below) is the default pattern:

final class GenerateSummary implements ShouldQueue
{
    public int $timeout = 120;
    public int $tries = 1;

    public function handle(ChatService $chat): void { /* ... */ }
}

Centralise retries and backoff yourself. Wrappers of this vintage rarely implement rate-limit handling. If the client exposes no retry config, wrap the call:

$result = retry(
    times: 3,
    callback: fn () => $this->client->chat($payload),
    sleepMilliseconds: fn (int $attempt) => $attempt * 2000,
    when: fn (\Throwable $e) => $this->isRetryable($e), // 429, 500, 503 — never 400
);

Track cost in one place. Read usage.prompt_tokens / usage.completion_tokens from every response and log them alongside the feature name. One wrapper method that logs and forwards pays for itself the first time a runaway loop costs you $200.

Test with a fake bound in the container. Because you bound the concrete client as a singleton, $this->mock(Client::class) in a feature test removes all network calls. Assert on the payload you send — model name, message roles, max_tokens — not on the model's prose, which is nondeterministic.

Stream only if the wrapper supports it. Most small wrappers do not expose stream: true with an iterable response. If the README doesn't document streaming, assume it's absent: for a chat UI, either poll a job status or drop to a raw Guzzle/Http SSE implementation for that one endpoint.

Gotchas and Tips

Treat it as vendored code, not a dependency. Seven stars, zero dependents, last release November 2023. Do not expect fixes for a 2024+ API change. Pin the exact version in composer.json and assume you may need to fork it into your org. This is the single most important consideration in the whole assessment.

Verify which endpoints still exist before you design around them. A late-2023 wrapper likely exposes /completions, /edits, and the first-generation /fine-tunes, all of which OpenAI has since deprecated or restructured. Grep src/ for the endpoints you intend to use and confirm each still responds against the live API. Only build on chat completions, embeddings, images, audio, and moderation without checking.

Model names are almost certainly defaulted or hardcoded. Any default in the wrapper is a 2023 model. Always pass model explicitly from your own config so you can upgrade without touching vendor code.

Guzzle's default timeout is 0 (no timeout). If the wrapper doesn't set one, a hung request ties up an FPM worker indefinitely. Set timeout explicitly — 60s for text, 120s+ for image and audio endpoints — and set a shorter connect_timeout separately.

Errors are probably generic exceptions. The wrapper may throw a plain \Exception with the raw body rather than a typed exception per status. Parse the status code yourself and — critically — do not retry 400s: a malformed payload will fail identically three times and burn latency. Also expect the API key to appear in stack traces if the wrapper puts it in the message; scrub it in your exception handler's report().

Response shape may differ from the HTTP response. Many thin wrappers decode to associative arrays, some to stdClass, some unwrap the choices array for you. Dump one real response early and encode the assumption in a single accessor method.

Streaming plus PHP-FPM is a trap. If you do implement SSE, session_write_close(), disable output buffering, and set X-Accel-Buffering: no if you're behind nginx — otherwise output arrives in one lump and the feature appears broken.

Extension points are limited. Realistically you have three: subclass the client and override the HTTP-facing methods, decorate it behind your own interface (preferred), or swap the container binding for your own implementation entirely. The third is the escape hatch — since your code only touches your ChatService, replacing the underlying library is a contained change.

Watch for the config quirk of a missing organization/project header. If you're on a team account, requests may be billed or rate-limited against the wrong scope. Check whether the constructor accepts headers for these; if not, you'll need a fork or a custom Guzzle client with default headers.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource