119 lines
4.0 KiB
PHP
119 lines
4.0 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use Illuminate\Console\Command;
|
|
use App\Models\BlogTopic;
|
|
use App\Models\Blog; // Ensure this model exists and has 'status' column
|
|
use App\Models\User;
|
|
use App\Services\AiBlogService;
|
|
use Illuminate\Support\Str;
|
|
use Carbon\Carbon;
|
|
|
|
class GenerateBlogAssistant extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'blog:generate-assistant {--topic= : Specific topic to generate}';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = 'Generate a new AI blog post draft based on active topics.';
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*/
|
|
public function handle(AiBlogService $aiService)
|
|
{
|
|
\Illuminate\Support\Facades\Log::info('GenerateBlogAssistant triggered. Args: ' . json_encode($_SERVER['argv'] ?? []));
|
|
$this->info('Starting AI Blog Assistant...');
|
|
|
|
// 1. Select Topic
|
|
$topicName = $this->option('topic');
|
|
$topic = null;
|
|
|
|
if ($topicName) {
|
|
$topic = BlogTopic::where('name', $topicName)->first();
|
|
if (!$topic) {
|
|
$this->error("Topic '{$topicName}' not found.");
|
|
return 1;
|
|
}
|
|
} else {
|
|
// Find oldest used active topic
|
|
$topic = BlogTopic::active()
|
|
->orderBy('last_used_at', 'asc') // Nulls first usually, or old dates
|
|
->first();
|
|
}
|
|
|
|
if (!$topic) {
|
|
$this->warn('No active topics found. Please add topics to blog_topics table.');
|
|
return 0;
|
|
}
|
|
|
|
$this->info("Selected Topic: {$topic->name}");
|
|
|
|
// 2. Generate Content
|
|
$this->info('Generating content with Gemini API...');
|
|
try {
|
|
$contentData = $aiService->generateContent($topic->name, $topic->context);
|
|
} catch (\Exception $e) {
|
|
$this->error('Content generation failed: ' . $e->getMessage());
|
|
return 1;
|
|
}
|
|
|
|
if (empty($contentData) || !isset($contentData['title']) || !isset($contentData['content'])) {
|
|
$this->error('Valid content not returned from AI Service.');
|
|
return 1;
|
|
}
|
|
|
|
$this->info('Content generated successfully.');
|
|
|
|
// 3. Generate/Fetch Image
|
|
$this->info('Fetching cover image...');
|
|
$imagePath = null;
|
|
if (isset($contentData['image_prompt'])) {
|
|
$imagePath = $aiService->fetchAndSaveImage($topic->name, $contentData['image_title'] ?? $contentData['image_prompt']); // Pollinations uses prompt
|
|
}
|
|
|
|
if (!$imagePath) {
|
|
$this->warn('Could not fetch image, proceeding without cover image.');
|
|
} else {
|
|
$this->info("Image saved to: {$imagePath}");
|
|
}
|
|
|
|
// 4. Create Draft Blog Post
|
|
$author = User::first(); // Default to first user (Admin)
|
|
|
|
$blog = new Blog();
|
|
$blog->title = $contentData['title'];
|
|
$blog->slug = Str::slug($contentData['title']);
|
|
$blog->content = $contentData['content'];
|
|
$blog->excerpt = $contentData['excerpt'] ?? Str::limit(strip_tags($contentData['content']), 150);
|
|
$blog->meta_title = $contentData['meta_title'] ?? $contentData['title'];
|
|
$blog->meta_description = $contentData['meta_description'] ?? $blog->excerpt;
|
|
$blog->status = 'draft'; // Verification required
|
|
$blog->author_id = $author ? $author->id : 1;
|
|
$blog->featured_image = $imagePath;
|
|
$blog->published_at = null; // Draft
|
|
$blog->tags = $contentData['tags'] ?? [];
|
|
// category_id? We might need to guess or default.
|
|
// For now leave null or set default if exists.
|
|
|
|
$blog->save();
|
|
|
|
// 5. Update Topic Usage
|
|
$topic->last_used_at = Carbon::now();
|
|
$topic->save();
|
|
|
|
$this->info("Blog post '{$blog->title}' created as DRAFT (ID: {$blog->id}).");
|
|
|
|
return 0;
|
|
}
|
|
}
|