gary.info

here be dragons

Usage with Laravel and Prism php

prism-laravel-example.php
<?php

namespace App\Data;

final readonly class ProductGenerationData extends BaseData
{
    public function __construct(
        public string $title,
        public string $description,
        public array $features,
        public string $metaDescription,
        public array $seoKeywords,
        public string $callToAction,
    ) {}
    
    public static function fromResponse(array $response): self
    {
        return new self(
            title: $response['title'],
            description: $response['description'],
            features: $response['features'],
            metaDescription: $response['metaDescription'],
            seoKeywords: $response['seoKeywords'],
            callToAction: $response['callToAction'],
        );
    }
}

// AI service implementation with Filament integration
namespace App\Filament\Resources\ProductResource\Pages;

use App\Filament\Resources\ProductResource;
use App\Services\ProductAIService;
use Filament\Actions\Action;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Support\HtmlString;

class EditProduct extends EditRecord
{
    protected static string $resource = ProductResource::class;

    protected function getHeaderActions(): array
    {
        return [
            Action::make('generateContent')
                ->label('Generate with AI')
                ->modalHeading('Generate Product Content')
                ->modalDescription('Use AI to generate product content based on the current information.')
                ->modalSubmitActionLabel('Generate')
                ->form([
                    Select::make('tone')
                        ->label('Content Tone')
                        ->options([
                            'professional' => 'Professional',
                            'casual' => 'Casual',
                            'enthusiastic' => 'Enthusiastic',
                            'technical' => 'Technical',
                        ])
                        ->default('professional')
                        ->required(),
                    Select::make('target_audience')
                        ->label('Target Audience')
                        ->options([
                            'general' => 'General Audience',
                            'technical' => 'Technical Users',
                            'beginners' => 'Beginners',
                            'professionals' => 'Professionals',
                        ])
                        ->default('general')
                        ->required(),
                    Checkbox::make('generate_features')
                        ->label('Generate Features')
                        ->default(true),
                    Checkbox::make('generate_seo')
                        ->label('Generate SEO Content')
                        ->default(true),
                ])
                ->action(function (array $data) {
                    $productData = $this->record->only([
                        'name', 
                        'category', 
                        'price', 
                        'specifications',
                    ]);
                    
                    $aiService = app(ProductAIService::class);
                    
                    $generatedContent = $aiService->generateProductContent(
                        product: $productData,
                        tone: $data['tone'],
                        targetAudience: $data['target_audience'],
                        generateFeatures: $data['generate_features'],
                        generateSeo: $data['generate_seo'],
                    );
                    
                    $this->form->fill([
                        'title' => $generatedContent->title,
                        'description' => $generatedContent->description,
                        'meta_description' => $generatedContent->metaDescription,
                        'seo_keywords' => implode(', ', $generatedContent->seoKeywords),
                    ]);
                    
                    if ($data['generate_features']) {
                        $featuresHtml = '';
                        foreach ($generatedContent->features as $feature) {
                            $featuresHtml .= "- {$feature}\n";
                        }
                        
                        $this->form->fill([
                            'features' => $featuresHtml,
                        ]);
                    }
                    
                    Notification::make()
                        ->title('Content generated')
                        ->body('AI-generated content has been applied to the form.')
                        ->success()
                        ->send();
                }),
        ];
    }
}

// Example of a schema factory method
namespace App\Schemas;

use Prism\Prism\Schema\EnumSchema;
use Prism\Prism\Schema\NumberSchema;
use Prism\Prism\Schema\ObjectSchema;
use Prism\Prism\Schema\StringSchema;
use Prism\Prism\Schema\BooleanSchema;
use Prism\Prism\Schema\ArraySchema;

class ProductSchemas
{
    public static function productContentSchema(): ObjectSchema
    {
        return new ObjectSchema(
            name: 'productContent',
            description: 'Generated content for a product',
            properties: [
                new StringSchema('title', 'Attention-grabbing product title'),
                new StringSchema('description', 'Detailed product description'),
                new ArraySchema(
                    name: 'features',
                    description: 'Key product features',
                    items: new StringSchema('feature', 'A product feature')
                ),
                new StringSchema('metaDescription', 'SEO meta description'),
                new ArraySchema(
                    name: 'seoKeywords',
                    description: 'SEO keywords',
                    items: new StringSchema('keyword', 'An SEO keyword')
                ),
                new StringSchema('callToAction', 'Call to action text'),
            ],
            requiredFields: ['title', 'description', 'features', 'metaDescription', 'seoKeywords', 'callToAction']
        );
    }
    
    public static function productCategorySchema(): ObjectSchema
    {
        return new ObjectSchema(
            name: 'productCategorization',
            description: 'AI-generated product categorization',
            properties: [
                new StringSchema('primaryCategory', 'Primary product category'),
                new ArraySchema(
                    name: 'secondaryCategories',
                    description: 'Secondary categories',
                    items: new StringSchema('category', 'A secondary category')
                ),
                new ArraySchema(
                    name: 'tags',
                    description: 'Product tags',
                    items: new StringSchema('tag', 'A product tag')
                ),
                new NumberSchema(
                    name: 'confidenceScore', 
                    description: 'Confidence score of the categorization between 0 and 100'
                ),
            ],
            requiredFields: ['primaryCategory', 'secondaryCategories', 'tags', 'confidenceScore']
        );
    }
}

// Example product content generation service
namespace App\Services;

use App\Data\ProductGenerationData;
use App\Schemas\ProductSchemas;

class ProductAIService
{
    public function __construct(
        protected AIService $aiService
    ) {}
    
    public function generateProductContent(
        array $product,
        string $tone = 'professional',
        string $targetAudience = 'general',
        bool $generateFeatures = true,
        bool $generateSeo = true
    ): ProductGenerationData {
        $prompt = view('prompts.product-content', [
            'product' => $product,
            'tone' => $tone,
            'targetAudience' => $targetAudience,
            'generateFeatures' => $generateFeatures,
            'generateSeo' => $generateSeo,
        ])->render();
        
        $schema = ProductSchemas::productContentSchema();
        
        $response = $this->aiService
            ->withModel('gpt-4o')
            ->withOptions([
                'temperature' => 0.7,
                'max_tokens' => 1500,
            ])
            ->generateStructured($prompt, $schema);
        
        return ProductGenerationData::fromResponse($response->structured);
    }
    
    public function categorizeProduct(string $description): ProductCategoryData
    {
        $prompt = view('prompts.product-categorization', [
            'description' => $description,
        ])->render();
        
        $schema = ProductSchemas::productCategorySchema();
        
        $response = $this->aiService
            ->withModel('gpt-4o')
            ->generateStructured($prompt, $schema);
        
        return ProductCategoryData::fromResponse($response->structured);
    }
}

// Example Artisan command for bulk product content generation
namespace App\Console\Commands;

use App\Models\Product;
use App\Services\ProductAIService;
use Illuminate\Console\Command;

class GenerateProductContent extends Command
{
    protected $signature = 'products:generate-content 
                            {--category= : Filter by product category}
                            {--tone=professional : Content tone}
                            {--audience=general : Target audience}';
                            
    protected $description = 'Generate AI content for products';

    public function handle(ProductAIService $service)
    {
        $query = Product::query();
        
        if ($category = $this->option('category')) {
            $query->where('category', $category);
        }
        
        $products = $query->whereNull('description')->orWhere('description', '')->get();
        
        if ($products->isEmpty()) {
            $this->info('No products found that need content generation.');
            return 0;
        }
        
        $this->info("Generating content for {$products->count()} products...");
        
        $bar = $this->output->createProgressBar($products->count());
        $bar->start();
        
        $tone = $this->option('tone');
        $audience = $this->option('audience');
        
        foreach ($products as $product) {
            try {
                $productData = $product->only([
                    'name', 
                    'category', 
                    'price', 
                    'specifications',
                ]);
                
                $generatedContent = $service->generateProductContent(
                    product: $productData,
                    tone: $tone,
                    targetAudience: $audience,
                );
                
                $product->update([
                    'title' => $generatedContent->title,
                    'description' => $generatedContent->description,
                    'features' => json_encode($generatedContent->features),
                    'meta_description' => $generatedContent->metaDescription,
                    'seo_keywords' => implode(', ', $generatedContent->seoKeywords),
                ]);
            } catch (\Exception $e) {
                $this->newLine();
                $this->warn("Error generating content for product #{$product->id}: {$e->getMessage()}");
            }
            
            $bar->advance();
        }
        
        $bar->finish();
        $this->newLine(2);
        
        $this->info('Content generation complete!');
        
        return 0;
    }
}

// Blade template example for product content generation
// resources/views/prompts/product-content.blade.php

// You are an expert product copywriter. Generate compelling content for the following product:
// 
// Product Name: {{ $product['name'] }}
// Category: {{ $product['category'] }}
// Price: {{ $product['price'] }}
// Specifications: {{ $product['specifications'] }}
// 
// Content requirements:
// - Tone: {{ $tone }}
// - Target audience: {{ $targetAudience }}
// @if($generateFeatures)- Include 4-6 key product features@endif
// @if($generateSeo)- Include SEO-optimized meta description and keywords@endif
// 
// Generate the following content:
// 1. An attention-grabbing product title
// 2. A detailed product description (150-250 words)
// 3. @if($generateFeatures)A list of key product features@endif
// 4. @if($generateSeo)A meta description (max 155 characters) and SEO keywords@endif
// 5. A compelling call to action
// 
// Format your response in a structured format with the following fields:
// title, description, @if($generateFeatures)features (as an array), @endif
// @if($generateSeo)metaDescription, seoKeywords (as an array), @endif callToAction.