Created
March 16, 2025 15:39
-
-
Save garyblankenship/c441de80775c672e9e902d93bb439595 to your computer and use it in GitHub Desktop.
Usage with Laravel and Prism php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment