72 lines
2.8 KiB
PHP
72 lines
2.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
use App\Services\Recommendations\FeedOfflineEvaluationService;
|
|
use Illuminate\Console\Command;
|
|
|
|
final class CompareFeedAbCommand extends Command
|
|
{
|
|
protected $signature = 'analytics:compare-feed-ab
|
|
{baseline : Baseline algo_version}
|
|
{candidate : Candidate algo_version}
|
|
{--from= : Start date (Y-m-d), defaults to last 30 days}
|
|
{--to= : End date (Y-m-d), defaults to today}
|
|
{--json : Output as JSON}';
|
|
|
|
protected $description = 'A/B helper for baseline vs candidate feed algo comparison';
|
|
|
|
public function __construct(private readonly FeedOfflineEvaluationService $evaluator)
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
public function handle(): int
|
|
{
|
|
$from = (string) ($this->option('from') ?: now()->subDays(29)->toDateString());
|
|
$to = (string) ($this->option('to') ?: now()->toDateString());
|
|
|
|
if ($from > $to) {
|
|
$this->error('Invalid range: --from must be <= --to');
|
|
return self::FAILURE;
|
|
}
|
|
|
|
$baseline = (string) $this->argument('baseline');
|
|
$candidate = (string) $this->argument('candidate');
|
|
|
|
$comparison = $this->evaluator->compareBaselineCandidate($baseline, $candidate, $from, $to);
|
|
|
|
if ((bool) $this->option('json')) {
|
|
$this->line((string) json_encode($comparison, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
|
return self::SUCCESS;
|
|
}
|
|
|
|
$this->table(
|
|
['algo_version', 'ctr', 'save_rate', 'long_dwell_share', 'bounce_rate', 'objective_score'],
|
|
[[
|
|
(string) $comparison['baseline']['algo_version'],
|
|
(float) $comparison['baseline']['ctr'],
|
|
(float) $comparison['baseline']['save_rate'],
|
|
(float) $comparison['baseline']['long_dwell_share'],
|
|
(float) $comparison['baseline']['bounce_rate'],
|
|
(float) $comparison['baseline']['objective_score'],
|
|
], [
|
|
(string) $comparison['candidate']['algo_version'],
|
|
(float) $comparison['candidate']['ctr'],
|
|
(float) $comparison['candidate']['save_rate'],
|
|
(float) $comparison['candidate']['long_dwell_share'],
|
|
(float) $comparison['candidate']['bounce_rate'],
|
|
(float) $comparison['candidate']['objective_score'],
|
|
]]
|
|
);
|
|
|
|
$delta = (array) $comparison['delta'];
|
|
$this->line('Δ objective_score: ' . (string) $delta['objective_score']);
|
|
$this->line('Δ objective_lift_pct: ' . (string) ($delta['objective_lift_pct'] ?? 'n/a'));
|
|
|
|
return self::SUCCESS;
|
|
}
|
|
}
|