Update app.py
Browse files
app.py
CHANGED
|
@@ -2,59 +2,67 @@ import streamlit as st
|
|
| 2 |
import pandas as pd
|
| 3 |
from sklearn.preprocessing import StandardScaler
|
| 4 |
from sklearn.neighbors import NearestNeighbors
|
| 5 |
-
from thefuzz import process
|
| 6 |
|
| 7 |
-
st.set_page_config(page_title="DNA Sonoro:
|
| 8 |
-
st.title("🧬 DNA Sonoro:
|
| 9 |
|
| 10 |
-
# Função para carregar o arquivo que você subiu
|
| 11 |
@st.cache_data
|
| 12 |
-
def
|
| 13 |
-
# Lendo o arquivo de 346MB que você acabou de subir
|
| 14 |
df = pd.read_csv("tracks_features.csv")
|
| 15 |
-
#
|
| 16 |
df = df[['name', 'artists', 'danceability', 'energy', 'acousticness', 'instrumentalness', 'valence', 'tempo']].dropna()
|
| 17 |
-
|
| 18 |
-
df['
|
|
|
|
| 19 |
return df
|
| 20 |
|
| 21 |
try:
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
# Preparando o motor matemático
|
| 26 |
features = ['danceability', 'energy', 'acousticness', 'instrumentalness', 'valence', 'tempo']
|
| 27 |
scaler = StandardScaler()
|
| 28 |
df_scaled = scaler.fit_transform(df[features])
|
| 29 |
-
|
| 30 |
-
model = NearestNeighbors(n_neighbors=7, metric='cosine')
|
| 31 |
model.fit(df_scaled)
|
| 32 |
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
-
if
|
| 36 |
-
# Busca
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
best_match = process.extractOne(query, choices)
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
track = df.iloc[idx]
|
|
|
|
| 44 |
|
| 45 |
-
|
| 46 |
-
|
| 47 |
distances, indices = model.kneighbors([df_scaled[idx]])
|
| 48 |
|
| 49 |
-
st.subheader("💡 Recomendações
|
| 50 |
for i in indices[0]:
|
| 51 |
if i != idx:
|
| 52 |
res = df.iloc[i]
|
| 53 |
st.write(f"✨ **{res['name']}** — {res['artists']}")
|
| 54 |
simil = int((1 - distances[0][list(indices[0]).index(i)]) * 100)
|
| 55 |
-
st.caption(f"
|
| 56 |
else:
|
| 57 |
-
st.
|
| 58 |
|
| 59 |
except Exception as e:
|
| 60 |
-
st.error(f"Erro
|
|
|
|
| 2 |
import pandas as pd
|
| 3 |
from sklearn.preprocessing import StandardScaler
|
| 4 |
from sklearn.neighbors import NearestNeighbors
|
|
|
|
| 5 |
|
| 6 |
+
st.set_page_config(page_title="DNA Sonoro: Filtro de Elite", page_icon="🧬")
|
| 7 |
+
st.title("🧬 DNA Sonoro: Precisão Máxima")
|
| 8 |
|
|
|
|
| 9 |
@st.cache_data
|
| 10 |
+
def carregar_dados():
|
|
|
|
| 11 |
df = pd.read_csv("tracks_features.csv")
|
| 12 |
+
# Mantendo apenas o essencial para não fritar a memória
|
| 13 |
df = df[['name', 'artists', 'danceability', 'energy', 'acousticness', 'instrumentalness', 'valence', 'tempo']].dropna()
|
| 14 |
+
# Limpeza de strings para busca não falhar por causa de espaço ou letra maiúscula
|
| 15 |
+
df['name_clean'] = df['name'].str.lower().str.strip()
|
| 16 |
+
df['artists_clean'] = df['artists'].str.lower().str.strip()
|
| 17 |
return df
|
| 18 |
|
| 19 |
try:
|
| 20 |
+
df = carregar_dados()
|
| 21 |
+
|
| 22 |
+
# Motor matemático
|
|
|
|
| 23 |
features = ['danceability', 'energy', 'acousticness', 'instrumentalness', 'valence', 'tempo']
|
| 24 |
scaler = StandardScaler()
|
| 25 |
df_scaled = scaler.fit_transform(df[features])
|
| 26 |
+
model = NearestNeighbors(n_neighbors=11, metric='cosine')
|
|
|
|
| 27 |
model.fit(df_scaled)
|
| 28 |
|
| 29 |
+
st.markdown("### 🔎 Busca Refinada")
|
| 30 |
+
col1, col2 = st.columns(2)
|
| 31 |
+
with col1:
|
| 32 |
+
musica_input = st.text_input("Nome da música:", placeholder="Ex: Spring Day")
|
| 33 |
+
with col2:
|
| 34 |
+
artista_input = st.text_input("Nome do artista (Opcional):", placeholder="Ex: BTS")
|
| 35 |
|
| 36 |
+
if musica_input:
|
| 37 |
+
# Busca exata ou parcial mas rigorosa
|
| 38 |
+
termo_musica = musica_input.lower().strip()
|
| 39 |
+
termo_artista = artista_input.lower().strip() if artista_input else ""
|
|
|
|
| 40 |
|
| 41 |
+
# Filtro direto no DataFrame (mais rápido e preciso que o Fuzzy para 1M de linhas)
|
| 42 |
+
if termo_artista:
|
| 43 |
+
match = df[(df['name_clean'].str.contains(termo_musica)) & (df['artists_clean'].str.contains(termo_artista))]
|
| 44 |
+
else:
|
| 45 |
+
match = df[df['name_clean'] == termo_musica]
|
| 46 |
+
if match.empty:
|
| 47 |
+
match = df[df['name_clean'].str.contains(termo_musica)].head(1)
|
| 48 |
+
|
| 49 |
+
if not match.empty:
|
| 50 |
+
idx = match.index[0]
|
| 51 |
track = df.iloc[idx]
|
| 52 |
+
st.success(f"🎯 **Identificada:** {track['name']} — {track['artists']}")
|
| 53 |
|
| 54 |
+
# Cálculo da vibe
|
|
|
|
| 55 |
distances, indices = model.kneighbors([df_scaled[idx]])
|
| 56 |
|
| 57 |
+
st.subheader("💡 Recomendações com DNA idêntico:")
|
| 58 |
for i in indices[0]:
|
| 59 |
if i != idx:
|
| 60 |
res = df.iloc[i]
|
| 61 |
st.write(f"✨ **{res['name']}** — {res['artists']}")
|
| 62 |
simil = int((1 - distances[0][list(indices[0]).index(i)]) * 100)
|
| 63 |
+
st.caption(f"Compatibilidade: {simil}%")
|
| 64 |
else:
|
| 65 |
+
st.error("Não achei essa combinação na base. Tente apenas uma palavra-chave da música.")
|
| 66 |
|
| 67 |
except Exception as e:
|
| 68 |
+
st.error(f"Erro no motor: {e}")
|