optimizations

This commit is contained in:
2026-03-28 19:15:39 +01:00
parent 0b25d9570a
commit cab4fbd83e
509 changed files with 1016804 additions and 1605 deletions

View File

@@ -8,6 +8,7 @@ use App\Jobs\RegenerateUserRecommendationCacheJob;
use App\Models\Artwork;
use App\Models\UserInterestProfile;
use App\Models\UserRecommendationCache;
use App\Support\AvatarUrl;
use Carbon\CarbonImmutable;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
@@ -382,7 +383,13 @@ final class PersonalizedFeedService
/** @var Collection<int, Artwork> $artworks */
$artworks = Artwork::query()
->with(['user:id,name'])
->with([
'user:id,name,username',
'user.profile:user_id,avatar_hash',
'categories:id,name,slug,content_type_id,parent_id,sort_order',
'categories.contentType:id,name,slug',
'tags:id,name,slug',
])
->whereIn('id', $ids)
->public()
->published()
@@ -397,14 +404,51 @@ final class PersonalizedFeedService
continue;
}
$primaryCategory = $artwork->categories->sortBy('sort_order')->first();
$primaryTag = $artwork->tags->sortBy('name')->first();
$source = (string) ($item['source'] ?? 'mixed');
$responseItems[] = [
'id' => $artwork->id,
'slug' => $artwork->slug,
'title' => $artwork->title,
'thumbnail_url' => $artwork->thumb_url,
'thumbnail_srcset' => $artwork->thumb_srcset,
'author' => $artwork->user?->name,
'username' => $artwork->user?->username,
'author_id' => $artwork->user?->id,
'avatar_url' => AvatarUrl::forUser(
(int) ($artwork->user?->id ?? 0),
$artwork->user?->profile?->avatar_hash,
64
),
'content_type_name' => $primaryCategory?->contentType?->name ?? '',
'content_type_slug' => $primaryCategory?->contentType?->slug ?? '',
'category_name' => $primaryCategory?->name ?? '',
'category_slug' => $primaryCategory?->slug ?? '',
'width' => $artwork->width,
'height' => $artwork->height,
'published_at' => $artwork->published_at?->toIso8601String(),
'url' => route('art.show', ['id' => $artwork->id, 'slug' => $artwork->slug]),
'primary_tag' => $primaryTag !== null ? [
'id' => (int) $primaryTag->id,
'name' => (string) $primaryTag->name,
'slug' => (string) $primaryTag->slug,
] : null,
'tags' => $artwork->tags
->sortBy('name')
->take(3)
->map(static fn ($tag): array => [
'id' => (int) $tag->id,
'name' => (string) $tag->name,
'slug' => (string) $tag->slug,
])
->values()
->all(),
'score' => (float) ($item['score'] ?? 0.0),
'source' => (string) ($item['source'] ?? 'mixed'),
'source' => $source,
'reason' => $this->buildRecommendationReason($artwork, $source),
'algo_version' => $algoVersion,
];
}
@@ -422,10 +466,30 @@ final class PersonalizedFeedService
'cache_status' => $cacheStatus,
'generated_at' => $generatedAt,
'total_candidates' => count($items),
'engine' => 'v1',
],
];
}
private function buildRecommendationReason(Artwork $artwork, string $source): string
{
$primaryCategory = $artwork->categories->sortBy('sort_order')->first();
$categoryName = trim((string) ($primaryCategory?->name ?? ''));
return match ($source) {
'personalized' => $categoryName !== ''
? 'Matched to your interest in ' . $categoryName
: 'Matched to your recent interests',
'cold_start' => $categoryName !== ''
? 'Popular in ' . $categoryName . ' right now'
: 'Popular with the community right now',
'fallback' => $categoryName !== ''
? 'Trending in ' . $categoryName
: 'Trending across Skinbase',
default => 'Picked for you',
};
}
private function resolveAlgoVersion(?string $algoVersion = null, ?int $userId = null): string
{
if ($algoVersion !== null && $algoVersion !== '') {