gutendex integration, phase 6
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Jobs\BatchImportFromGutendex;
|
||||
use App\Jobs\GenerateSummary;
|
||||
use App\Models\Book;
|
||||
use App\Models\Summary;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class GutendexController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display the Gutendex admin dashboard.
|
||||
*/
|
||||
public function dashboard()
|
||||
{
|
||||
$stats = $this->getStatistics();
|
||||
$recentImports = $this->getRecentImports();
|
||||
$recentFailures = $this->getRecentFailures();
|
||||
|
||||
return view('admin.gutendex.dashboard', compact('stats', 'recentImports', 'recentFailures'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Display processing status.
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
$stats = $this->getStatistics();
|
||||
$processing = Summary::processing()->with('book')->get();
|
||||
$pending = Summary::pending()->with('book')->limit(20)->get();
|
||||
$failed = Summary::failed()->with('book')->limit(20)->get();
|
||||
|
||||
$queueStats = $this->getQueueStatistics();
|
||||
|
||||
return view('admin.gutendex.status', compact('stats', 'processing', 'pending', 'failed', 'queueStats'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a new import.
|
||||
*/
|
||||
public function import(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'language' => 'required|string|max:10',
|
||||
'limit' => 'required|integer|min:1|max:500',
|
||||
'page' => 'required|integer|min:1',
|
||||
'generate_summaries' => 'boolean',
|
||||
]);
|
||||
|
||||
$language = $request->input('language', 'en');
|
||||
$limit = (int) $request->input('limit', 50);
|
||||
$page = (int) $request->input('page', 1);
|
||||
$generateSummaries = $request->boolean('generate_summaries', true);
|
||||
|
||||
$filters = [
|
||||
'languages' => $language,
|
||||
'copyright' => 'false',
|
||||
];
|
||||
|
||||
// Calculate end page
|
||||
$booksPerPage = 32;
|
||||
$endPage = $page + (int) ceil($limit / $booksPerPage) - 1;
|
||||
|
||||
// Dispatch batch import job
|
||||
BatchImportFromGutendex::dispatch(
|
||||
$filters,
|
||||
$page,
|
||||
$endPage,
|
||||
$limit,
|
||||
$generateSummaries
|
||||
);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => "Import job dispatched for up to {$limit} books",
|
||||
'details' => [
|
||||
'language' => $language,
|
||||
'limit' => $limit,
|
||||
'start_page' => $page,
|
||||
'end_page' => $endPage,
|
||||
'generate_summaries' => $generateSummaries,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry a failed book summary.
|
||||
*/
|
||||
public function retry(Book $book)
|
||||
{
|
||||
if (!$book->summary) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Book does not have a summary record',
|
||||
], 404);
|
||||
}
|
||||
|
||||
if ($book->summary->processing_status === 'completed') {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Summary is already completed',
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Dispatch job to regenerate summary
|
||||
GenerateSummary::dispatch($book->id);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => "Retry job dispatched for: {$book->title}",
|
||||
'book_id' => $book->id,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get overall statistics.
|
||||
*/
|
||||
protected function getStatistics(): array
|
||||
{
|
||||
$totalBooks = Book::count();
|
||||
$gutendexBooks = Book::gutendex()->count();
|
||||
$booksWithText = Book::whereNotNull('full_text_url')->count();
|
||||
$booksWithoutSummaries = Book::gutendex()
|
||||
->whereNotNull('full_text_url')
|
||||
->doesntHave('summary')
|
||||
->count();
|
||||
|
||||
$totalSummaries = Summary::count();
|
||||
$completedSummaries = Summary::completed()->count();
|
||||
$pendingSummaries = Summary::pending()->count();
|
||||
$processingSummaries = Summary::processing()->count();
|
||||
$failedSummaries = Summary::failed()->count();
|
||||
|
||||
$completionRate = $totalSummaries > 0
|
||||
? round(($completedSummaries / $totalSummaries) * 100, 2)
|
||||
: 0;
|
||||
|
||||
return [
|
||||
'total_books' => $totalBooks,
|
||||
'gutendex_books' => $gutendexBooks,
|
||||
'books_with_text' => $booksWithText,
|
||||
'books_without_summaries' => $booksWithoutSummaries,
|
||||
'total_summaries' => $totalSummaries,
|
||||
'completed_summaries' => $completedSummaries,
|
||||
'pending_summaries' => $pendingSummaries,
|
||||
'processing_summaries' => $processingSummaries,
|
||||
'failed_summaries' => $failedSummaries,
|
||||
'completion_rate' => $completionRate,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent imports.
|
||||
*/
|
||||
protected function getRecentImports(int $limit = 10): array
|
||||
{
|
||||
return Book::gutendex()
|
||||
->with('category')
|
||||
->orderByDesc('created_at')
|
||||
->limit($limit)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent failures.
|
||||
*/
|
||||
protected function getRecentFailures(int $limit = 10): array
|
||||
{
|
||||
return Summary::failed()
|
||||
->with('book')
|
||||
->orderByDesc('updated_at')
|
||||
->limit($limit)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get queue statistics.
|
||||
*/
|
||||
protected function getQueueStatistics(): array
|
||||
{
|
||||
try {
|
||||
$pendingJobs = DB::table('jobs')->count();
|
||||
$failedJobs = DB::table('failed_jobs')->count();
|
||||
|
||||
return [
|
||||
'pending_jobs' => $pendingJobs,
|
||||
'failed_jobs' => $failedJobs,
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
return [
|
||||
'pending_jobs' => 0,
|
||||
'failed_jobs' => 0,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user