lanos/laravel-bfl

Laravel wrapper for Black Forest Labs FLUX API - AI-powered image generation and fine-tuning services

v1.0.0 2025-08-24 23:26 UTC

This package is auto-updated.

Last update: 2025-08-24 23:44:12 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

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.