Search by

yousefaman / filament-smart-fill

yousef-aman

Fill Filament forms from a PDF, an image or pasted text with AI, and review every value before it lands

Package info

github.com/yousef-aman/filament-smart-fill

pkg:composer/yousefaman/filament-smart-fill

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.1.0 2026-10-10 19:44 UTC

This package is auto-updated.

Last update: 2026-10-10 21:38:17 UTC


README

Latest Version on Packagist Total Downloads tests Filament License

Fill a Filament form from a PDF, an image or pasted text with AI, and review every value before it lands.

Filament Smart Fill demo

If this package saves you time, a star on GitHub helps other Filament developers find it.

Requirements

  • PHP 8.3+
  • Laravel 12.62+ or 13.15+ (the versions laravel/ai supports)
  • Filament 4.15+ or 5.10+
  • An AI provider configured in config/ai.php

Tested combinations

CI runs on every push and pull request, and once a week to catch breakage from new Filament, Livewire or laravel/ai releases.

PHP Filament Laravel (Testbench)
8.3, 8.4 4.15+, 5.10+ 12 (Testbench 10), 13 (Testbench 11)
8.3 4.15 (lowest dependencies) 12 (Testbench 10)

The stable legs install the latest patch release of each version listed. The lowest leg installs the oldest versions the package allows.

Installation

composer require yousefaman/filament-smart-fill
php artisan vendor:publish --tag=ai-config

Add the key of the provider you use to .env, for example:

OPENAI_API_KEY=your-key

Smart Fill uses the default provider from config/ai.php. To pick another one, see Usage.

Publish the package config (optional):

php artisan vendor:publish --tag="filament-smart-fill-config"

Publish the translations (optional):

php artisan vendor:publish --tag="filament-smart-fill-translations"

Usage

Add the action to the header of a Create or Edit page:

use Filament\Resources\Pages\CreateRecord;
use YousefAman\FilamentSmartFill\Actions\SmartFillAction;

class CreateInvoice extends CreateRecord
{
    protected static string $resource = InvoiceResource::class;

    protected function getHeaderActions(): array
    {
        return [SmartFillAction::make()];
    }
}

The action opens a modal in two steps. In the first, the user uploads a document or pastes text. In the second, a review grid lists every field the model found, with the current value, the proposed value and a status. The user ticks the values to apply and clicks Apply. The values are written into the form; nothing is saved until the user clicks Save.

A field that already holds a different value shows as Changed and stays unticked, so the AI never overwrites by accident. An empty field shows as New and is ticked.

Action options

SmartFillAction::make()
    ->only(['number', 'customer_id', 'issued_on'])
    ->except(['internal_notes'])
    ->provider('openai', model: 'gpt-4o')
    ->instructions('Amounts are in US dollars. Dates in the document are day-first.')
    ->overwriteByDefault()
    ->acceptedFileTypes(['application/pdf', 'image/png'])
    ->maxFileSize(5120);
Option What it does
only(array $statePaths) Fill only these fields. Paths are relative to the form, such as number or address.city.
except(array $statePaths) Never fill these fields.
provider($provider, model: null) The AI provider (a Laravel\Ai\Enums\Lab case or a name from config/ai.php) and, optionally, the model. Use this instead of model(), which Filament's Action already uses for the record's model class.
instructions(string $text) Extra guidance added to the agent's instructions.
overwriteByDefault() Tick Changed rows by default.
acceptedFileTypes(array $mimeTypes) MIME types the upload accepts. Defaults to the config.
maxFileSize(int $kilobytes) Largest accepted upload. Defaults to the config.

When provider() is not called, the action uses SMART_FILL_PROVIDER and SMART_FILL_MODEL from the config, and falls back to the defaults in config/ai.php.

Field macros

use Filament\Forms\Components\TextInput;

TextInput::make('reference')
    ->smartFillHint('The purchase order number, printed top right. Looks like PO-12345.');

TextInput::make('internal_code')
    ->smartFill(false);
  • smartFillHint() adds a hint for the model about where to find the value.
  • smartFill(false) keeps a field out of Smart Fill. It accepts a closure.

Configuration

config/filament-smart-fill.php:

Key Default Meaning
provider env('SMART_FILL_PROVIDER') Provider name. null uses the default in config/ai.php.
model env('SMART_FILL_MODEL') Model name. null uses the provider's default.
timeout 60 Seconds to wait for the provider.
max_file_size 10240 Upload limit in kilobytes.
accepted_file_types PDF, PNG, JPEG, WebP, plain text Accepted MIME types.
max_text_length 50000 Characters accepted in the paste-text field.
review_ttl 1800 Seconds a pending review is kept before it expires.

Limits

The defaults above can be capped by settings outside the package:

  • PHP upload limits. PHP's stock upload_max_filesize is 2M and post_max_size is 8M. Raise both above max_file_size (10 MB by default), or larger documents fail before Smart Fill sees them.
  • Livewire's temporary upload rule. Livewire validates every temporary upload with max:12288 (12 MB) unless you set temporary_file_upload.rules in config/livewire.php. A max_file_size above 12 MB has no effect until you do.
  • Web server timeouts. Keep timeout (60 seconds by default) below your web server and proxy timeouts (for nginx, fastcgi_read_timeout or proxy_read_timeout, also 60 seconds by default). Otherwise a slow provider ends in a gateway timeout instead of Smart Fill's own message.
  • Rate limiting. Filament's rateLimit() on the action only limits Apply. Reading the document happens on the wizard's Next, so it does not limit calls to your AI provider.

Supported fields

Field What the model returns Notes
TextInput (text, email, url, tel) text The field's maxLength and input type are sent to the model.
TextInput with numeric() or integer() number or integer
Textarea, MarkdownEditor text
DatePicker ISO 8601 date Anything that is not ISO 8601 is dropped. Written in the picker's own format.
DateTimePicker ISO 8601 date and time As above.
Toggle, Checkbox true or false
Select, Radio, ToggleButtons with options the key of one option The model sees key = label pairs and can match either.
Select with multiple(), CheckboxList a list of option keys
TagsInput a list of tags
Select with relationship() a name from the document Resolved to a record, see below.

Relationship selects

The model returns the name as it is written in the document. Smart Fill then looks it up through the select's own query, so modifyQueryUsing(), scopes and tenancy all apply, and the user is never offered a record they could not pick by hand.

  • One exact match fills the field.
  • Several matches show a Choose a match select in the review, with up to five candidates. The row stays unticked until the user picks one.
  • No match lists the name under Not found. Nothing is created.

What is skipped

These are listed under Skipped in the review so the user knows they were not touched:

  • TimePicker
  • Repeater and Builder, and everything inside them
  • KeyValue, RichEditor and FileUpload
  • a Select or option field with no options to choose from (for example, one fed only by getSearchResultsUsing() without a relationship)

Hidden fields, disabled fields, read-only fields, password inputs, Hidden fields and fields marked smartFill(false) are never sent to the model and are not listed.

Providers

The document goes to the provider as an attachment. What the provider accepts depends on its gateway in laravel/ai, so check this table against the version you have installed (verified against laravel/ai 1.2.0).

Provider PDF documents Images
OpenAI, Anthropic, Gemini, Mistral, xAI, OpenRouter yes yes
Ollama, Groq, DeepSeek, openai-compatible no yes

A text file is sent the same way as a PDF, as a document, so it follows the PDF column.

When the provider cannot read the attachment, the user sees: "Your AI provider can't read this file type. Upload an image or paste the text instead." Pasted text works with every provider.

Whether a given model can read a document is up to the model, not the gateway. Pick a vision-capable model for images and scans.

Local servers (Ollama and openai-compatible) do not need an API key. For every other provider, a blank key shows "Smart fill isn't configured yet: set an AI provider in config/ai.php."

Testing in your app

Smart Fill uses a named agent, so laravel/ai's fakes work:

use YousefAman\FilamentSmartFill\Extraction\SmartFillAgent;

SmartFillAgent::fake([['number' => 'INV-1']])->preventStrayPrompts();

The keys are the form-relative state paths of the fields, with each dot written as a double underscore (address.city becomes address__city). A test then calls the action as it would any Filament action, and no request leaves your machine.

Security and privacy

  • The document goes to your AI provider. Smart Fill sends the uploaded file or pasted text, plus the labels and options of the fields it is filling, to the provider you configured. Do not use it with documents your provider is not allowed to see. Some providers store requests by default; for OpenAI, set OPENAI_STORE=false to turn that off.
  • Hidden, disabled, read-only and password fields are never filled. They are not sent to the model either, and every field is checked again right before its value is written.
  • Nothing is saved without the user. Apply writes into the open form. The record changes only when the user clicks Save.
  • Proposals stay on the server. The review is kept in your cache under a random token for review_ttl seconds, and the token works only in the session that created it. The browser only holds the token, and an applied value must be one of the stored proposals (a relationship choice must be one of the offered candidates).
  • Uploads are checked and deleted. The upload accepts only the configured types, checked against the file's real MIME type, and the configured maximum size. The file is deleted right after extraction, also when extraction fails. Livewire keeps its own small metadata file for a temporary upload until its routine cleanup of temporary files runs.
  • The document is treated as data. Pasted text is sent between <document> tags, and the agent is told to treat the whole document as data and ignore instructions written inside it. This lowers the risk of prompt injection but cannot remove it, which is one more reason the user reviews every value.

Translations

Smart Fill ships in every language Filament ships (64 locales), so the action follows your panel's locale:

am ar az bg bn bs ca ckb cs da de el en es et eu fa fi fil fr he hi hr hu hy id it ja ka km ko ku lt lus lv mk mn ms my nb ne nl pl pt pt_BR ro ru sk sl sq sr_Cyrl sr_Latn sv sw tg th tr uk ur uz vi zh_CN zh_HK zh_TW

English and Arabic were written by hand. The other languages were machine-translated, reusing Filament's own wording for shared terms. If a string reads wrong in your language, a pull request to resources/lang/{locale}/smart-fill.php is very welcome.

Publish them to change any string:

php artisan vendor:publish --tag="filament-smart-fill-translations"

Changelog

Please see CHANGELOG for what has changed recently.

Contributing

Issues and pull requests are welcome. Run the tests with:

composer test

Security Vulnerabilities

Please do not report security vulnerabilities through public GitHub issues. Report them privately through GitHub's private vulnerability reporting instead. See SECURITY.md for details.

Credits

License

The MIT License (MIT). Please see License File for more information.