cjmellor/fal-ai-laravel
最新稳定版本:v1.2.0
Composer 安装命令:
composer require cjmellor/fal-ai-laravel
包简介
A Laravel SDK for Fal.ai
README 文档
README
Fal.ai Laravel Package
A Laravel package for integrating with the Fal.ai API, providing a fluent interface for AI model interactions with built-in webhook support.
✨ Features
- 🚀 Fluent API - Chainable methods for easy request building
- 🔗 Webhook Support - Secure webhook handling with ED25519 signature verification
- ⚡ Queue & Sync Modes - Support for both immediate and queued requests
- 📡 Real-time Streaming - Server-Sent Events (SSE) support for progressive AI model responses
- 💰 Platform API - Access pricing, cost estimation, usage tracking, and analytics for models
- 🛡️ Security - Built-in webhook verification middleware
- 🧪 Well Tested - Comprehensive test suite
- 📝 Laravel Integration - Native Laravel middleware and service provider
- 🛣️ Built-in Routes - Pre-configured webhook endpoints ready to use
📦 Installation
Install the package via Composer:
composer require fal-ai/laravel
Publish the configuration file:
php artisan vendor:publish --provider="FalAi\FalAiServiceProvider"
Add your Fal.ai API key to your .env file:
FAL_API_KEY=your_fal_api_key_here
🚀 Basic Usage
🎯 Simple Request
use FalAi\FalAi; $falAi = new FalAi(); $response = $falAi->model('fal-ai/flux/schnell') ->prompt('A beautiful sunset over mountains') ->imageSize('landscape_4_3') ->run();
⚡ Queue vs Sync Modes
Tip
Queue mode is the default and recommended for most use cases. It's perfect for complex generations that take time to process.
📋 Queue Mode (Default)
$response = $falAi->model('fal-ai/flux/dev') ->prompt('A futuristic cityscape') ->queue() // Explicit queue mode (optional, it's the default) ->run(); // Returns: ['request_id' => 'req_123...', 'status' => 'IN_QUEUE']
Use queue mode when:
- Generating high-quality images with many inference steps
- Processing multiple images in batch
- You don't need immediate results
- Working with complex prompts or large image sizes
⚡ Sync Mode
$response = $falAi->model('fal-ai/flux/schnell') ->prompt('A beautiful landscape') ->sync() // Switch to sync mode ->run(); // Returns the complete result immediately
Use sync mode when:
- You need immediate results
- Generating simple images with few inference steps
- Building interactive applications
- Testing and development
Warning
Sync mode may timeout for complex requests. Use queue mode for production applications.
🛰️ Polling Request Status
You can poll the status of a queued request (useful when not using webhooks). Set includeLogs to true to retrieve execution logs.
use Cjmellor\FalAi\Facades\FalAi; $status = FalAi::status('req_123456789', includeLogs: true); if ($status->isInProgress()) { $logs = $status->getLogs(); }
📦 Fetching Results by ID
Fetch the final result payload for a completed request and use convenient accessors.
use Cjmellor\FalAi\Facades\FalAi; $result = FalAi::result('req_123456789'); $firstImageUrl = $result->firstImageUrl; // Convenience accessor $all = $result->json(); // Raw payload if you prefer
⛔ Cancelling a Queued Request
Cancel a queued request that hasn’t started processing yet.
use Cjmellor\FalAi\Facades\FalAi; FalAi::cancel('req_123456789', modelId: 'fal-ai/flux/schnell');
🧭 Submit Response Helpers
Access useful URLs directly from the initial submit response.
use Cjmellor\FalAi\Facades\FalAi; $response = FalAi::model('fal-ai/flux/schnell') ->prompt('A photorealistic fox in a forest') ->queue() ->run(); $requestId = $response->getRequestId(); $statusUrl = $response->getStatusUrl(); $cancelUrl = $response->getCancelUrl();
🔗 Webhook Support
📤 Making Requests with Webhooks
When you add a webhook URL to your request, it automatically switches to queue mode:
$response = $falAi->model('fal-ai/flux/schnell') ->withWebhook('https://myapp.com/webhooks/fal') ->prompt('A beautiful sunset over mountains') ->imageSize('landscape_4_3') ->run(); // Returns: ['request_id' => 'req_123...', 'status' => 'IN_QUEUE']
📋 Webhook URL Requirements
- Must be a valid HTTPS URL
- Must be publicly accessible
- Should respond with 2xx status codes
🛠️ Setting Up Webhook Endpoints
You have two options for handling webhooks: use the built-in route or create your own custom endpoint.
🎯 Option 1: Built-in Webhook Route (Easiest)
The package includes a pre-configured webhook route at /webhooks/fal that handles basic webhook processing:
// This route is automatically registered by the package // POST /webhooks/fal // Use it in your requests: $response = $falAi->model('fal-ai/flux/schnell') ->withWebhook(url('/webhooks/fal')) // Uses the built-in route ->prompt('Your prompt here') ->run();
Tip
The built-in route automatically verifies webhooks and returns appropriate responses. Perfect for getting started quickly!
🏭 Option 2: Custom Webhook Endpoint (Recommended for Production)
use FalAi\Middleware\VerifyFalWebhook; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::post('/webhooks/fal', function (Request $request) { $payload = $request->json()->all(); if ($payload['status'] === 'OK') { $images = $payload['data']['images']; // Process successful results foreach ($images as $image) { // Save image URL: $image['url'] } } elseif ($payload['status'] === 'ERROR') { $error = $payload['error']; // Handle error } return response()->json(['status' => 'processed']); })->middleware(VerifyFalWebhook::class);
For production applications, create a custom webhook endpoint with your own processing logic:
use FalAi\Middleware\VerifyFalWebhook; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; Route::post('/webhooks/fal-custom', function (Request $request) { $payload = $request->json()->all(); if ($payload['status'] === 'OK') { $images = $payload['data']['images']; // Process successful results foreach ($images as $image) { // Save image URL: $image['url'] // Custom processing logic here } } elseif ($payload['status'] === 'ERROR') { $error = $payload['error']; // Handle error with custom logic } return response()->json(['status' => 'processed']); })->middleware(VerifyFalWebhook::class);
🔧 Option 3: Manual Verification (Advanced)
For complete control over the verification process:
use FalAi\Services\WebhookVerifier; use FalAi\Exceptions\WebhookVerificationException; Route::post('/webhooks/fal-manual', function (Request $request) { $verifier = new WebhookVerifier(); try { $verifier->verify($request); // Webhook is valid, process payload $payload = $request->json()->all(); return response()->json(['status' => 'verified']); } catch (WebhookVerificationException $e) { return response()->json([ 'error' => 'Unauthorized', 'message' => 'Webhook verification failed' ], 401); } });
📄 Webhook Payload Examples
✅ Successful Completion
{
"request_id": "req_123456789",
"status": "OK",
"data": {
"images": [
{
"url": "https://fal.media/files/generated-image.jpg",
"width": 1024,
"height": 768,
"content_type": "image/jpeg"
}
],
"seed": 12345,
"has_nsfw_concepts": [false],
"prompt": "A beautiful sunset over mountains"
}
}
❌ Error
{
"request_id": "req_123456789",
"status": "ERROR",
"error": {
"type": "ValidationError",
"message": "Invalid prompt provided"
}
}
📡 Streaming
The Fal.ai Laravel package supports real-time streaming responses using Server-Sent Events (SSE). This is particularly useful for AI models that generate content progressively, such as text generation or image creation with intermediate steps.
🎯 Basic Streaming Usage
To use streaming, call the stream() method instead of run() or queue():
use Cjmellor\FalAi\Facades\FalAi; $streamResponse = FalAi::model('fal-ai/flux/schnell') ->prompt('A beautiful sunset over mountains') ->imageSize('landscape_4_3') ->stream(); $streamResponse->getResponse(); }
📊 Streaming vs Regular Requests
| Feature | Regular Request | Streaming Request |
|---|---|---|
| Response Time | Wait for completion | Real-time updates |
| User Experience | Loading spinner | Progress indicators |
| Resource Usage | Lower | Slightly higher |
| Complexity | Simple | Moderate |
| Best For | Simple workflows | Interactive applications |
📝 Important Notes
- Streaming requests always use the
https://fal.runendpoint regardless of configuration - Not all Fal.ai models support streaming - check the model documentation
- Streaming responses cannot be cached like regular responses
- Consider implementing proper error handling for network interruptions
- Use streaming for models that benefit from progressive updates (text generation, multi-step image creation)
⚙️ Configuration
Note
You can customise the package behaviour by publishing and modifying the configuration file.
The configuration file config/fal-ai.php contains the following options:
return [ 'api_key' => env('FAL_API_KEY'), 'base_url' => 'https://queue.fal.run', 'default_model' => '', 'webhook' => [ // JWKS cache TTL in seconds (max 24 hours) 'jwks_cache_ttl' => env('FAL_WEBHOOK_JWKS_CACHE_TTL', 86400), // Timestamp tolerance in seconds (prevents replay attacks) 'timestamp_tolerance' => env('FAL_WEBHOOK_TIMESTAMP_TOLERANCE', 300), // HTTP timeout for JWKS fetching 'verification_timeout' => env('FAL_WEBHOOK_VERIFICATION_TIMEOUT', 10), ], ];
Environment Variables
# Required FAL_API_KEY=your_fal_api_key_here # Optional webhook configuration FAL_WEBHOOK_JWKS_CACHE_TTL=86400 FAL_WEBHOOK_TIMESTAMP_TOLERANCE=300 FAL_WEBHOOK_VERIFICATION_TIMEOUT=10
🎯 Using a Default Model
Set a default model in config and omit the model ID in your calls.
// config/fal-ai.php // 'default_model' => 'fal-ai/flux/schnell' use Cjmellor\FalAi\Facades\FalAi; $response = FalAi::model() ->prompt('A cozy cabin in the woods') ->run();
🌐 Overriding the Base URL
If you need to direct a request to a specific Fal endpoint manually, you can override the base URL for a single call. The fluent builder already switches between queue and sync automatically in most cases.
use Cjmellor\FalAi\Facades\FalAi; $response = FalAi::runWithBaseUrl( ['prompt' => 'A watercolor skyline at dawn'], modelId: 'fal-ai/flux/schnell', baseUrlOverride: 'https://queue.fal.run', webhookUrl: 'https://example.com/webhooks/fal' );
💰 Platform API
The Platform API provides access to pricing information and cost estimation for Fal.ai models. This is separate from the model execution APIs and uses a different endpoint (api.fal.ai).
📊 Get Model Pricing
Retrieve pricing information for one or more model endpoints. Supports up to 50 endpoints per request.
use Cjmellor\FalAi\Facades\FalAi; // Get pricing for multiple endpoints $pricing = FalAi::platform() ->pricing() ->forEndpoints(['fal-ai/flux/dev', 'fal-ai/flux/schnell']) ->get(); // Or add endpoints individually $pricing = FalAi::platform() ->pricing() ->forEndpoint('fal-ai/flux/dev') ->forEndpoint('fal-ai/flux/schnell') ->get(); // Access pricing data $unitPrice = $pricing->getUnitPriceFor('fal-ai/flux/dev'); // 0.025 $priceInfo = $pricing->getPriceFor('fal-ai/flux/dev'); // ['endpoint_id' => 'fal-ai/flux/dev', 'unit_price' => 0.025, 'unit' => 'image', 'currency' => 'USD']
Example Response:
[
'prices' => [
[
'endpoint_id' => 'fal-ai/flux/dev',
'unit_price' => 0.025,
'unit' => 'image',
'currency' => 'USD'
],
[
'endpoint_id' => 'fal-ai/flux/schnell',
'unit_price' => 0.003,
'unit' => 'image',
'currency' => 'USD'
]
],
'has_more' => false,
'next_cursor' => null
]
💵 Estimate Costs
Estimate the cost of API usage before making requests. Supports two estimation modes: historical API price and unit price.
Historical API Price Mode
Estimate costs based on the number of API calls you plan to make.
use Cjmellor\FalAi\Facades\FalAi; $estimate = FalAi::platform() ->estimateCost() ->historicalApiPrice() ->endpoint('fal-ai/flux/dev', callQuantity: 100) ->endpoint('fal-ai/flux/schnell', callQuantity: 50) ->estimate(); echo "Total cost: $" . $estimate->totalCost; // 3.65
Example Response:
[
'estimate_type' => 'historical_api_price',
'total_cost' => 3.65,
'currency' => 'USD'
]
Unit Price Mode
Estimate costs based on the number of billing units (e.g., images, megapixels).
use Cjmellor\FalAi\Facades\FalAi; $estimate = FalAi::platform() ->estimateCost() ->unitPrice() ->endpoint('fal-ai/flux/dev', unitQuantity: 100) ->estimate(); echo "Total cost: $" . $estimate->totalCost; // 2.50
Example Response:
[
'estimate_type' => 'unit_price',
'total_cost' => 2.50,
'currency' => 'USD'
]
Bulk Endpoint Estimation
Set multiple endpoints at once using the endpoints() method:
$estimate = FalAi::platform() ->estimateCost() ->historicalApiPrice() ->endpoints([ 'fal-ai/flux/dev' => ['call_quantity' => 100], 'fal-ai/flux/schnell' => ['call_quantity' => 50], ]) ->estimate();
📊 Get Usage Data
Access detailed usage line items with unit quantities, prices, and costs. Perfect for tracking your API consumption over time.
use Cjmellor\FalAi\Facades\FalAi; // Get usage for specific endpoints $usage = FalAi::platform() ->usage() ->forEndpoints(['fal-ai/flux/dev', 'fal-ai/flux/schnell']) ->get(); // Access usage data $timeSeries = $usage->timeSeries; $totalCost = $usage->getTotalCost(); // Total cost across all endpoints $totalQuantity = $usage->getTotalQuantity(); // Total units consumed
Filter by Date Range
$usage = FalAi::platform() ->usage() ->forEndpoint('fal-ai/flux/dev') ->between('2025-01-01T00:00:00Z', '2025-01-15T00:00:00Z') ->timeframe('day') // Aggregate by: 'minute', 'hour', 'day', 'week', 'month' ->timezone('America/New_York') ->get();
Include Additional Data
$usage = FalAi::platform() ->usage() ->forEndpoint('fal-ai/flux/dev') ->withTimeSeries() // Include time-bucketed data (default) ->withSummary() // Include aggregate summary ->withAuthMethod() // Include auth method breakdown ->get(); // Access summary if included if ($usage->summary) { echo "Total: $" . $usage->summary['total_cost']; }
Get Usage for Specific Endpoint
$usage = FalAi::platform() ->usage() ->forEndpoints(['fal-ai/flux/dev', 'fal-ai/flux/schnell']) ->get(); // Get cost for specific endpoint $devCost = $usage->getTotalCostFor('fal-ai/flux/dev'); $schnellCost = $usage->getTotalCostFor('fal-ai/flux/schnell'); // Get quantity for specific endpoint $devQuantity = $usage->getTotalQuantityFor('fal-ai/flux/dev');
Example Response:
[
'time_series' => [
[
'bucket' => '2025-01-15T00:00:00-05:00',
'results' => [
[
'endpoint_id' => 'fal-ai/flux/dev',
'unit' => 'image',
'quantity' => 10,
'unit_price' => 0.025,
'cost' => 0.25,
'currency' => 'USD',
'auth_method' => 'Production Key'
]
]
]
],
'has_more' => false,
'next_cursor' => null
]
📈 Get Analytics Data
Query time-bucketed metrics for request counts, success/error rates, and latency percentiles. Essential for monitoring API performance.
use Cjmellor\FalAi\Facades\FalAi; // Get analytics for an endpoint (endpoint_id is required) $analytics = FalAi::platform() ->analytics() ->forEndpoint('fal-ai/flux/dev') ->get(); // Access metrics $totalRequests = $analytics->getTotalRequests(); $successRate = $analytics->getSuccessRate(); // Returns percentage (e.g., 95.0)
Include Specific Metrics
$analytics = FalAi::platform() ->analytics() ->forEndpoint('fal-ai/flux/dev') ->withRequestCount() // Total requests ->withSuccessCount() // Successful responses (2xx) ->withErrorCount() // Server errors (5xx) ->withUserErrorCount() // User errors (4xx) ->withP50Duration() // 50th percentile latency ->withP90Duration() // 90th percentile latency ->get();
Convenience Methods
// Include all error metrics $analytics = FalAi::platform() ->analytics() ->forEndpoint('fal-ai/flux/dev') ->withAllErrors() // user_error_count + error_count ->get(); // Include all latency metrics $analytics = FalAi::platform() ->analytics() ->forEndpoint('fal-ai/flux/dev') ->withAllLatencyMetrics() // P50, P75, P90 for both prepare and execution ->get(); // Include everything $analytics = FalAi::platform() ->analytics() ->forEndpoint('fal-ai/flux/dev') ->withAllMetrics() ->get();
Filter by Date Range and Timeframe
$analytics = FalAi::platform() ->analytics() ->forEndpoint('fal-ai/flux/dev') ->between('2025-01-01T00:00:00Z', '2025-01-15T00:00:00Z') ->timeframe('hour') // Aggregate by: 'minute', 'hour', 'day', 'week', 'month' ->timezone('UTC') ->get();
Calculate Success Rates
$analytics = FalAi::platform() ->analytics() ->forEndpoints(['fal-ai/flux/dev', 'fal-ai/flux/schnell']) ->withSuccessCount() ->get(); // Overall success rate $overallRate = $analytics->getSuccessRate(); // e.g., 97.5 // Per-endpoint success rate $devRate = $analytics->getSuccessRateFor('fal-ai/flux/dev'); $schnellRate = $analytics->getSuccessRateFor('fal-ai/flux/schnell'); // Get totals $totalErrors = $analytics->getTotalErrors(); $totalUserErrors = $analytics->getTotalUserErrors();
Example Response:
[
'time_series' => [
[
'bucket' => '2025-01-15T12:00:00-05:00',
'results' => [
[
'endpoint_id' => 'fal-ai/flux/dev',
'request_count' => 1500,
'success_count' => 1450,
'user_error_count' => 40,
'error_count' => 10,
'p50_duration' => 2.5,
'p90_duration' => 4.8
]
]
]
],
'has_more' => false,
'next_cursor' => null
]
🗑️ Delete Request Payloads
Delete IO payloads and associated CDN output files for a specific request. This is useful for cleaning up generated content and freeing storage.
Warning
This action is irreversible. Only output CDN files are deleted; input files may be used by other requests and are preserved.
use Cjmellor\FalAi\Facades\FalAi; $response = FalAi::platform() ->deleteRequestPayloads('req_123456789') ->delete(); // Check if all deletions succeeded if (!$response->hasErrors()) { echo "All files deleted successfully"; } // Access individual results foreach ($response->cdnDeleteResults as $result) { echo $result['link']; // CDN file URL echo $result['exception']; // null or error message }
With Idempotency Key
Use an idempotency key for safe retries. Responses are cached for 10 minutes per unique key.
$response = FalAi::platform() ->deleteRequestPayloads('req_123456789') ->withIdempotencyKey('unique-operation-key') ->delete();
Filtering Results
// Get only successful deletions $successful = $response->getSuccessfulDeletions(); // Get only failed deletions $failed = $response->getFailedDeletions(); // Check if any deletions failed if ($response->hasErrors()) { foreach ($failed as $result) { Log::error("Failed to delete: {$result['link']} - {$result['exception']}"); } }
Example Response:
[
'cdn_delete_results' => [
[
'link' => 'https://v3.fal.media/files/abc123/output.png',
'exception' => null
],
[
'link' => 'https://v3.fal.media/files/def456/output.jpg',
'exception' => 'File not found'
]
]
]
🔗 Fluent API Methods
🛠️ Common Methods
$request = $falAi->model('fal-ai/flux/schnell') ->prompt('Your prompt here') // Set the text prompt ->imageSize('landscape_4_3') // Set image dimensions ->numImages(2) // Number of images to generate ->seed(12345) // Set random seed ->withWebhook('https://...') // Add webhook URL ->queue() // Use queue mode ->sync(); // Use sync mode
🧰 Adding and Inspecting Payload Data
Enrich the request body with with([...]) and dynamic setters. You can also inspect what will be sent.
use Cjmellor\FalAi\Facades\FalAi; $request = FalAi::model('fal-ai/flux/schnell') ->with(['num_images' => 2]) ->imageSize('square_hd') ->prompt('An astronaut riding a horse'); $payload = $request->toArray(); $response = $request->run();
⚠️ Error Handling
Important
Always implement proper error handling in production applications to gracefully handle API failures and webhook verification issues.
use FalAi\Exceptions\WebhookVerificationException; use InvalidArgumentException; try { $response = $falAi->model('fal-ai/flux/schnell') ->withWebhook('https://myapp.com/webhook') ->prompt('Test prompt') ->run(); if (!$response->successful()) { throw new Exception('API request failed: ' . $response->body()); } } catch (InvalidArgumentException $e) { // Invalid webhook URL or other validation errors echo "Validation error: " . $e->getMessage(); } catch (WebhookVerificationException $e) { // Webhook verification failed (in webhook endpoints) echo "Webhook error: " . $e->getMessage(); } catch (Exception $e) { // Other errors (network, API, etc.) echo "Error: " . $e->getMessage(); }
🧪 Testing
Run the test suite:
composer test
🔒 Security
Caution
Webhook security is critical for protecting your application from malicious requests. Always use the provided verification mechanisms.
🔐 Webhook Security
This package implements Fal.ai's webhook verification using:
- ED25519 signature verification using Fal.ai's public keys
- Timestamp validation to prevent replay attacks
- JWKS caching for performance
- Automatic header extraction and validation
💡 Best Practices
Tip
Follow these security practices to ensure your webhook endpoints are secure:
- Always use HTTPS for webhook URLs
- Use the provided middleware for automatic verification
- Validate webhook payloads in your application logic
- Implement proper error handling and logging
- Monitor webhook endpoints for suspicious activity
- Use rate limiting on webhook routes
- Keep your API keys secure and rotate them regularly
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
This package is open-sourced software licensed under the MIT license.
💬 Support
For support, please open an issue on GitHub or contact the maintainers.
统计信息
- 总下载量: 330
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 5
- 点击次数: 1
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-07-26