env('RECOMMENDATIONS_QUEUE', env('VISION_QUEUE', 'default')), // ─── Phase 1 "For You" feed scoring weights ─────────────────────────────── // Influences the PHP reranking pass after Meilisearch candidate retrieval. // Tweak here without code changes. 'weights' => [ // Tag overlap score weight (0–1 normalized overlap fraction) 'tag_overlap' => (float) env('RECO_W_TAG_OVERLAP', 0.40), // Creator affinity score weight (1.0 if followed, 0 otherwise) 'creator_affinity' => (float) env('RECO_W_CREATOR_AFFINITY', 0.25), // Popularity boost (log-normalised views/downloads) 'popularity' => (float) env('RECO_W_POPULARITY', 0.20), // Freshness boost (exponential decay over 30 days) 'freshness' => (float) env('RECO_W_FRESHNESS', 0.15), ], // ─── User preference signal weights ────────────────────────────────────── // How much each user action contributes to building the reco profile. 'signal_weights' => [ 'award' => (float) env('RECO_SIG_AWARD', 5.0), 'favorite' => (float) env('RECO_SIG_FAVORITE', 3.0), 'reaction' => (float) env('RECO_SIG_REACTION', 2.0), 'view' => (float) env('RECO_SIG_VIEW', 1.0), 'follow' => (float) env('RECO_SIG_FOLLOW', 2.0), ], // ─── Candidate generation ────────────────────────────────────────────────── // How many Meilisearch candidates to fetch before PHP reranking. 'candidate_pool_size' => (int) env('RECO_CANDIDATE_POOL', 200), // ─── Diversity controls ──────────────────────────────────────────────────── // Maximum artworks per creator allowed in a single page of results. 'max_per_creator' => (int) env('RECO_MAX_PER_CREATOR', 3), // Minimum distinct tag count in first 20 feed results. 'min_unique_tags' => (int) env('RECO_MIN_UNIQUE_TAGS', 5), // ─── TTLs (seconds) ──────────────────────────────────────────────────────── 'ttl' => [ // User reco profile cache (tag/creator affinity data) 'user_reco_profile' => (int) env('RECO_TTL_PROFILE', 6 * 3600), // For You paginated results cache 'for_you_feed' => (int) env('RECO_TTL_FOR_YOU', 5 * 60), // Similar artworks per artwork 'similar_artworks' => (int) env('RECO_TTL_SIMILAR', 30 * 60), // Suggested creators per user 'creator_suggestions' => (int) env('RECO_TTL_CREATORS', 30 * 60), // Suggested tags per user 'tag_suggestions' => (int) env('RECO_TTL_TAGS', 60 * 60), ], // ─── Profile limits ──────────────────────────────────────────────────────── 'profile' => [ 'top_tags_limit' => (int) env('RECO_PROFILE_TAGS', 20), 'top_categories_limit' => (int) env('RECO_PROFILE_CATS', 5), 'strong_creators_limit' => (int) env('RECO_PROFILE_CREATORS', 50), ], 'embedding' => [ 'enabled' => env('RECOMMENDATIONS_EMBEDDING_ENABLED', true), 'model' => env('RECOMMENDATIONS_EMBEDDING_MODEL', 'clip'), 'model_version' => env('RECOMMENDATIONS_EMBEDDING_MODEL_VERSION', 'v1'), 'algo_version' => env('RECOMMENDATIONS_ALGO_VERSION', 'clip-cosine-v1'), // Preferred CLIP endpoint for embeddings. The service also accepts an embedding payload from the analyze endpoint response. 'endpoint' => env('CLIP_EMBED_ENDPOINT', '/embed'), 'timeout_seconds' => (int) env('CLIP_EMBED_TIMEOUT_SECONDS', 8), 'connect_timeout_seconds' => (int) env('CLIP_EMBED_CONNECT_TIMEOUT_SECONDS', 2), 'retries' => (int) env('CLIP_EMBED_HTTP_RETRIES', 1), 'retry_delay_ms' => (int) env('CLIP_EMBED_HTTP_RETRY_DELAY_MS', 200), // Guardrails for malformed service responses. 'min_dim' => (int) env('RECOMMENDATIONS_MIN_DIM', 64), 'max_dim' => (int) env('RECOMMENDATIONS_MAX_DIM', 4096), ], // Backfill chunk size for resumable queue fan-out. 'backfill_batch_size' => (int) env('RECOMMENDATIONS_BACKFILL_BATCH', 200), // A/B support for recommendation ranking variants. 'ab' => [ 'algo_versions' => array_values(array_filter(array_map( static fn (string $value): string => trim($value), explode(',', (string) env('RECOMMENDATIONS_AB_ALGO_VERSIONS', env('RECOMMENDATIONS_ALGO_VERSION', 'clip-cosine-v1'))) ))), ], ];