From a608be73878bbe2d850267c3b6655a4784b85115 Mon Sep 17 00:00:00 2001 From: Claudio Ortolina Date: Sat, 11 Apr 2026 21:27:35 +0100 Subject: [PATCH] Move regenerate_artist_embeddings into Similarity --- lib/music_library/records/similarity.ex | 14 ++++ .../music_library/records/similarity_test.exs | 72 +++++++++++++++++++ 2 files changed, 86 insertions(+) diff --git a/lib/music_library/records/similarity.ex b/lib/music_library/records/similarity.ex index fef77348..4569dba9 100644 --- a/lib/music_library/records/similarity.ex +++ b/lib/music_library/records/similarity.ex @@ -341,6 +341,20 @@ defmodule MusicLibrary.Records.Similarity do |> Oban.insert() end + @doc """ + Enqueues embedding regeneration for every record by the given artist. + + Used when upstream artist metadata (MusicBrainz/Wikipedia/Discogs/Last.fm) + changes, so that each record's text representation — which embeds per-artist + context — is re-computed. + """ + @spec regenerate_artist_embeddings(String.t()) :: :ok + def regenerate_artist_embeddings(musicbrainz_id) do + musicbrainz_id + |> Records.get_artist_records() + |> Enum.each(&generate_embedding_async/1) + end + @spec generate_all_embeddings_async() :: non_neg_integer() def generate_all_embeddings_async do Record diff --git a/test/music_library/records/similarity_test.exs b/test/music_library/records/similarity_test.exs index 685f5907..bb9e1ba9 100644 --- a/test/music_library/records/similarity_test.exs +++ b/test/music_library/records/similarity_test.exs @@ -297,6 +297,78 @@ defmodule MusicLibrary.Records.SimilarityTest do end end + describe "generate_embedding_async/1" do + test "enqueues a GenerateRecordEmbedding job for the record" do + record = record() + + assert {:ok, %Oban.Job{}} = Similarity.generate_embedding_async(record) + + assert_enqueued( + worker: MusicLibrary.Worker.GenerateRecordEmbedding, + args: %{record_id: record.id} + ) + end + end + + describe "regenerate_artist_embeddings/1" do + test "enqueues a GenerateRecordEmbedding job for each record by the artist" do + artist_mbid = Ecto.UUID.generate() + other_artist_mbid = Ecto.UUID.generate() + + record_a = + record(%{ + artists: [ + %{ + name: "Target Artist", + musicbrainz_id: artist_mbid, + sort_name: "Artist, Target", + joinphrase: "" + } + ] + }) + + record_b = + record(%{ + artists: [ + %{ + name: "Target Artist", + musicbrainz_id: artist_mbid, + sort_name: "Artist, Target", + joinphrase: "" + } + ] + }) + + _unrelated = + record(%{ + artists: [ + %{ + name: "Unrelated", + musicbrainz_id: other_artist_mbid, + sort_name: "Unrelated", + joinphrase: "" + } + ] + }) + + assert :ok = Similarity.regenerate_artist_embeddings(artist_mbid) + + assert_enqueued( + worker: MusicLibrary.Worker.GenerateRecordEmbedding, + args: %{record_id: record_a.id} + ) + + assert_enqueued( + worker: MusicLibrary.Worker.GenerateRecordEmbedding, + args: %{record_id: record_b.id} + ) + end + + test "returns :ok when the artist has no records" do + assert :ok = Similarity.regenerate_artist_embeddings(Ecto.UUID.generate()) + end + end + describe "find_similar/2" do setup do # Create test records with embeddings