|
|
""" |
|
|
HarmoniFind Gradio Backend |
|
|
Deploy this to Hugging Face Spaces or run locally |
|
|
|
|
|
To deploy to Hugging Face Spaces: |
|
|
1. Create account at https://huggingface.co |
|
|
2. Create new Space with Gradio SDK |
|
|
3. Upload this file as app.py |
|
|
4. Upload your embeddings and index files |
|
|
5. Copy the Space URL to your frontend config |
|
|
""" |
|
|
|
|
|
import gradio as gr |
|
|
import numpy as np |
|
|
from sentence_transformers import SentenceTransformer |
|
|
import json |
|
|
|
|
|
|
|
|
MODEL_NAME = 'all-mpnet-base-v2' |
|
|
MIN_SIMILARITY_THRESHOLD = 0.5 |
|
|
TOP_K_RESULTS = 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
songs_metadata = [ |
|
|
{ |
|
|
"title": "Rise Up", |
|
|
"artist": "Andra Day", |
|
|
"lyrics": "You're broken down and tired, Of living life on a merry go round...", |
|
|
"spotify_url": "https://open.spotify.com/track/4fSlpKIGm3xa5Q0h7r0qVL" |
|
|
}, |
|
|
{ |
|
|
"title": "Stronger", |
|
|
"artist": "Kelly Clarkson", |
|
|
"lyrics": "What doesn't kill you makes you stronger...", |
|
|
"spotify_url": "https://open.spotify.com/track/0WqIKmW4BTrj3eJFmnCKMv" |
|
|
}, |
|
|
{ |
|
|
"title": "Fight Song", |
|
|
"artist": "Rachel Platten", |
|
|
"lyrics": "This is my fight song, Take back my life song...", |
|
|
"spotify_url": "https://open.spotify.com/track/4PXLm6TfjCvQsn9PkW78eN" |
|
|
} |
|
|
] |
|
|
|
|
|
|
|
|
print("Loading sentence transformer model...") |
|
|
model = SentenceTransformer(MODEL_NAME) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
print("Computing embeddings for demo songs...") |
|
|
demo_lyrics = [song['lyrics'] for song in songs_metadata] |
|
|
song_embeddings = model.encode(demo_lyrics, convert_to_numpy=True) |
|
|
song_embeddings = song_embeddings / np.linalg.norm(song_embeddings, axis=1, keepdims=True) |
|
|
|
|
|
|
|
|
def search_songs(query: str) -> list: |
|
|
""" |
|
|
Perform semantic search on song lyrics |
|
|
|
|
|
Args: |
|
|
query: Text description of desired song characteristics |
|
|
|
|
|
Returns: |
|
|
List of matching songs with similarity scores |
|
|
""" |
|
|
if not query or not query.strip(): |
|
|
return [] |
|
|
|
|
|
try: |
|
|
|
|
|
query_embedding = model.encode([query], convert_to_numpy=True) |
|
|
query_embedding = query_embedding / np.linalg.norm(query_embedding, axis=1, keepdims=True) |
|
|
|
|
|
|
|
|
similarities = np.dot(song_embeddings, query_embedding.T).flatten() |
|
|
|
|
|
|
|
|
top_indices = np.argsort(similarities)[::-1][:TOP_K_RESULTS] |
|
|
|
|
|
|
|
|
results = [] |
|
|
for idx in top_indices: |
|
|
similarity = float(similarities[idx]) |
|
|
|
|
|
|
|
|
if similarity >= MIN_SIMILARITY_THRESHOLD: |
|
|
song = songs_metadata[idx] |
|
|
results.append({ |
|
|
"title": song['title'], |
|
|
"artist": song['artist'], |
|
|
"similarity": similarity, |
|
|
"spotifyUrl": song.get('spotify_url', '') |
|
|
}) |
|
|
|
|
|
return results |
|
|
|
|
|
except Exception as e: |
|
|
print(f"Error during search: {str(e)}") |
|
|
return [] |
|
|
|
|
|
|
|
|
def gradio_search(query: str) -> str: |
|
|
"""Wrapper function for Gradio that returns JSON string""" |
|
|
results = search_songs(query) |
|
|
return json.dumps(results, indent=2) |
|
|
|
|
|
|
|
|
demo = gr.Interface( |
|
|
fn=gradio_search, |
|
|
inputs=gr.Textbox( |
|
|
label="Search Query", |
|
|
placeholder="Describe the song you're looking for...", |
|
|
lines=3 |
|
|
), |
|
|
outputs=gr.JSON(label="Search Results"), |
|
|
title="🎵 HarmoniFind Backend", |
|
|
description=f""" |
|
|
Semantic music search powered by {MODEL_NAME} embeddings. |
|
|
|
|
|
**Current Settings:** |
|
|
- Minimum Similarity: {MIN_SIMILARITY_THRESHOLD * 100}% |
|
|
- Top Results: {TOP_K_RESULTS} |
|
|
- Dataset: {len(songs_metadata)} songs |
|
|
|
|
|
Enter a description of lyrical themes, emotions, or narratives to find matching songs. |
|
|
""", |
|
|
examples=[ |
|
|
["Uplifting song about overcoming personal challenges"], |
|
|
["Melancholic love song with introspective narrative"], |
|
|
["Energetic anthem about friendship and loyalty"], |
|
|
["Reflective song about life transitions and growth"], |
|
|
], |
|
|
api_name="predict" |
|
|
) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
demo.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=7860, |
|
|
share=False |
|
|
) |