File size: 4,505 Bytes
ec24f86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import gradio as gr
import pandas as pd
import pickle
from sklearn.metrics.pairwise import cosine_similarity
import heapq

# Load data and model
df = pd.read_csv('./DATA/spotify_millsongdata.csv')

# Load saved embeddings
with open("./DATA/lyrics_embeddings.pkl", "rb") as f:
    lyrics_embeddings = pickle.load(f)

# List of artists and songs
artists = df['artist'].unique()
song_titles = df['song']

# Recommendation logic
def recommend_songs(song_index, top_n=5, batch_size=100):
    top_sim_scores = []
    num_batches = len(df) // batch_size + 1

    for i in range(num_batches):
        start_idx = i * batch_size
        end_idx = min((i + 1) * batch_size, len(df))

        # Compute cosine similarity for the current batch
        cosine_sim_batch = cosine_similarity(
            lyrics_embeddings[start_idx:end_idx],
            [lyrics_embeddings[song_index]]
        )

        # Select the top N most similar songs
        for j, sim_score in enumerate(cosine_sim_batch):
            global_idx = start_idx + j
            heapq.heappush(top_sim_scores, (sim_score[0], global_idx))
            if len(top_sim_scores) > top_n + 1:
                heapq.heappop(top_sim_scores)

    # Exclude the selected song itself and return the most similar songs with their similarity scores
    top_sim_scores = sorted(top_sim_scores, key=lambda x: x[0], reverse=True)[1:top_n+1]
    recommended_songs = [(song_titles[i[1]], df['link'][i[1]], round(i[0], 2)) for i in top_sim_scores]

    return recommended_songs

# Interface logic function
def get_songs_by_artist(artist_name):
    filtered_songs = df[df['artist'] == artist_name]['song'].tolist()
    return gr.update(choices=filtered_songs, value=filtered_songs[0] if filtered_songs else None)


def gradio_recommend(song_title):
    try:
        # Find the index of the selected song
        song_index = song_titles[song_titles == song_title].index[0]
        # Get recommended songs
        recommendations = recommend_songs(song_index)

        # Format the output, making song links clickable
        result = "<div style='text-align: left;'>"
        for song, link, sim_score in recommendations:
            result += f"<b>Song Name:</b> {song}<br>"
            result += f"<b>Search Link:</b> <a href='https://www.google.com/search?q={link}' target='_blank'>{link}</a><br>"
            result += f"<b>Lyrics Similarity:</b> {sim_score:.2f}<br><br>"
        result += "</div>"
        return result
    except IndexError:
        return "Song not found."

# Create Gradio multi-page interface
with gr.Blocks(css="""
@media (max-width: 768px) {
    .gr-container { 
        width: 100%; 
        padding: 10px; 
        box-sizing: border-box; 
    }
    .gr-dropdown select {
    width: 100%;
    height: 40px; /* Limit height */
    font-size: 16px;
    padding: 5px;
    box-sizing: border-box;
    }
    .gr-button { 
        width: 100%; 
        font-size: 16px; 
        margin-top: 10px; 
    }
    .gr-html, .gr-row { 
        width: 100%; 
        font-size: 16px; 
        margin: 10px 0; 
    }
    h1 { 
        font-size: 24px; 
    }
    p { 
        font-size: 14px; 
    }
    .gr-dropdown::after {
    content: '';
    width: 12px;
    height: 12px;
    border: solid black;
    border-width: 0 2px 2px 0;
    display: inline-block;
    transform: rotate(45deg);
    margin-left: 10px;
   }
}
""") as demo:

    gr.Markdown(
        """
        <div style="text-align: center; padding: 20px;">
            <h1 style="color: #1DB954;">Music Recommendation System</h1>
            <p style="font-size: 18px;">Get the most relevant song recommendations based on lyrics similarity</p>
        </div>
        """
    )

    # Page 1: Select artist
    with gr.Row():
        with gr.Column():
          artist_dropdown = gr.Dropdown(choices=list(artists), label="Select Artist")
          next_button = gr.Button("Next")

    # Page 2: Select song and get recommendations
    with gr.Row(visible=False) as song_selection_row:
        song_dropdown = gr.Dropdown(label="Select Song")
        recommend_button = gr.Button("Get Recommendations")
        output = gr.HTML(label="Recommended Similar Songs")

    # Event bindings
    artist_dropdown.change(get_songs_by_artist, inputs=artist_dropdown, outputs=song_dropdown)
    next_button.click(lambda: gr.update(visible=True), None, song_selection_row)
    recommend_button.click(gradio_recommend, inputs=song_dropdown, outputs=output)

if __name__ == "__main__":
    demo.launch()