AI Content Generation

Laratic includes AI-powered blog post generation that creates complete posts with titles, descriptions, content, and cover images. The generation runs in a background queue for better performance.

Before using AI content generation, you need to set up Prism and have an OpenAI API key configured. Please see AI Integration for more details.

How it Works

  1. Live wire components gets the text prompt from the prompt input field
  2. Live wire components dispatches a GeneratePostWithAi job to the ai queue
  3. The job will recive the prompt input and adds more details to the prompt to generate a more accurate post
  4. The job generates structured post content (title, description, content) using OpenAI via Prism
  5. The job will generate a cover image using DALL-E 3 via Prism, you can change the model in the job
  6. The job automatically creates a draft post (unpublished by default) with the generated content and saves it
  7. AI usage is tracked and linked to the created post
  8. The Livewire component polls for completion every 8 seconds
  9. Upon completion, the user is automatically redirected to the edit page of the newly created post and the Livewire component is updated to show the post details

Setting Up the Queue

AI generation uses a background queue to handle long-running operations. The job is dispatched to the ai queue, which runs asynchronously.

To start processing the queue, run:

php artisan queue:work --queue=ai

Generating Posts

In the admin post creation form, click the floating AI orb button to open the AI prompt interface. All you need to do is enter a prompt and click the generate button.

The system uses Prism's structured output feature to generate well-formed blog posts:

$schema = new ObjectSchema(
        name: 'blog_post',
        description: 'A structured blog post payload',
        properties: [
            new StringSchema('title', 'Compelling H1 title for the blog post'),
            new StringSchema('description', '1-2 sentence summary/teaser for the post, should be 200 characters or less'),
            new StringSchema('content', 'Full blog post body in well formatted Markdown'),
        ],
        requiredFields: ['title', 'description', 'content']
    );

Image Generation

You need to setup cloudinary to save the generated images. Please see Cloudinary for more details.

The system automatically generates cover images using DALL-E 3. The generation process:

  • Creates a hyper-realistic image based on the post topic
  • $response = Prism::image()
                ->using('openai', 'dall-e-3')
                ->withPrompt('Create a hyper-realistic image for: ' . $userPrompt . '. No text. not too much details. low intensity.')
                ->withProviderOptions([
                    'size' => '1024x1024',
                    'quality' => 'standard',
                    'style' => 'vivid',
                ])
                ->generate();
            
  • Uploads the generated image to Cloudinary for hosting
  •   $uploadResult = Cloudinary::uploadApi()->upload($imageUrl, [
        'resource_type' => 'image',
    ]);
    
  • Retries up to 3 times (you can change this in the job) if the image generation fails
  • Tracks image generation usage separately. You can define the pricing in the ai helpers function
  • $pricing = [
                // Prices are per 1,000,000 tokens in USD
                'gpt-4o-mini' => ['in' => (0.4 / 1000000), 'out' => (1.6 / 1000000)],
                'gpt-4.1-mini' => ['in' => (0.4 / 1000000), 'out' => (1.6 / 1000000)],
                'dall-e-3' => ['in' => 0, 'out' => (0.04 / 1)],
            ];
            

Cache-Based Communication

The system uses Laravel's cache to communicate between the background job and the Livewire component. When generation starts, a unique request ID is created and the job writes status updates to cache keys:

  • post_ai:{requestId}:done - Set to true when generation completes
  • post_ai:{requestId}:result - Contains post_id on success
  • post_ai:{requestId}:error - Contains error message on failure

The Livewire component polls these cache keys every 8 seconds using wire:poll.8s. When done is detected, it reads the result or error, shows a notification, and redirects to the edit page. All cache entries expire after 20 minutes.

You can clear these cache entries manually using:

php artisan cache:clear

Usage Tracking

AI generation automatically tracks usage:

  • Text generation tokens (prompt + output)
  • Image generation (counted as 1 image generation)
  • Linked to the created post via ai_usage_post pivot table
  • Stored in ai_usages table with cost calculation

Read Next