Files
newznab-tmux-NNTmux/app/Services/Categorization/CategorizationService.php
T
2026-03-11 10:11:30 +01:00

155 lines
5.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Services\Categorization;
use App\Models\Category;
use App\Services\Categorization\Pipes\AbstractCategorizationPipe;
use Blacklight\Categorize;
/**
* Categorization service using Laravel Pipeline.
*
* This class is a drop-in replacement for the legacy Blacklight\Categorize
* with additional features like confidence scoring and debug information.
*/
class CategorizationService
{
protected CategorizationPipeline $pipeline;
public function __construct(?CategorizationPipeline $pipeline = null)
{
$this->pipeline = $pipeline ?? CategorizationPipeline::createDefault();
}
/**
* Determine category for a release.
*
* @param int|string $groupId The usenet group ID
* @param string $releaseName The name of the release
* @param string|null $poster The poster name
* @param bool $debug Whether to include debug information
* @return array<string, mixed> The categorization result with category ID and optional debug info
*/
public function determineCategory(
int|string $groupId,
string $releaseName = '',
?string $poster = '',
bool $debug = false
): array {
return $this->pipeline->categorize($groupId, $releaseName, $poster, $debug);
}
/**
* Batch categorize multiple releases.
*
* @param array<string, mixed> $releases Array of ['group_id' => x, 'name' => y, 'poster' => z]
* @return array<string, mixed> Array of categorization results
*/
public function batchCategorize(array $releases): array
{
$results = [];
foreach ($releases as $release) {
$groupId = $release['group_id'] ?? $release['groupId'] ?? 0;
$name = $release['name'] ?? $release['releaseName'] ?? '';
$poster = $release['poster'] ?? '';
$results[] = [
'release' => $release,
'result' => $this->determineCategory($groupId, $name, $poster),
];
}
return $results;
}
/**
* Get the underlying pipeline.
*
* @return list<array<string, mixed>>
*/
public function getPipeline(): CategorizationPipeline
{
return $this->pipeline;
}
/**
* Add a custom categorizer pipe to the pipeline.
*/
public function addCategorizer(AbstractCategorizationPipe $pipe): self
{
$this->pipeline->addCategorizer($pipe);
return $this;
}
/**
* Compare pipeline categorization against the legacy Blacklight\Categorize class.
*
* Returns an array with 'pipeline', 'legacy', and 'match' keys so callers
* can verify the new pipeline produces the same results as the old categorizer.
*
* @param int|string $groupId The usenet group ID
* @param string $releaseName The name of the release
* @return array{pipeline: array{category_id: int, category_name: string}, legacy: array{category_id: int, category_name: string}, match: bool}
*/
public function compare(int|string $groupId, string $releaseName): array
{
// Run the new pipeline categorization
$pipelineResult = $this->determineCategory($groupId, $releaseName);
$pipelineCategoryId = $pipelineResult['categories_id'];
$pipelineCategory = Category::find($pipelineCategoryId);
$pipelineCategoryName = $pipelineCategory ? $pipelineCategory->title : 'Unknown';
// Attempt legacy categorization if the class still exists
$legacyCategoryId = Category::OTHER_MISC;
$legacyCategoryName = 'Unknown';
if (class_exists(Categorize::class)) {
try {
$legacy = new Categorize;
/** @var int $legacyCategoryId */
$legacyCategoryId = (int) $legacy->determineCategory($groupId, $releaseName);
$legacyCategory = Category::find($legacyCategoryId);
$legacyCategoryName = $legacyCategory ? $legacyCategory->title : 'Unknown';
} catch (\Throwable) {
$legacyCategoryName = 'Legacy error';
}
} else {
$legacyCategoryName = 'Legacy unavailable';
}
return [
'pipeline' => [
'category_id' => $pipelineCategoryId,
'category_name' => $pipelineCategoryName,
],
'legacy' => [
'category_id' => $legacyCategoryId,
'category_name' => $legacyCategoryName,
],
'match' => $pipelineCategoryId === $legacyCategoryId,
];
}
/**
* Get statistics about categorizer usage.
*
* @return array<string, mixed>
*/
public function getCategorizerStats(): array
{
$categorizers = $this->pipeline->getCategorizers();
return $categorizers->map(function ($categorizer) {
return [
'name' => $categorizer->getName(),
'priority' => $categorizer->getPriority(),
'class' => get_class($categorizer),
];
})->toArray();
}
}