Skip to content

Create a DALL-E Image Generation API with Laravel: Step-by-Step Guide

In this guide, we'll walk through the process of creating a Laravel API endpoint that generates DALL-E images and stores them in the local filesystem. This functionality can be useful for applications that require AI-generated images on demand, such as content creation tools or chatbots.

Introduction

DALL-E is an AI model developed by OpenAI that can create unique images from text descriptions. Integrating this capability into a Laravel application opens up possibilities for dynamic, AI-powered visual content.

Problem

Many developers find it challenging to incorporate AI image generation capabilities into their Laravel applications. The process involves not only generating the images but also storing them efficiently, providing access to them, and handling potential errors. This article aims to simplify this process by providing a comprehensive guide.

Solution

Let's break down the solution into the following steps:

Step 1: Set Up the OpenAI API

Before we start, you need to obtain an API key from the OpenAI API. Visit the OpenAI website, create an account, and generate an API key.

Once you have your API key, add it to your Laravel environment configuration:

OPENAI_API_KEY=your_api_key_here

Step 2: Create the OpenAIProvider Helper Class

Create a new file called app/AI/Providers/OpenAIProvider.php and add the following code:

php
<?php

namespace App\AI\Providers;

use App\Exceptions\Errors;
use OpenAI;
use Exception;

class OpenAIProvider
{
    const array MODEL_RETRY_TIMES = [3000, 7000, 10000];

    private static function getApiKey(): string
    {
        return config('openai.api_key');
    }

    private static function getClient(): OpenAI\Client
    {
        return OpenAI::client(self::getApiKey());
    }

    public static function images(
        string $prompt,
        int $n = 1,
        string $model = 'dall-e-3',
        string $quality = 'hd',
        string $size = '1792x1024',
        string $style = 'natural',
        string $response_format = 'url',
        ?string $user = null
    ): ?array {
        $urls = [];
        $parameters = [
            'prompt' => $prompt,
            'model' => $model,
            'n' => $n,
            'quality' => $quality,
            'size' => $size,
            'style' => $style,
            'response_format' => $response_format,
        ];

        if ($user !== null) {
            $parameters['user'] = $user;
        }

        try {
            $response = retry(
                times: self::MODEL_RETRY_TIMES,
                callback: function () use ($parameters) {
                    return self::getClient()->images()->create($parameters);
                },
            );

            foreach ($response->data as $data) {
                $urls[] = $data->url;
            }
        } catch (Exception $e) {
            Errors::captureException($e);
        }

        return $urls;
    }
}

This class handles the interaction with the OpenAI API, including retrying the request if necessary and capturing any exceptions that occur.

Step 3: Implement Error Handling

Create a new file called app/Exceptions/Errors.php and add the following code:

php
<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Support\Facades\Log;

use function Sentry\captureException;

class Errors
{
    public static function captureException(Exception $e): void
    {
        captureException($e);

        if (config('app.env') === 'local') {
            Log::error($e);
        }
    }
}

This class captures exceptions and logs them using Sentry error tracking, with additional local logging for development environments.

Step 4: Set Up the Controller

Create a new controller called app/Http/Controllers/ChatbotController.php and add the following code:

php
<?php

namespace App\Http\Controllers;

use App\AI\Providers\OpenAIProvider;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;

class ChatbotController extends Controller
{
    public function v1Dalle(Request $request): JsonResponse
    {
        $v = $request->validate([
            'prompt' => 'required|string',
        ]);

        $chatbot_api_key = config('integrations.chatbot_api_key');
        $incoming_api_key = $request->headers->get('X-Api-Key');

        if ($chatbot_api_key !== $incoming_api_key) {
            return response()->json([
                'error' => 'Unauthorized',
            ], 401);
        }

        $prompt = $v['prompt'];
        $app_url = config('app.url');
        $public_url = null;

        $images = OpenAIProvider::images(
            prompt: $prompt,
        );

        foreach ($images as $image) {
            $image_contents = Http::get($image)->body();

            $filename = 'dalle3/'.uniqid().'.png';
            $public_filename = 'public/'.$filename;

            Storage::put($public_filename, $image_contents);

            $public_url = $app_url.Storage::url($public_filename);
        }

        return response()->json([
            'url' => $public_url,
        ]);
    }
}

This controller handles the incoming request, validates the API key, generates the image using the OpenAIProvider, saves it to the local filesystem using Laravel Storage, and returns the public URL of the saved image.

Step 5: Set Up the Route

Add the following route to your routes/api.php file:

php
Route::post('/v1/dalle', [ChatbotController::class, 'v1Dalle']);

Step 6: Configure API Key

Add the following to your .env file:

CHATBOT_API_KEY=your_chatbot_api_key_here

Then, in config/integrations.php (create this file if it doesn't exist), add:

php
<?php

return [
    'chatbot_api_key' => env('CHATBOT_API_KEY'),
];

Step 7: Refresh the Local Configuration

To ensure the new environment variables are loaded into the application, run the php artisan optimize:clear command. This will execute a couple of actions, one of them is ensuring the new environment varialbles are cached.

Step 8: Testing the Endpoint

You can test the endpoint using a tool like Postman or curl. Send a POST request to /api/v1/dalle with the following headers and body:

Headers:

X-Api-Key: your_chatbot_api_key_here
Content-Type: application/json

Body:

json
{
  "prompt": "A futuristic cityscape with flying cars"
}

The response should contain a URL to the generated image.

Security Considerations

When implementing this API, it's crucial to follow API security best practices:

  1. Always use HTTPS for API requests to protect API keys and other sensitive data.
  2. Store API keys securely in environment variables, never in version control.
  3. Implement rate limiting in Laravel on your endpoint to prevent abuse.

Performance Considerations

To ensure optimal performance of your DALL-E image generation API:

  1. Consider implementing caching for frequently requested images to reduce API calls and storage operations.
  2. Use Laravel queues for image generation tasks if you expect high traffic to prevent blocking the main thread.

Limitations of This Approach

While the solution presented in this guide provides a functional DALL-E image generation API, it's important to be aware of its limitations:

  1. Single Fixed API Key: The example uses a single fixed environment variable (CHATBOT_API_KEY) to authenticate requests. This approach lacks flexibility and may not be suitable for multi-user systems or applications requiring different access levels.

  2. Local File Storage: Images are stored in the local filesystem, which may not be scalable or suitable for distributed systems. In a production environment, you might need to consider using cloud storage solutions like AWS S3 or Google Cloud Storage.

  3. Error Handling: While basic error handling is implemented, it does not cover all possible edge cases or provide detailed error messages to the client.

  4. Fixed Image Parameters: The DALL-E parameters (like size and quality) are hardcoded in this example, feel free to add additional parameters in the request as needed.

  5. Limited Prompt Validation: The example only checks if the prompt is a non-empty string, without any content moderation or length restrictions.

  6. No Usage Tracking: The example doesn't track API usage, which could be important for billing or monitoring purposes.

Conclusion

By following these steps, we've successfully created an API endpoint that generates DALL-E images and stores them in the local filesystem using Laravel.

This endpoint can be easily integrated into existing Laravel applications, allowing for on-demand generation and storage of AI images.

Remember to handle errors gracefully, implement proper security measures, and consider performance optimizations as your application scales.