File size: 7,231 Bytes
16568c6
 
 
 
 
 
 
 
0b7b671
16568c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
985a585
7275350
 
16568c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a34e3b0
16568c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a34e3b0
16568c6
 
7201617
16568c6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
import streamlit as st
import numpy as np
import pandas as pd
import tensorflow as tf
from transformers import RobertaTokenizer, TFRobertaForSequenceClassification
from sentence_transformers import SentenceTransformer, util
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials
import os 

sim_model = SentenceTransformer("sentence-transformers/all-mpnet-base-v2")

# Function to analyze sentiment of the user's input
def analyze_user_input(user_input, tokenizer, model):
    encoded_input = tokenizer(user_input, return_tensors="tf", truncation=True, padding=True, max_length=512)
    outputs = model(encoded_input)
    scores = tf.nn.softmax(outputs.logits, axis=-1).numpy()[0]
    predicted_class_idx = tf.argmax(outputs.logits, axis=-1).numpy()[0]
    sentiment_label = model.config.id2label[predicted_class_idx]
    sentiment_score = scores[predicted_class_idx]
    return sentiment_label, sentiment_score

# Function to match songs from the dataset with the user's sentiment
def match_songs_with_sentiment(user_sentiment_label, user_sentiment_score,inputVector, score_range,songs_df):

    # Filter songs with the same sentiment label
    matched_songs = songs_df[songs_df['sentiment'] == user_sentiment_label]

    # Calculate the score range
    score_min = max(0, user_sentiment_score - score_range)
    score_max = min(1, user_sentiment_score + score_range)

    # Further filter songs whose scores fall within the specified range
    matched_songs = matched_songs[(matched_songs['score'] >= score_min) & (matched_songs['score'] <= score_max)]

    # Shuffle the matched songs to get a random order
    matched_songs = matched_songs.sample(frac=1).reset_index(drop=True)

    matched_songs['similarity'] = matched_songs['seq'].apply(lambda x: util.pytorch_cos_sim(sim_model.encode(x), inputVector))

    top_5 = matched_songs['similarity'].sort_values(ascending=False).head(5)

    # Sort the songs by how close their score is to the user's sentiment score
    # matched_songs['score_diff'] = abs(matched_songs['score'] - user_sentiment_score)
    # matched_songs = matched_songs.sort_values(by='score_diff')

    # Select the top five songs and return
    return matched_songs.loc[top_5.index, ['song','artist','seq','similarity','sentiment','score']]


client_id = os.getenv('client_id')
client_secret = os.getenv('client_secret')

client_credentials_manager = SpotifyClientCredentials(client_id=client_id, client_secret=client_secret)
sp = spotipy.Spotify(client_credentials_manager=client_credentials_manager)

def get_track_id(song_name):
    # Search for the track ID using the song name
    results = sp.search(q=song_name, type='track', limit=1)
    if results['tracks']['items']:
        track_id = results['tracks']['items'][0]['id']
        return track_id
    else:
        print(f"No results found for {song_name}")
        return None

def get_track_preview_url(track_id):
    # Get the 30-second preview URL for the track
    track_info = sp.track(track_id)
    preview_url = track_info['preview_url']
    return preview_url

# Initialize the tokenizer and model outside of the functions to speed up repeated calls
tokenizer = RobertaTokenizer.from_pretrained('roberta-base')
model = TFRobertaForSequenceClassification.from_pretrained('arpanghoshal/EmoRoBERTa')

# Streamlit app layout
st.set_page_config(page_title="MODUS MUSIC", layout="wide")  # New: Setting page title and layout

# Custom CSS for background and text color
st.markdown("""
    <style>
    .stApp {
        background: rgb(0,0,0);
        background-size: cover;
        color: white;  /* Sets global text color to white */
    }
    /* General rule for all labels */
    label {
        color: white !important;
    }
    /* Specific color for the main title */
    h1 {
        color: red !important;  /* Making the MODUS MUSIC title red */
    }
    /* Additional specific styling */
    .stTextInput > label, .stButton > button, .css-10trblm, .css-1yjuwjr, .intro {
        color: white !important;
    }
    </style>
    """, unsafe_allow_html=True)


image_path = './MODUSMUSIC.png'  # Replace with the actual path to your image

st.image(image_path, use_column_width=False, width=250)  # Adjust the width as needed
# Custom gradient background using CSS
st.markdown("""
    <style>
    .stApp {
        background: rgb(0,0,0);
        background-size: cover;
    }
    </style>
    """, unsafe_allow_html=True)

# Custom HTML for the main title
st.markdown("<h1 style='text-align: center; font-weight: bold;'>MODUS MUSIC</h1>", unsafe_allow_html=True)

st.title('Music Suggestion Based on Your Feeling')  # Existing Title

# New: Introduction Section
with st.container():
    st.markdown("""
        <style>
        .intro {
            font-size:18px;
        }
        </style>
        <div class='intro'>
        Welcome to Modus Music! Share your vibe, and let's find the perfect songs to match your mood.
        Just type in your thoughts, and we'll do the rest.
        </div>
        """, unsafe_allow_html=True)

# User input text area
with st.container():
    user_input = st.text_area("What's your vibe? Tell me about it:", key="123", height=150, max_chars=500)
m = st.markdown("""
<style>
div.stButton > button:first-child {
    background-color: rgb(204, 49, 49);

}
</style>""", unsafe_allow_html=True)
# Use the custom style for the button
submit_button = st.button("Generate music")


# Processing and Displaying Results
if submit_button and len(user_input.split()) > 5:
    # New: Define inputVector here
    inputVector = sim_model.encode(user_input)

    # Run sentiment analysis on the user input
    sentiment_label, sentiment_score = analyze_user_input(user_input, tokenizer, model)
    st.write(f"Sentiment: {sentiment_label}, Score: {sentiment_score:.2f}")

    # Load songs dataframe
    songs_df = pd.read_csv('./music_mental_health.csv')

    # Suggest songs
    suggested_songs = match_songs_with_sentiment(sentiment_label, sentiment_score, inputVector, 0.0003, songs_df)
    suggested_songs['similarity'] = suggested_songs['similarity'].apply(lambda x: x.numpy()[0][0])

    # Styling for the suggested songs display
    with st.container():
        st.markdown("<div class='song-list'>", unsafe_allow_html=True)
        st.write("Based on your vibe, you might like these songs:")
        for index, row in suggested_songs.iterrows():
          song = row['song']
          artist = row['artist']
          track_id = get_track_id(song)
          if track_id.strip():
            preview_url = get_track_preview_url(track_id)
            #st.write(f"Similarity: {row['similarity']}")
            st.write(f"{song} by {artist}")
            with st.expander(f"Show Lyrics for {song} by {artist}", expanded=False):
                st.write(f"Lyrics: {row['seq']}")

            if preview_url:
              st.audio(preview_url)
            else:
              st.write("No Preview Available")
        st.markdown("</div>", unsafe_allow_html=True)
        st.dataframe(suggested_songs[['song','artist','seq','similarity','sentiment','score']])
elif submit_button and not len(user_input.split()) > 5:
    st.warning("Please provide a longer response with 5 words or more.")
    st.rerun()