Initial commit: Animexe Laravel platform
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Anime;
|
||||
use App\Models\BlogPost;
|
||||
use App\Services\DeepSeekService;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class GenerateBlogPosts extends Command
|
||||
{
|
||||
protected $signature = 'animexe:generate-blogs
|
||||
{--count=2 : Kaç blog yazısı üretileceği}
|
||||
{--anime= : Belirli bir anime ID için üret}
|
||||
{--force : Daha önce blog yazılmış animeler için de üret}';
|
||||
|
||||
protected $description = 'DeepSeek AI ile anime blog yazıları üretir';
|
||||
|
||||
public function handle(DeepSeekService $deepseek): int
|
||||
{
|
||||
if (!$deepseek->isConfigured()) {
|
||||
$this->error('DeepSeek API anahtarı ayarlanmamış. Admin > Ayarlar > deepseek_api_key');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$count = (int) $this->option('count');
|
||||
$animeId = $this->option('anime');
|
||||
$force = $this->option('force');
|
||||
|
||||
if ($animeId) {
|
||||
$animes = Anime::where('id', $animeId)->where('is_published', true)->with('genres')->get();
|
||||
} else {
|
||||
$alreadyBlogged = $force ? [] : BlogPost::whereNotNull('anime_id')->pluck('anime_id')->toArray();
|
||||
$animesQuery = Anime::where('is_published', true)
|
||||
->whereNotIn('id', $alreadyBlogged)
|
||||
->with('genres')
|
||||
->orderByDesc('rating')
|
||||
->limit($count * 3)
|
||||
->get();
|
||||
|
||||
$randomResult = $animesQuery->random(min($count, $animesQuery->count()));
|
||||
$animes = collect($randomResult);
|
||||
}
|
||||
|
||||
if ($animes->isEmpty()) {
|
||||
$this->info('Blog yazısı üretilecek anime bulunamadı.');
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$generated = 0;
|
||||
|
||||
foreach ($animes->take($count) as $anime) {
|
||||
$this->info("Blog üretiliyor: {$anime->title}...");
|
||||
|
||||
// Aynı türden ilgili animeler bul
|
||||
$genreIds = $anime->genres->pluck('id');
|
||||
$related = Anime::where('is_published', true)
|
||||
->where('id', '!=', $anime->id)
|
||||
->whereHas('genres', fn($q) => $q->whereIn('genres.id', $genreIds))
|
||||
->orderByDesc('rating')
|
||||
->limit(5)
|
||||
->get(['id', 'title', 'slug'])
|
||||
->map(fn($a) => ['slug' => $a->slug, 'title' => $a->title])
|
||||
->toArray();
|
||||
|
||||
$data = $deepseek->generateBlogPost($anime, $related);
|
||||
|
||||
if (!$data || empty($data['content'])) {
|
||||
$this->warn(" [{$anime->title}] için içerik üretilemedi: " . $deepseek->lastError);
|
||||
continue;
|
||||
}
|
||||
|
||||
// [LINK:slug]Title[/LINK] placeholder'larını gerçek URL'lerle değiştir
|
||||
$content = preg_replace_callback(
|
||||
'/\[LINK:([^\]]+)\]([^\[]*)\[\/LINK\]/',
|
||||
function ($m) {
|
||||
$slug = trim($m[1]);
|
||||
$label = trim($m[2]);
|
||||
try {
|
||||
$url = route('anime.show', $slug);
|
||||
return "<a href=\"{$url}\">{$label}</a>";
|
||||
} catch (\Exception $e) {
|
||||
return $label;
|
||||
}
|
||||
},
|
||||
$data['content'] ?? ''
|
||||
);
|
||||
|
||||
$title = $data['title'] ?? ($anime->title . ' İzle — Animexe Rehberi');
|
||||
$slug = BlogPost::generateSlug($title);
|
||||
|
||||
// Linked anime IDs
|
||||
$linkedIds = [];
|
||||
if (!empty($data['linked_slugs'])) {
|
||||
$linkedIds = Anime::whereIn('slug', $data['linked_slugs'])->pluck('id')->toArray();
|
||||
}
|
||||
|
||||
$readingTime = max(3, (int) (str_word_count(strip_tags($content)) / 200));
|
||||
|
||||
BlogPost::create([
|
||||
'title' => $title,
|
||||
'slug' => $slug,
|
||||
'excerpt' => $data['excerpt'] ?? '',
|
||||
'content' => $content,
|
||||
'cover_image' => $anime->cover_image,
|
||||
'focus_keyword' => $data['focus_keyword'] ?? $anime->title,
|
||||
'meta_title' => $data['title'] ?? null,
|
||||
'meta_description' => $data['meta_description'] ?? $data['excerpt'] ?? '',
|
||||
'meta_keywords' => implode(', ', array_filter([
|
||||
$anime->title,
|
||||
$anime->title . ' izle',
|
||||
'türkçe anime',
|
||||
$data['focus_keyword'] ?? '',
|
||||
])),
|
||||
'status' => 'published',
|
||||
'ai_generated' => true,
|
||||
'anime_id' => $anime->id,
|
||||
'linked_anime_ids' => $linkedIds,
|
||||
'faq' => $data['faq'] ?? [],
|
||||
'reading_time' => $readingTime,
|
||||
'published_at' => now(),
|
||||
]);
|
||||
|
||||
$this->info(" ✓ Blog yazısı oluşturuldu: {$title}");
|
||||
$generated++;
|
||||
|
||||
// API rate limit
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
$this->info("Tamamlandı. {$generated} blog yazısı üretildi.");
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user