diff --git a/.gitignore b/.gitignore index d7bfd42..cb37056 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,4 @@ htmlcov/ .AppleDouble .LSOverride ._* +nul diff --git a/backend/src/core/essentia_classifier.py b/backend/src/core/essentia_classifier.py index 919c54d..8e52396 100644 --- a/backend/src/core/essentia_classifier.py +++ b/backend/src/core/essentia_classifier.py @@ -1,5 +1,6 @@ """Music classification using Essentia-TensorFlow models.""" import os +import json from pathlib import Path from typing import Dict, List, Optional import numpy as np @@ -28,7 +29,7 @@ class EssentiaClassifier: # Model URLs (for documentation) MODEL_URLS = { - "genre": "https://essentia.upf.edu/models/classification-heads/mtg_jamendo_genre/mtg_jamendo_genre-discogs-effnet-1.pb", + "genre": "https://essentia.upf.edu/models/classification-heads/genre_discogs400/genre_discogs400-discogs-effnet-1.pb", "mood": "https://essentia.upf.edu/models/classification-heads/mtg_jamendo_moodtheme/mtg_jamendo_moodtheme-discogs-effnet-1.pb", "instrument": "https://essentia.upf.edu/models/classification-heads/mtg_jamendo_instrument/mtg_jamendo_instrument-discogs-effnet-1.pb", } @@ -68,7 +69,7 @@ class EssentiaClassifier: # Model file names for classification heads model_files = { - "genre": "mtg_jamendo_genre-discogs-effnet-1.pb", + "genre": "genre_discogs400-discogs-effnet-1.pb", "mood": "mtg_jamendo_moodtheme-discogs-effnet-1.pb", "instrument": "mtg_jamendo_instrument-discogs-effnet-1.pb", } @@ -90,21 +91,20 @@ class EssentiaClassifier: def _load_class_labels(self) -> None: """Load class labels for models.""" - # These are the actual class labels from MTG-Jamendo dataset - # In production, these should be loaded from JSON files - - self.class_labels["genre"] = [ - "rock", "pop", "alternative", "indie", "electronic", - "female vocalists", "dance", "00s", "alternative rock", "jazz", - "beautiful", "metal", "chillout", "male vocalists", "classic rock", - "soul", "indie rock", "Mellow", "electronica", "80s", - "folk", "90s", "chill", "instrumental", "punk", - "oldies", "blues", "hard rock", "ambient", "acoustic", - "experimental", "female vocalist", "guitar", "Hip-Hop", "70s", - "party", "country", "easy listening", "sexy", "catchy", - "funk", "electro", "heavy metal", "Progressive rock", "60s", - "rnb", "indie pop", "sad", "House", "happy" - ] + # Load genre labels from Discogs400 JSON file + genre_json_path = self.models_path / "genre_discogs400-discogs-effnet-1.json" + if genre_json_path.exists(): + try: + with open(genre_json_path, 'r', encoding='utf-8') as f: + genre_metadata = json.load(f) + self.class_labels["genre"] = genre_metadata.get("classes", []) + logger.info(f"Loaded {len(self.class_labels['genre'])} genre labels from JSON") + except Exception as e: + logger.error(f"Failed to load genre labels from JSON: {e}") + self.class_labels["genre"] = [] + else: + logger.warning(f"Genre labels JSON not found: {genre_json_path}") + self.class_labels["genre"] = [] self.class_labels["mood"] = [ "action", "adventure", "advertising", "background", "ballad", @@ -159,10 +159,11 @@ class EssentiaClassifier: embeddings_mean = np.mean(embeddings, axis=0) # Step 2: Feed embeddings to classification head + # Discogs400 uses different node names than MTG-Jamendo classifier = TensorflowPredict2D( graphFilename=self.models["genre"], - input="model/Placeholder", - output="model/Sigmoid" + input="serving_default_model_Placeholder", + output="PartitionedCall:0" ) predictions = classifier(embeddings_mean.reshape(1, -1)) predictions = predictions[0] # Remove batch dimension diff --git a/scripts/download-essentia-models.sh b/scripts/download-essentia-models.sh index 23a7e3b..9d94cd7 100755 --- a/scripts/download-essentia-models.sh +++ b/scripts/download-essentia-models.sh @@ -47,9 +47,15 @@ download_model "discogs-effnet-bs64-1.pb" \ # Download classification heads echo "" echo "Downloading classification heads..." -download_model "mtg_jamendo_genre-discogs-effnet-1.pb" \ - "$CLASS_HEADS_URL/mtg_jamendo_genre/mtg_jamendo_genre-discogs-effnet-1.pb" +# Genre: Discogs400 (professional taxonomy with 400 genres) +download_model "genre_discogs400-discogs-effnet-1.pb" \ + "$CLASS_HEADS_URL/genre_discogs400/genre_discogs400-discogs-effnet-1.pb" + +download_model "genre_discogs400-discogs-effnet-1.json" \ + "$CLASS_HEADS_URL/genre_discogs400/genre_discogs400-discogs-effnet-1.json" + +# Mood & Instrument: MTG-Jamendo download_model "mtg_jamendo_moodtheme-discogs-effnet-1.pb" \ "$CLASS_HEADS_URL/mtg_jamendo_moodtheme/mtg_jamendo_moodtheme-discogs-effnet-1.pb"