Repair: copy legacy joinDate into new user's created_at when creating users from legacy wallz
This commit is contained in:
118
app/Console/Commands/SearchArtworkVectorsCommand.php
Normal file
118
app/Console/Commands/SearchArtworkVectorsCommand.php
Normal file
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Artwork;
|
||||
use App\Models\Category;
|
||||
use App\Services\Vision\ArtworkVisionImageUrl;
|
||||
use App\Services\Vision\VectorGatewayClient;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
final class SearchArtworkVectorsCommand extends Command
|
||||
{
|
||||
protected $signature = 'artworks:vectors-search
|
||||
{artwork_id : Source artwork id}
|
||||
{--limit=5 : Number of similar artworks to return}';
|
||||
|
||||
protected $description = 'Search similar artworks through the vector gateway using an artwork image URL';
|
||||
|
||||
public function handle(VectorGatewayClient $client, ArtworkVisionImageUrl $imageUrl): int
|
||||
{
|
||||
if (! $client->isConfigured()) {
|
||||
$this->error('Vision vector gateway is not configured. Set VISION_VECTOR_GATEWAY_URL and VISION_VECTOR_GATEWAY_API_KEY.');
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$artworkId = max(1, (int) $this->argument('artwork_id'));
|
||||
$limit = max(1, min((int) $this->option('limit'), 100));
|
||||
|
||||
$artwork = Artwork::query()
|
||||
->with(['categories' => fn ($categories) => $categories->with('contentType')->orderBy('sort_order')->orderBy('name')])
|
||||
->find($artworkId);
|
||||
|
||||
if (! $artwork) {
|
||||
$this->error("Artwork {$artworkId} was not found.");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$url = $imageUrl->fromArtwork($artwork);
|
||||
if ($url === null) {
|
||||
$this->error("Artwork {$artworkId} does not have a usable CDN image URL.");
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
$matches = $client->searchByUrl($url, $limit + 1);
|
||||
} catch (\Throwable $e) {
|
||||
$this->error('Vector search failed: ' . $e->getMessage());
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$ids = collect($matches)
|
||||
->map(fn (array $match): int => (int) $match['id'])
|
||||
->filter(fn (int $id): bool => $id > 0 && $id !== $artworkId)
|
||||
->unique()
|
||||
->take($limit)
|
||||
->values()
|
||||
->all();
|
||||
|
||||
if ($ids === []) {
|
||||
$this->warn('No similar artworks were returned by the vector gateway.');
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$artworks = Artwork::query()
|
||||
->with(['categories' => fn ($categories) => $categories->with('contentType')->orderBy('sort_order')->orderBy('name')])
|
||||
->whereIn('id', $ids)
|
||||
->public()
|
||||
->published()
|
||||
->get()
|
||||
->keyBy('id');
|
||||
|
||||
$rows = [];
|
||||
foreach ($matches as $match) {
|
||||
$matchId = (int) ($match['id'] ?? 0);
|
||||
if ($matchId <= 0 || $matchId === $artworkId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Artwork|null $matchedArtwork */
|
||||
$matchedArtwork = $artworks->get($matchId);
|
||||
if (! $matchedArtwork) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$category = $this->primaryCategory($matchedArtwork);
|
||||
$rows[] = [
|
||||
'id' => $matchId,
|
||||
'score' => number_format((float) ($match['score'] ?? 0.0), 4, '.', ''),
|
||||
'title' => (string) $matchedArtwork->title,
|
||||
'content_type' => (string) ($category?->contentType?->name ?? ''),
|
||||
'category' => (string) ($category?->name ?? ''),
|
||||
];
|
||||
|
||||
if (count($rows) >= $limit) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($rows === []) {
|
||||
$this->warn('The vector gateway returned matches, but none resolved to public published artworks.');
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$this->table(['ID', 'Score', 'Title', 'Content Type', 'Category'], $rows);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function primaryCategory(Artwork $artwork): ?Category
|
||||
{
|
||||
/** @var Category|null $category */
|
||||
$category = $artwork->categories->sortBy('sort_order')->first();
|
||||
|
||||
return $category;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user