Skip to content

Instantly share code, notes, and snippets.

@garyblankenship
Created March 16, 2025 15:39
Show Gist options
  • Save garyblankenship/c441de80775c672e9e902d93bb439595 to your computer and use it in GitHub Desktop.
Save garyblankenship/c441de80775c672e9e902d93bb439595 to your computer and use it in GitHub Desktop.
Usage with Laravel and Prism 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment