askerakbar/gpt-trix-editor
Laravel package that brings AI-powered writing to the Trix editor. Generate, rewrite, and enhance rich text directly from the toolbar using OpenAI GPT, with configurable prompts and a simple Blade component for seamless integration into your app.
Install via Composer
composer require askerakbar/gpt-trix-editor
Publish package assets/config (if the package exposes them)
php artisan vendor:publish --tag=gpt-trix-editor-config
php artisan vendor:publish --tag=gpt-trix-editor-assets
The published config typically surfaces the OpenAI API key, model name, temperature, and the prompt templates that the editor’s GPT buttons send.
Set your OpenAI key in .env:
OPENAI_API_KEY=sk-...
The package proxies requests server‑side, so the key should never reach the browser — confirm the published config reads from env('OPENAI_API_KEY') and that the underlying proxy route is behind your web/auth middleware.
Use the field inside a Filament form
use Askerakbar\GptTrixEditor\Forms\Components\GptTrixEditor;
GptTrixEditor::make('body')
->label('Content')
->required()
->columnSpanFull();
First use case to try: a Resource form for a Post/Article/Page model where editors need to draft long-form copy. Type a short prompt into the GPT panel, let it generate the body, then hand-edit the Trix content before saving. Once that works, extend to “rewrite selected text”, “fix grammar”, or “summarise” prompts.
Where to look first if something doesn’t render: resources/js and resources/views inside the package (Trix + GPT toolbar assets), the package’s route/provider in src/, and the published config file — that’s where the proxy endpoint and prompt list live.
Standalone field vs. resource form. Because it’s a standard Forms\Components\Field, it drops into any Filament form — panel resources, custom Livewire pages, relation managers. The only integration work is ensuring the asset registration (usually automatic via the service provider) is picked up by the panel that renders it.
Pair with a “prompt-first” authoring flow. Typical pattern: a plain TextInput for title/brief, then GptTrixEditor for body. Editors write a sentence in the brief, generate, edit, save. Keep the GPT button usage optional so forms still work with the key unset.
Field-level prompt customisation. Set per-field prompts so a “product description” field isn’t using the same template as a “legal notice” field:
GptTrixEditor::make('description')
->gptPrompt('Write a concise, benefit-led product description in 2 short paragraphs.');
(Check the published config / field methods for the exact setter names; the pattern is to override the global default at the field level.)
Model / temperature control. Expose ->gptModel('gpt-4o-mini') or config equivalents for cheaper fields, and reserve larger models for the long-form fields where quality matters. This is the single biggest cost lever.
Wrap in a Filament Section with contextual helpers. Put the editor in a Section::make('Content')->description('Use the ✨ button to draft, then edit before publishing.') so editors know the field is AI-assisted rather than purely manual.
Sanitise on output, not just input. Store the Trix HTML as-is, but render through a sanitising step (HtmlSanitizer, Blade’s {!! !!} with a purifier) — GPT output can contain markup you did not intend.
Reuse the field across Resources by extracting the component config into a small helper (e.g. ContentField::make()) so prompt, model, and toolbar options stay consistent as you add more Resources.
Filament version drift is the big one. Last release was 2024-09, which puts it squarely in the Filament v3 era. Verify compatibility with your installed Filament before committing; a v4 panel may need a fork or a pinned Filament version. Check composer.json require constraints first.
Auth on the proxy route. The GPT features work by POSTing to a Laravel route that calls OpenAI. Make sure that route is not publicly reachable — an unauthenticated user hitting it directly is burning your API budget. If the package ships a bare route, wrap it in auth/throttle middleware.
Rate-limit and cap. Add throttle: to the proxy route and consider a per-user daily cap (e.g. a simple RateLimiter::for('gpt-trix', ...)) — editors will hammer the button otherwise.
Cost surprises on long documents. “Rewrite entire content” on a 4k-word article is a full completion every time. Prefer “rewrite selection” / “continue” behaviour and a cheap default model (gpt-4o-mini) so exploratory clicking doesn’t run up a bill.
No streaming means spinner UX matters. If the package waits for a full completion, the button can appear frozen for several seconds on large models. Disable the button while a request is in flight and consider a toast (Notification::make()->body('Generating…')) for feedback.
Config caching in production. If you php artisan config:cache, any change to prompt templates or the model in the config file requires a re-cache. Prefer setting per-field prompts in code so they ship with the deploy.
Trix attachments vs. GPT. Trix uploads files to your storage — that has nothing to do with the GPT side. Make sure your Trix attachment endpoint is configured independently; the GPT feature only sees text content, not embedded images.
Debugging a silent button. If the ✨ button does nothing: open the browser console (JS error → assets not published/registered), check the network tab for a 419 (CSRF/middleware issue on the proxy route) or 500 with an OpenAI error (bad key/model name), then verify config('services.openai'). Add a Log::debug() in the package’s controller as a temporary measure.
Extension points. The two real levers are the published config (prompts, model, endpoint) and subclassing/replacing the field component if you need custom UI. Anything deeper means vendoring the package — plan for that given the low star count and stale release.
Long-term maintenance risk. With ~43 stars and a single 2024 release, treat it as a thin wrapper you may need to own. If the AI behaviour is central to your product, budget time to be able to fork it (or replace it with a small custom GptTrixEditor in your own app) rather than treating it as a stable dependency.
How can I help you explore Laravel packages today?