perf(suggestions): add skip_vector_build option for faster initial load
- Add skip_vector_build config option to SuggestionConfig - When true, skips ensure_vector calls (which can be very slow) - Uses only cached/existing vectors for similarity search - Frontend now uses skip_vector_build=true for initial load - Add timestamped logging helper in frontend component
This commit is contained in:
1 parent
ba5ca133f4
commit
ff9e11db5c
4 files changed
+34
-19
No files matched your search
@@ -34,6 +34,8 @@ pub struct SuggestionConfig {
|
||||
pub vector_max_age_days: i64,
|
||||
/// Minimum similarity score to include artist
|
||||
pub min_similarity: f32,
|
||||
/// Skip building vectors - only use existing cached vectors (faster but may have fewer results)
|
||||
pub skip_vector_build: bool,
|
||||
}
|
||||
|
||||
impl Default for SuggestionConfig {
|
||||
@@ -44,6 +46,7 @@ impl Default for SuggestionConfig {
|
||||
max_pool_size: 100,
|
||||
vector_max_age_days: 7,
|
||||
min_similarity: 0.1,
|
||||
skip_vector_build: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,18 +139,22 @@ impl SuggestionsEngine {
|
||||
});
|
||||
}
|
||||
|
||||
// 1. Ensure vectors exist for playlist artists
|
||||
log::info!("[SuggestionsEngine] Step 1: Ensuring vectors for {} artists", playlist_artist_mbids.len());
|
||||
// 1. Ensure vectors exist for playlist artists (skip if configured)
|
||||
let step1_start = Instant::now();
|
||||
for (i, mbid) in playlist_artist_mbids.iter().enumerate() {
|
||||
let artist_start = Instant::now();
|
||||
let _ = self
|
||||
.builder
|
||||
.ensure_vector(mbid, None, None, self.config.vector_max_age_days)
|
||||
.await;
|
||||
log::debug!("[SuggestionsEngine] ensure_vector {}/{} took {:?}", i + 1, playlist_artist_mbids.len(), artist_start.elapsed());
|
||||
if self.config.skip_vector_build {
|
||||
log::info!("[SuggestionsEngine] Step 1: SKIPPED (skip_vector_build=true), using only cached vectors");
|
||||
} else {
|
||||
log::info!("[SuggestionsEngine] Step 1: Ensuring vectors for {} artists", playlist_artist_mbids.len());
|
||||
for (i, mbid) in playlist_artist_mbids.iter().enumerate() {
|
||||
let artist_start = Instant::now();
|
||||
let _ = self
|
||||
.builder
|
||||
.ensure_vector(mbid, None, None, self.config.vector_max_age_days)
|
||||
.await;
|
||||
log::debug!("[SuggestionsEngine] ensure_vector {}/{} took {:?}", i + 1, playlist_artist_mbids.len(), artist_start.elapsed());
|
||||
}
|
||||
log::info!("[SuggestionsEngine] Step 1 completed in {:?}", step1_start.elapsed());
|
||||
}
|
||||
log::info!("[SuggestionsEngine] Step 1 completed in {:?}", step1_start.elapsed());
|
||||
|
||||
// 2. Compute combined playlist vector
|
||||
log::info!("[SuggestionsEngine] Step 2: Computing playlist vector");
|
||||
|
||||
@@ -158,8 +158,8 @@ pub async fn get_playlist_suggestions_v2(
|
||||
|
||||
// Create the engine with config
|
||||
let config = input.config.unwrap_or_default();
|
||||
log::info!("[Suggestions] Config: max_artists={}, tracks_per={}, pool_size={}",
|
||||
config.max_artists, config.tracks_per_artist, config.max_pool_size);
|
||||
log::info!("[Suggestions] Config: max_artists={}, tracks_per={}, pool_size={}, skip_build={}",
|
||||
config.max_artists, config.tracks_per_artist, config.max_pool_size, config.skip_vector_build);
|
||||
|
||||
let engine = SuggestionsEngine::new(
|
||||
store_state.store.clone(),
|
||||
|
||||
@@ -57,6 +57,12 @@
|
||||
// Track the last playlist we loaded for
|
||||
let lastLoadedPlaylistId = $state<number | null>(null);
|
||||
|
||||
// Helper for timestamped logs
|
||||
function log(...args: unknown[]) {
|
||||
const ts = new Date().toISOString().slice(11, 23);
|
||||
console.log(`[${ts}] [Suggestions]`, ...args);
|
||||
}
|
||||
|
||||
// Load suggestions when playlist/artists change
|
||||
$effect(() => {
|
||||
const artistCount = artists.length;
|
||||
@@ -64,7 +70,7 @@
|
||||
|
||||
// Only load if we have artists and haven't loaded for this playlist yet
|
||||
if (artistCount > 0 && currentPlaylistId !== lastLoadedPlaylistId && !loading) {
|
||||
console.log('[Suggestions] Effect triggered, playlist:', currentPlaylistId, 'artists:', artistCount);
|
||||
log('Effect triggered, playlist:', currentPlaylistId, 'artists:', artistCount);
|
||||
lastLoadedPlaylistId = currentPlaylistId;
|
||||
hasLoadedOnce = false;
|
||||
pool = [];
|
||||
@@ -74,27 +80,27 @@
|
||||
|
||||
async function loadSuggestions(expanded: boolean) {
|
||||
if (loading) {
|
||||
console.log('[Suggestions] Already loading, skipping');
|
||||
log('Already loading, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
const poolSize = expanded ? EXPANDED_POOL : INITIAL_POOL;
|
||||
console.log(`[Suggestions] Starting load (expanded=${expanded}, poolSize=${poolSize}, artists=${artists.length})`);
|
||||
log(`Starting load (expanded=${expanded}, poolSize=${poolSize}, artists=${artists.length})`);
|
||||
const startTime = performance.now();
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
console.log('[Suggestions] Calling backend...');
|
||||
log('Calling backend...');
|
||||
result = await getPlaylistSuggestionsV2(
|
||||
artists,
|
||||
excludeTrackIds,
|
||||
showReasons,
|
||||
{ max_pool_size: poolSize }
|
||||
{ max_pool_size: poolSize, skip_vector_build: true }
|
||||
);
|
||||
const elapsed = ((performance.now() - startTime) / 1000).toFixed(2);
|
||||
console.log(`[Suggestions] Backend returned in ${elapsed}s:`, {
|
||||
log(`Backend returned in ${elapsed}s:`, {
|
||||
tracks: result.tracks.length,
|
||||
sourceArtists: result.source_artists.length,
|
||||
playlistArtists: result.playlist_artists_count,
|
||||
@@ -105,7 +111,7 @@
|
||||
hasLoadedOnce = true;
|
||||
} catch (err) {
|
||||
const elapsed = ((performance.now() - startTime) / 1000).toFixed(2);
|
||||
console.error(`[Suggestions] Failed after ${elapsed}s:`, err);
|
||||
log(`Failed after ${elapsed}s:`, err);
|
||||
error = err instanceof Error ? err.message : 'Failed to load suggestions';
|
||||
pool = [];
|
||||
} finally {
|
||||
|
||||
@@ -15,6 +15,8 @@ export interface SuggestionConfig {
|
||||
max_pool_size?: number;
|
||||
vector_max_age_days?: number;
|
||||
min_similarity?: number;
|
||||
/** Skip building vectors - only use existing cached vectors (faster but may have fewer results) */
|
||||
skip_vector_build?: boolean;
|
||||
}
|
||||
|
||||
export interface SuggestedTrack {
|
||||
|
||||
Reference in new issue
Block a user