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

Laravel Filament Image Generator Field Laravel Package

naturalgroove/laravel-filament-image-generator-field

Laravel Filament Image Generator Field adds an AI-powered image generation field to Filament forms, letting users create images from text prompts directly in your admin panel. Includes configurable API integration and a simple, native field experience.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Filament form field that lets an editor type a prompt, call an AI image API, and drop the result straight into a normal file-upload field. The whole workflow lives inside a Filament form, so start by getting it rendering on one resource before doing anything clever.

Install and publish config:

composer require naturalgroove/laravel-filament-image-generator-field
php artisan vendor:publish --tag="image-generator-field-config"

Add your provider credentials to .env (the package wraps the OpenAI image endpoint, so an OPENAI_API_KEY and billing on that account are required):

OPENAI_API_KEY=sk-...

Then add the field to any Filament form — a PostResource hero-image field is the fastest first use case:

use NaturalGroove\FilamentImageGeneratorField\ImageGeneratorField;

public static function form(Form $form): Form
{
    return $form->schema([
        TextInput::make('title')->required(),
        ImageGeneratorField::make('image')
            ->label('Hero image')
            ->disk('public')
            ->directory('heroes'),
    ]);
}

Where to look first, in order:

  1. config/image-generator-field.php — model, size, quality, disk, and any default prompt settings. This is the file you will actually touch.
  2. The field class itself (src/.../ImageGeneratorField.php) — confirms the exact fluent methods and the HTTP client/service it calls. The README shows the happy path; the class shows the real API surface.
  3. The README usage section — if it disagrees with the class, trust the class.

Note: verify exact class names and method names against the installed version. The package is small (16 stars, last release Dec 2024) and the public API has evolved; copy from the README of the tag you actually installed, not from blog posts.

Implementation Patterns

Pair it with a real file field. The generator is most useful when it writes into standard Laravel storage that the rest of your app already understands. Either chain storage config directly onto the field, or pair it with FileUpload / Spatie Media Library so downstream code (image conversions, S3 sync, cleanup) keeps working unchanged.

ImageGeneratorField::make('image')
    ->disk('public')          // must be a disk the browser can read
    ->directory('posts/heroes')
    ->visibility('public');

Build prompts from other form fields. The best day-to-day use is a prompt assembled from the record's own content, not free-typed each time. Use $get() with reactive fields so the prompt stays in sync:

TextInput::make('title')
    ->live(onBlur: true),

ImageGeneratorField::make('image')
    ->prompt(fn (Get $get) => "Editorial photo illustrating: {$get('title')}, no text, cinematic lighting"),

Keep the prompt builder pure and deterministic — it should not hit the DB during form hydration.

Generate into a draft, not production. Treat generation as an editorial step. Let the field write to a temp/draft disk or a pending directory, then promote on save. This makes "regenerate" cheap and keeps abandoned prompts from littering your media library.

Regeneration as a first-class action. Expose the field on edit forms and let editors overwrite. Store the prompt used (image_prompt column) alongside the image so you can show what produced it and re-run it later for a different size or style.

Gate it. Generation costs money per call. Wrap usage in authorization and make the field ->disabled(fn () => ! auth()->user()->can('generate-images')) or hide it entirely for non-editors. In multi-tenant apps, decide whether the API key is global or per-tenant before shipping.

Custom field subclass for house style. If every form needs the same model/size/quality defaults, subclass the field and set them once:

class BrandImageField extends ImageGeneratorField
{
    protected function setUp(): void
    {
        parent::setUp();
        $this->model('dall-e-3')->size('1024x1024');
    }
}

Then use BrandImageField::make('image') everywhere and change defaults in one place.

Async where it matters. Generation is a slow network call (several seconds to tens of seconds). For an admin behind a spinner this is fine. For anything user-facing, move generation to a queued job and have the field display a "generating…" state — the field is a UI convenience, not a job runner.

Gotchas and Tips

  • It is a blocking HTTP call during a Livewire request. DALL-E-class endpoints routinely take 10–30s. If your PHP max_execution_time, web server timeout, or Livewire request timeout is lower, the form will fail with an opaque 500 or a dropped connection. Raise timeouts on admin routes, or queue the work. This is the single most common "it doesn't work" report.
  • Cost is per call and invisible until the invoice. There is no dry-run mode. Add throttling or a confirmation step before wiring this into any form a non-admin can submit. Also check whether a failed/moderated call still bills — assume it might.
  • API key resolution and config caching. After changing .env, run php artisan config:clear (and config:cache in production). A stale cached config is the usual cause of "invalid API key" on a server where the key is definitely set.
  • Size/model constraints are enforced by the upstream API, not the field. Modern image models accept only a small set of dimensions (e.g. 1024x1024, 1024x1792, 1792x1024 for DALL-E 3). Passing an arbitrary size gives a provider-side 400 that surfaces as a vague validation error. Validate against the allowed list before calling.
  • Disk visibility. Saving to a private or local disk "works" but the preview renders broken because the URL isn't publicly reachable. Use a public/S3 disk with public visibility, or generate a temporary URL for preview.
  • Content moderation rejections. Prompts are filtered server-side; a rejection is a normal outcome, not a bug. Catch the error and return a friendly message ("prompt was rejected — try rewording") rather than letting a raw exception bubble into the Filament notification.
  • Filament version compatibility. Last release was Dec 2024. Confirm the package's Filament major (v3 vs v4) matches your app before installing; mismatches typically show up as a missing field or a fatal in setUp().
  • Assets may need publishing. If the prompt UI renders unstyled, run php artisan filament:assets (and the package's own publish tag from the README). Panel registration via ->plugin(...) may or may not be needed depending on version — check the README for the installed tag.
  • Temp uploads and cleanup. If the field stages a generated image as a Livewire temporary upload, those files land in livewire-tmp and are pruned on a schedule. Don't depend on generated-but-unsaved images surviving; save the record to persist.
  • Never hit the real API in tests. Stub with Http::fake() on the provider endpoint (or Storage::fake() for the file side) so the suite is fast, deterministic, and free. Add one integration test behind an env flag for the real call.
  • Debugging. Wrap usage in a try/catch during development and log the provider response body via Http::onError. The field's notification often collapses the upstream error into a generic message; the raw response is what tells you it was a quota/429 versus a bad-key/401 versus a moderation/400.
  • Extension points. The field is small, so the reliable extension points are (a) subclassing to change setUp() defaults, (b) the published config for model/size/disk, and (c) swapping the underlying service binding if the package uses the container. Don't monkey-patch vendor files — subclass instead, since the package updates without much ceremony and you want to absorb those.
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.
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo