lanos / laravel-bfl
Laravel wrapper for Black Forest Labs FLUX API - AI-powered image generation and fine-tuning services
Requires
- php: ^8.1
- ext-zip: *
- illuminate/contracts: ^10.0|^11.0
- illuminate/database: ^10.0|^11.0
- illuminate/filesystem: ^10.0|^11.0
- illuminate/queue: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
- lanos/php-bfl: ^1.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.0
README
A professional Laravel wrapper for Black Forest Labs' FLUX API, providing seamless integration for AI-powered image generation and fine-tuning services.
Features
- Multiple Processing Modes: Manual, synchronous, and queue-based job processing
- Complete Model Support: All FLUX models (Pro, Dev, Ultra, Fill, Expand, Canny, Depth, Kontext)
- Fine-tuning Support: Create and manage fine-tuned models with dedicated service
- File Storage Integration: Automatic file downloading and storage with configurable drivers
- Job Tracking: Complete job lifecycle management with database persistence
- Queue Integration: Built-in Laravel queue job for background processing
- Facade Support: Convenient facades for BFL and fine-tuning operations
- Comprehensive Testing: Full test coverage with PHPUnit
- Type-Safe: Full PHP 8.1+ type hints and strict types
Installation
Install the package via Composer:
composer require lanos/laravel-bfl
Publish and Run Migrations
Publish the migration and config files:
php artisan vendor:publish --provider="Lanos\LaravelBFL\BFLServiceProvider"
Or publish them separately:
# Publish only the config php artisan vendor:publish --tag="bfl-config" # Publish only migrations php artisan vendor:publish --tag="bfl-migrations"
Run the migrations:
php artisan migrate
Environment Configuration
Add your BFL API key to your .env
file:
BFL_API_KEY=your-black-forest-labs-api-key BFL_STORE_FILES=true BFL_STORAGE_DISK=local BFL_STORAGE_PATH_PREFIX=generated-bfl-images
Configuration
The package publishes a configuration file to config/bfl.php
. Key configuration options:
return [ 'api_key' => env('BFL_API_KEY'), 'storage' => [ 'store_files' => env('BFL_STORE_FILES', true), 'disk' => env('BFL_STORAGE_DISK', 'local'), 'path_prefix' => env('BFL_STORAGE_PATH_PREFIX', 'generated-bfl-images'), 'public' => env('BFL_STORAGE_PUBLIC', false), ], 'jobs' => [ 'queue_connection' => env('BFL_QUEUE_CONNECTION', 'default'), 'queue_name' => env('BFL_QUEUE_NAME', 'default'), 'polling' => [ 'max_attempts' => env('BFL_POLLING_MAX_ATTEMPTS', 120), 'delay_seconds' => env('BFL_POLLING_DELAY_SECONDS', 3), ], 'cleanup_after_days' => env('BFL_CLEANUP_AFTER_DAYS', 30), ], ];
Basic Usage
The package provides three different processing modes:
1. Manual Mode
Create a job and manually check its status:
use Lanos\LaravelBFL\Facades\BFL; use Lanos\LaravelBFL\Models\BFLJob; // Create a manual job $job = BFL::createManualJob( BFLJob::MODEL_FLUX_1_PRO, 'A majestic dragon soaring through clouds at sunset', [ 'width' => 1024, 'height' => 768, 'steps' => 50, 'guidance' => 3.5, ], ['user_request_id' => 'req_123'], // metadata auth()->user() // optional user association ); // Later, check the job status $updatedJob = BFL::checkJobStatus($job); if ($updatedJob->isCompleted()) { echo "Job completed! Files stored at: "; foreach ($updatedJob->file_paths ?? [] as $path) { echo BFL::getFileUrl($path) . "\n"; } } elseif ($updatedJob->isFailed()) { echo "Job failed: " . $updatedJob->error_message; }
2. Synchronous Mode
Create a job and wait for completion:
// This will block until completion or timeout $job = BFL::createSyncJob( BFLJob::MODEL_FLUX_1_PRO, 'A beautiful sunset over mountains', [ 'aspect_ratio' => '16:9', 'steps' => 28, 'safety_tolerance' => 2, ] ); // Job is automatically completed when this returns if ($job->isCompleted()) { echo "Generated image result: " . json_encode($job->result); }
3. Queue Mode
Create a job that processes in the background:
// Dispatch to queue for background processing $job = BFL::createQueueJob( BFLJob::MODEL_FLUX_11_PRO_ULTRA, 'An abstract artistic composition with vibrant colors', [ 'aspect_ratio' => '1:1', 'raw' => false, ], [], // metadata auth()->user(), // user 'redis', // queue connection (optional) 'images' // queue name (optional) ); echo "Job queued with ID: {$job->id}"; // Check status later $job->refresh(); if ($job->isCompleted()) { // Handle completion }
Available Models
// Generation models BFLJob::MODEL_FLUX_1_PRO // 'flux-1-pro' BFLJob::MODEL_FLUX_1_DEV // 'flux-1-dev' BFLJob::MODEL_FLUX_11_PRO // 'flux-1.1-pro' BFLJob::MODEL_FLUX_11_PRO_ULTRA // 'flux-1.1-pro-ultra' // Editing models BFLJob::MODEL_FLUX_1_FILL // 'flux-1-fill' BFLJob::MODEL_FLUX_1_EXPAND // 'flux-1-expand' BFLJob::MODEL_FLUX_1_CANNY // 'flux-1-canny' BFLJob::MODEL_FLUX_1_DEPTH // 'flux-1-depth' // Context models BFLJob::MODEL_FLUX_KONTEXT_PRO // 'flux-kontext-pro' BFLJob::MODEL_FLUX_KONTEXT_MAX // 'flux-kontext-max'
Common Parameters
$parameters = [ // Dimensions 'width' => 1024, 'height' => 768, 'aspect_ratio' => '16:9', // Alternative to width/height // Generation settings 'steps' => 50, // Denoising steps 'guidance' => 3.5, // How closely to follow prompt 'seed' => 42, // For reproducible results 'safety_tolerance' => 2, // Content filtering (0=strict, 6=lenient) 'output_format' => 'png', // 'png' or 'jpeg' // Advanced options 'image_prompt' => base64_encode(file_get_contents('reference.jpg')), 'prompt_upsampling' => true, // Webhooks 'webhook_url' => 'https://your-site.com/webhooks/bfl', 'webhook_secret' => 'your-webhook-secret', ];
Model-Specific Parameters
Fill/Inpainting models:
$parameters = [ 'image' => base64_encode(file_get_contents('input.jpg')), 'mask' => base64_encode(file_get_contents('mask.png')), // Optional ];
Expand models:
$parameters = [ 'image' => base64_encode(file_get_contents('input.jpg')), 'top' => 100, // Pixels to add 'bottom' => 100, 'left' => 50, 'right' => 50, ];
Control models (Canny/Depth):
$parameters = [ 'control_image' => base64_encode(file_get_contents('control.jpg')), 'canny_low_threshold' => 50, // For Canny model 'canny_high_threshold' => 200, ];
Fine-tuning
The package provides comprehensive fine-tuning support through the BFLFinetune
facade:
Creating Fine-tunes
use Lanos\LaravelBFL\Facades\BFLFinetune; use Lanos\LaravelBFL\Enums\FinetuneMode; // Create from file paths (automatically zips and encodes) $finetune = BFLFinetune::create([ 'files' => [ '/path/to/image1.jpg', '/path/to/image2.jpg', '/path/to/image3.jpg', ], 'finetune_comment' => 'My custom style training', 'mode' => FinetuneMode::STYLE, // or 'style' as string 'trigger_word' => 'MYSTYLE', 'iterations' => 500, ]); // Or create from pre-encoded ZIP $finetune = BFLFinetune::create([ 'file_data' => base64_encode(file_get_contents('training_data.zip')), 'finetune_comment' => 'Character fine-tune', 'mode' => 'character', 'trigger_word' => 'MYCHAR', 'iterations' => 800, ]);
Managing Fine-tunes
// Get finetune details $details = BFLFinetune::getDetails('ft-123'); // List your finetunes $finetunes = BFLFinetune::listMyFinetunes(); // Delete a finetune $result = BFLFinetune::delete('ft-123');
Generating with Fine-tuned Models
// Generate with fine-tuned Pro $job = BFLFinetune::generateWithFinetunedPro( 'ft-123', 'A beautiful sunset in MYSTYLE', ['width' => 1024, 'height' => 768] ); // Generate with fine-tuned Ultra $job = BFLFinetune::generateWithFinetunedUltra( 'ft-123', 'Portrait in MYSTYLE', ['raw' => true] ); // Generate with fine-tuned control models $job = BFLFinetune::generateWithFinetunedCanny( 'ft-123', 'Landscape in MYSTYLE', base64_encode(file_get_contents('control.jpg')) );
Job Status and Management
Status Checking
$job = BFLJob::find(1); // Status checks $job->isPending(); // Job created but not started $job->isProcessing(); // Job is currently running $job->isCompleted(); // Job finished successfully $job->isFailed(); // Job failed $job->isFinished(); // Job is in any terminal state // Progress tracking echo "Progress: {$job->progress}%"; echo "Started: {$job->started_at}"; echo "Completed: {$job->completed_at}";
User Association
// Create job for specific user $job = BFL::createManualJob( BFLJob::MODEL_FLUX_1_PRO, 'User generated image', [], [], User::find(1) ); // Get user's jobs $userJobs = BFL::getUserJobs(auth()->user(), [ 'status' => BFLJob::STATUS_COMPLETED, 'model_type' => BFLJob::MODEL_FLUX_1_PRO, ]);
Queue Configuration
Queue Settings
Configure queue processing in config/bfl.php
:
'jobs' => [ 'queue_connection' => 'redis', 'queue_name' => 'bfl-jobs', 'polling' => [ 'max_attempts' => 120, // Maximum poll attempts 'delay_seconds' => 3, // Delay between polls ], ],
Running Queue Workers
# Start worker for BFL jobs php artisan queue:work --queue=bfl-jobs # With specific connection php artisan queue:work redis --queue=bfl-jobs
File Storage
Generated images are automatically downloaded and stored when store_files
is enabled:
// Access stored files $job = BFLJob::find(1); $filePaths = $job->file_paths; // Array of stored file paths // Get public URLs foreach ($filePaths as $path) { echo BFL::getFileUrl($path); }
Custom Storage Configuration
// Use S3 or other disks 'storage' => [ 'disk' => 's3', 'public' => true, ],
Utility Methods
Cleanup
// Clean up old jobs (respects cleanup_after_days config) $deletedCount = BFL::cleanupOldJobs();
Direct Client Access
// Access underlying FLUX client for advanced usage $client = BFL::getClient(); $config = BFL::getConfig();
Testing
Run the package test suite:
composer test
Testing in Your Application
use Lanos\LaravelBFL\Services\BFLService; use Lanos\LaravelBFL\Models\BFLJob; public function test_image_generation() { $mockService = $this->mock(BFLService::class); $mockJob = new BFLJob([ 'bfl_task_id' => 'test-task', 'status' => BFLJob::STATUS_COMPLETED, ]); $mockService->allows('createManualJob') ->andReturn($mockJob); // Test your application logic }
API Reference
BFL Facade Methods
// Job creation BFL::createManualJob(string $modelType, string $prompt, array $parameters = [], array $metadata = [], ?object $user = null): BFLJob BFL::createSyncJob(string $modelType, string $prompt, array $parameters = [], array $metadata = [], ?object $user = null): BFLJob BFL::createQueueJob(string $modelType, string $prompt, array $parameters = [], array $metadata = [], ?object $user = null, ?string $queueConnection = null, ?string $queueName = null): BFLJob // Job management BFL::checkJobStatus(BFLJob $job): BFLJob BFL::completeJob(BFLJob $job, GetResultResponse $result): BFLJob // Utility methods BFL::getStorageDisk(): \Illuminate\Contracts\Filesystem\Filesystem BFL::getFileUrl(string $filePath): string BFL::cleanupOldJobs(): int BFL::getUserJobs(object $user, array $filters = []): \Illuminate\Database\Eloquent\Collection BFL::getClient(): \Lanos\PHPBFL\FluxClient BFL::getConfig(): array
BFLFinetune Facade Methods
// Finetune management BFLFinetune::create(array $params): array BFLFinetune::getDetails(string $finetuneId): array BFLFinetune::listMyFinetunes(): array BFLFinetune::delete(string $finetuneId): array // Generation with finetuned models BFLFinetune::generateWithFinetunedPro(string $finetuneId, string $prompt, array $parameters = [], array $metadata = [], ?object $user = null): BFLJob BFLFinetune::generateWithFinetunedUltra(string $finetuneId, string $prompt, array $parameters = [], array $metadata = [], ?object $user = null): BFLJob BFLFinetune::generateWithFinetunedDepth(string $finetuneId, string $prompt, string $controlImage, array $parameters = [], array $metadata = [], ?object $user = null): BFLJob BFLFinetune::generateWithFinetunedCanny(string $finetuneId, string $prompt, string $controlImage, array $parameters = [], array $metadata = [], ?object $user = null): BFLJob BFLFinetune::generateWithFinetunedFill(string $finetuneId, string $image, array $parameters = [], array $metadata = [], ?object $user = null): BFLJob
Job Model Methods
// Status checks $job->isPending(): bool $job->isProcessing(): bool $job->isCompleted(): bool $job->isFailed(): bool $job->isFinished(): bool // Status updates $job->markAsProcessing(): self $job->markAsCompleted(?array $result = null, ?array $filePaths = null): self $job->markAsFailed(?string $errorMessage = null): self $job->updateProgress(float $progress): self
Contributing
We welcome contributions! Please ensure all tests pass and follow PSR-12 coding standards.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.
Changelog
Please see CHANGELOG.md for more information on what has changed recently.