Initial commit: Animexe Laravel platform
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Anime;
|
||||
use App\Models\BlogPost;
|
||||
use App\Services\DeepSeekService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class BlogController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
{
|
||||
$q = $request->get('q');
|
||||
$posts = BlogPost::with('anime')
|
||||
->when($q, fn($query) => $query->where('title', 'like', "%{$q}%"))
|
||||
->orderByDesc('created_at')
|
||||
->paginate(20);
|
||||
|
||||
$stats = [
|
||||
'total' => BlogPost::count(),
|
||||
'published' => BlogPost::where('status', 'published')->count(),
|
||||
'draft' => BlogPost::where('status', 'draft')->count(),
|
||||
'ai' => BlogPost::where('ai_generated', true)->count(),
|
||||
];
|
||||
|
||||
return view('admin.blog.index', compact('posts', 'stats', 'q'));
|
||||
}
|
||||
|
||||
public function create()
|
||||
{
|
||||
$animes = Anime::where('is_published', true)->orderBy('title')->get(['id', 'title']);
|
||||
$post = new BlogPost();
|
||||
return view('admin.blog.edit', compact('post', 'animes'));
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$data = $this->validated($request);
|
||||
$data['slug'] = BlogPost::generateSlug($data['title']);
|
||||
$data['published_at'] = $data['status'] === 'published' ? now() : null;
|
||||
BlogPost::create($data);
|
||||
return redirect()->route('admin.blog.index')->with('success', 'Blog yazısı oluşturuldu.');
|
||||
}
|
||||
|
||||
public function edit(BlogPost $blog)
|
||||
{
|
||||
$animes = Anime::where('is_published', true)->orderBy('title')->get(['id', 'title']);
|
||||
return view('admin.blog.edit', compact('blog', 'animes'));
|
||||
}
|
||||
|
||||
public function update(Request $request, BlogPost $blog)
|
||||
{
|
||||
$data = $this->validated($request);
|
||||
if ($data['status'] === 'published' && !$blog->published_at) {
|
||||
$data['published_at'] = now();
|
||||
}
|
||||
$blog->update($data);
|
||||
return redirect()->route('admin.blog.index')->with('success', 'Blog yazısı güncellendi.');
|
||||
}
|
||||
|
||||
public function destroy(BlogPost $blog)
|
||||
{
|
||||
$blog->delete();
|
||||
return redirect()->route('admin.blog.index')->with('success', 'Blog yazısı silindi.');
|
||||
}
|
||||
|
||||
public function generateAi(Request $request, DeepSeekService $deepseek)
|
||||
{
|
||||
$request->validate(['anime_id' => 'required|exists:animes,id']);
|
||||
|
||||
if (!$deepseek->isConfigured()) {
|
||||
return response()->json(['error' => 'DeepSeek API anahtarı ayarlanmamış. Admin > Ayarlar > deepseek_api_key'], 422);
|
||||
}
|
||||
|
||||
set_time_limit(120);
|
||||
|
||||
$anime = Anime::with('genres')->findOrFail($request->anime_id);
|
||||
$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'])) {
|
||||
return response()->json(['error' => 'AI içerik üretemedi: ' . $deepseek->lastError], 422);
|
||||
}
|
||||
|
||||
$content = preg_replace_callback(
|
||||
'/\[LINK:([^\]]+)\]([^\[]*)\[\/LINK\]/',
|
||||
function ($m) {
|
||||
$slug = trim($m[1]);
|
||||
$label = trim($m[2]);
|
||||
try {
|
||||
return '<a href="' . route('anime.show', $slug) . '">' . $label . '</a>';
|
||||
} catch (\Exception $e) {
|
||||
return $label;
|
||||
}
|
||||
},
|
||||
$data['content']
|
||||
);
|
||||
|
||||
$linkedIds = [];
|
||||
if (!empty($data['linked_slugs'])) {
|
||||
$linkedIds = Anime::whereIn('slug', $data['linked_slugs'])->pluck('id')->toArray();
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'title' => $data['title'] ?? '',
|
||||
'excerpt' => $data['excerpt'] ?? '',
|
||||
'content' => $content,
|
||||
'focus_keyword' => $data['focus_keyword'] ?? $anime->title,
|
||||
'meta_description' => $data['meta_description'] ?? '',
|
||||
'faq' => $data['faq'] ?? [],
|
||||
'linked_anime_ids' => $linkedIds,
|
||||
]);
|
||||
}
|
||||
|
||||
public function bulkGenerate(Request $request)
|
||||
{
|
||||
$count = min(5, (int) $request->get('count', 3));
|
||||
set_time_limit(300);
|
||||
try {
|
||||
\Artisan::call('animexe:generate-blogs', ['--count' => $count, '--force' => false]);
|
||||
$output = \Artisan::output();
|
||||
return redirect()->route('admin.blog.index')->with('success', 'AI blog üretimi tamamlandı: ' . trim($output));
|
||||
} catch (\Throwable $e) {
|
||||
return redirect()->route('admin.blog.index')->with('error', 'Hata: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function validated(Request $request): array
|
||||
{
|
||||
return $request->validate([
|
||||
'title' => 'required|string|max:255',
|
||||
'excerpt' => 'nullable|string',
|
||||
'content' => 'nullable|string',
|
||||
'cover_image' => 'nullable|string|max:500',
|
||||
'focus_keyword' => 'nullable|string|max:255',
|
||||
'meta_title' => 'nullable|string|max:255',
|
||||
'meta_description' => 'nullable|string',
|
||||
'meta_keywords' => 'nullable|string',
|
||||
'status' => 'required|in:draft,published',
|
||||
'anime_id' => 'nullable|exists:animes,id',
|
||||
'reading_time' => 'nullable|integer|min:1|max:60',
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user