- migration 00006: track features and embeddings (pgvector, HNSW), analysis queue filled by a trigger on new tracks, wave sessions and impressions, recommender profiles, model versions - analyzer basic-1 (ADR-014): ffmpeg decode, three 30 s excerpts, 256-d timbre/rhythm embedding, tempo by onset autocorrelation, key, loudness, energy, danceability, acousticness, intro length; worker with SKIP LOCKED claims, retries and re-analysis on version change - wave engine v1: candidates (session/taste similarity, fresh, liked artists, rediscover, popular, exploration, seed), filters (dislikes, played in 3 h, already served), heuristic score, activity and mood fit from contexts.yaml with relaxing thresholds, MMR with one track per artist, exploration share, session vector updated by reactions and a change of course after three skips - POST /internal/wave/batch with the catalog index cached in memory and the session kept in Redis Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
3.5 KiB
PL/PgSQL
107 lines
3.5 KiB
PL/PgSQL
-- +goose Up
|
|
CREATE TABLE track_features (
|
|
track_id uuid PRIMARY KEY REFERENCES tracks(id) ON DELETE CASCADE,
|
|
analyzer_ver text NOT NULL,
|
|
bpm real,
|
|
bpm_confidence real,
|
|
key text,
|
|
scale text,
|
|
loudness_lufs real,
|
|
energy real,
|
|
danceability real,
|
|
valence real,
|
|
arousal real,
|
|
acousticness real,
|
|
instrumentalness real,
|
|
mood_happy real,
|
|
mood_sad real,
|
|
mood_relaxed real,
|
|
mood_aggressive real,
|
|
mood_party real,
|
|
intro_ms int,
|
|
analyzed_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE track_embeddings (
|
|
track_id uuid PRIMARY KEY REFERENCES tracks(id) ON DELETE CASCADE,
|
|
audio vector(256),
|
|
cf vector(64),
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
CREATE INDEX track_embeddings_audio_idx ON track_embeddings USING hnsw (audio vector_cosine_ops);
|
|
|
|
CREATE TABLE analysis_jobs (
|
|
track_id uuid PRIMARY KEY REFERENCES tracks(id) ON DELETE CASCADE,
|
|
status text NOT NULL DEFAULT 'queued',
|
|
attempts int NOT NULL DEFAULT 0,
|
|
error text,
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
CREATE INDEX analysis_jobs_queued_idx ON analysis_jobs (updated_at) WHERE status = 'queued';
|
|
|
|
-- Каждый новый трек сразу встаёт в очередь анализа; существующие — тоже.
|
|
-- +goose StatementBegin
|
|
CREATE FUNCTION enqueue_analysis() RETURNS trigger LANGUAGE plpgsql AS $$
|
|
BEGIN
|
|
INSERT INTO analysis_jobs (track_id) VALUES (NEW.id) ON CONFLICT DO NOTHING;
|
|
RETURN NEW;
|
|
END $$;
|
|
-- +goose StatementEnd
|
|
CREATE TRIGGER tracks_enqueue_analysis AFTER INSERT ON tracks FOR EACH ROW EXECUTE FUNCTION enqueue_analysis();
|
|
INSERT INTO analysis_jobs (track_id) SELECT id FROM tracks ON CONFLICT DO NOTHING;
|
|
|
|
CREATE TABLE wave_sessions (
|
|
id uuid PRIMARY KEY,
|
|
user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
activity text,
|
|
mood text,
|
|
seed_type text,
|
|
seed_id uuid,
|
|
started_at timestamptz NOT NULL DEFAULT now(),
|
|
ended_at timestamptz,
|
|
tracks_served int NOT NULL DEFAULT 0
|
|
);
|
|
CREATE INDEX wave_sessions_user_idx ON wave_sessions (user_id, started_at DESC);
|
|
|
|
CREATE TABLE wave_impressions (
|
|
wave_session_id uuid REFERENCES wave_sessions(id) ON DELETE CASCADE,
|
|
position int NOT NULL,
|
|
track_id uuid NOT NULL,
|
|
candidate_source text NOT NULL,
|
|
score real,
|
|
model_ver text,
|
|
served_at timestamptz NOT NULL DEFAULT now(),
|
|
outcome text,
|
|
PRIMARY KEY (wave_session_id, position)
|
|
);
|
|
CREATE INDEX wave_impressions_track_idx ON wave_impressions (wave_session_id, track_id);
|
|
|
|
CREATE TABLE user_profiles_rec (
|
|
user_id uuid PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
|
|
taste_audio vector(256),
|
|
taste_cf vector(64),
|
|
genre_prefs jsonb NOT NULL DEFAULT '{}',
|
|
bandit jsonb NOT NULL DEFAULT '{}',
|
|
exploration real NOT NULL DEFAULT 0.15,
|
|
updated_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE TABLE model_versions (
|
|
id text PRIMARY KEY,
|
|
kind text NOT NULL,
|
|
metrics jsonb,
|
|
is_active boolean NOT NULL DEFAULT false,
|
|
created_at timestamptz NOT NULL DEFAULT now()
|
|
);
|
|
|
|
-- +goose Down
|
|
DROP TABLE model_versions;
|
|
DROP TABLE user_profiles_rec;
|
|
DROP TABLE wave_impressions;
|
|
DROP TABLE wave_sessions;
|
|
DROP TRIGGER tracks_enqueue_analysis ON tracks;
|
|
DROP FUNCTION enqueue_analysis();
|
|
DROP TABLE analysis_jobs;
|
|
DROP TABLE track_embeddings;
|
|
DROP TABLE track_features;
|