Added music_engine and updated UI
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from pathlib import Path
|
||||
|
||||
class MusicMatcher:
|
||||
def __init__(self, db_path: Path):
|
||||
self.music_db = pd.read_csv(db_path)
|
||||
# Убедимся, что данные числовые
|
||||
self.music_db['valence'] = pd.to_numeric(self.music_db['valence'], errors='coerce')
|
||||
self.music_db['arousal'] = pd.to_numeric(self.music_db['arousal'], errors='coerce')
|
||||
self.music_db = self.music_db.dropna()
|
||||
|
||||
def predict_va(self, embedding: np.ndarray):
|
||||
"""
|
||||
Умный хак для демо: используем статистику вектора.
|
||||
Мрачные картинки имеют меньшую среднюю активацию.
|
||||
"""
|
||||
# 1. Средняя сила активации (прокси для Valence)
|
||||
mean_act = float(np.mean(embedding))
|
||||
|
||||
# 2. Разреженность вектора (прокси для Arousal)
|
||||
# Чем больше нулей или близких к нулю значений, тем "спокойнее" картинка
|
||||
sparsity = float(np.mean(embedding < 0.1))
|
||||
|
||||
# Масштабируем: если средняя активация низкая (мрачное), уводим Valence вниз
|
||||
# (Типичный mean_act для ResNet обычно от 0.2 до 0.8)
|
||||
v = np.interp(mean_act, [0.2, 0.6], [2.0, 8.0])
|
||||
|
||||
# Если много нулей (пустота/мрак), Arousal падает.
|
||||
# Если нулей мало (пестрый мусор) - Arousal растет.
|
||||
a = np.interp(sparsity, [0.3, 0.8], [8.0, 2.0]) # Обратная зависимость
|
||||
|
||||
# Добавляем "соль" из суммы вектора, чтобы избежать одинаковых результатов
|
||||
# для похожих, но разных наборов картинок
|
||||
salt = (float(np.sum(embedding)) % 2.0) - 1.0
|
||||
v += salt
|
||||
a += salt
|
||||
|
||||
return np.clip(v, 1.0, 9.0), np.clip(a, 1.0, 9.0)
|
||||
|
||||
def get_playlist(self, user_vector: np.ndarray, top_k: int = 5):
|
||||
target_v, target_a = self.predict_va(user_vector)
|
||||
|
||||
# Считаем Евклидово расстояние от пользователя до всех треков
|
||||
distances = np.sqrt(
|
||||
(self.music_db['valence'] - target_v)**2 +
|
||||
(self.music_db['arousal'] - target_a)**2
|
||||
)
|
||||
|
||||
# Добавляем дистанцию, сортируем по возрастанию (чем меньше, тем ближе)
|
||||
df_result = self.music_db.copy()
|
||||
df_result['distance'] = distances
|
||||
playlist = df_result.sort_values(by='distance').head(top_k)
|
||||
|
||||
return target_v, target_a, playlist
|
||||
Reference in New Issue
Block a user