Compare commits
8 Commits
2a0d022e37
...
prochains-
| Author | SHA1 | Date | |
|---|---|---|---|
| 04603cd5e9 | |||
| cc2f1d0051 | |||
| 169a759b57 | |||
| 88db8cc9c8 | |||
| 3e225b158f | |||
| 8ec8b1aa42 | |||
| e3d85f4775 | |||
| df781fb605 |
264
.claude-todo.md
264
.claude-todo.md
@@ -1,264 +0,0 @@
|
||||
# Audio Classifier - TODO Mise à Jour (6 décembre 2024)
|
||||
|
||||
## ✅ Ce qui est FAIT (État actuel du projet)
|
||||
|
||||
### Infrastructure
|
||||
- ✅ Structure complète backend + frontend
|
||||
- ✅ Docker Compose avec PostgreSQL + pgvector
|
||||
- ✅ Backend Dockerfile (Python 3.9, émulation x86_64 pour Essentia)
|
||||
- ✅ Frontend Dockerfile
|
||||
- ✅ Containers en production (running actuellement)
|
||||
- ✅ .env et .env.example configurés
|
||||
- ✅ Modèles Essentia téléchargés (genre, mood, instrument)
|
||||
|
||||
### Backend (Python/FastAPI)
|
||||
- ✅ Structure complète src/
|
||||
- ✅ Modèles SQLAlchemy (schema.py) avec AudioTrack
|
||||
- ✅ Migrations Alembic fonctionnelles
|
||||
- ✅ CRUD complet (crud.py)
|
||||
- ✅ API FastAPI (main.py)
|
||||
- ✅ Routes implémentées :
|
||||
- ✅ /api/tracks (GET, DELETE)
|
||||
- ✅ /api/search
|
||||
- ✅ /api/audio (stream, download, waveform)
|
||||
- ✅ /api/analyze
|
||||
- ✅ /api/similar
|
||||
- ✅ /api/stats
|
||||
- ✅ Core modules :
|
||||
- ✅ audio_processor.py (Librosa)
|
||||
- ✅ essentia_classifier.py (modèles genre/mood/instruments)
|
||||
- ✅ analyzer.py (orchestrateur)
|
||||
- ✅ file_scanner.py
|
||||
- ✅ waveform_generator.py
|
||||
- ✅ Utils (config, logging, validators)
|
||||
- ✅ CLI scanner fonctionnel
|
||||
|
||||
### Frontend (Next.js 14)
|
||||
- ✅ Structure Next.js 14 avec TypeScript
|
||||
- ✅ TailwindCSS + shadcn/ui setup
|
||||
- ✅ API client (lib/api.ts)
|
||||
- ✅ Types TypeScript (lib/types.ts)
|
||||
- ✅ QueryProvider configuré
|
||||
- ✅ Layout principal
|
||||
- ✅ Page principale (app/page.tsx)
|
||||
|
||||
### Documentation
|
||||
- ✅ README.md complet
|
||||
- ✅ QUICKSTART.md
|
||||
- ✅ SETUP.md
|
||||
- ✅ STATUS.md
|
||||
- ✅ COMMANDES.md
|
||||
- ✅ DOCKER.md
|
||||
- ✅ ESSENTIA.md
|
||||
- ✅ CORRECTIONS.md
|
||||
- ✅ RESUME.md
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Ce qui reste À FAIRE
|
||||
|
||||
### Phase 1: Finaliser Docker pour Mac ARM
|
||||
|
||||
#### 1.1 Docker Build Optimization
|
||||
- [ ] **Finir le build Docker backend** (actuellement timeout à 10min)
|
||||
- Build en cours mais très lent (émulation x86_64)
|
||||
- Options :
|
||||
- [ ] Option A : Augmenter timeout et laisser finir (15-20 min estimé)
|
||||
- [ ] Option B : Build natif ARM64 en compilant Essentia depuis sources
|
||||
- [ ] Option C : Utiliser image multi-arch existante (mgoltzsche/essentia-container)
|
||||
- [ ] Tester le container backend une fois buildé
|
||||
- [ ] Vérifier que Essentia fonctionne correctement dans le container
|
||||
- [ ] Documenter temps de build et performances
|
||||
|
||||
#### 1.2 Docker Compose Validation
|
||||
- [ ] Tester docker-compose up complet
|
||||
- [ ] Vérifier connectivité DB ↔ Backend
|
||||
- [ ] Vérifier connectivité Frontend ↔ Backend
|
||||
- [ ] Tester les 3 services ensemble
|
||||
|
||||
---
|
||||
|
||||
### Phase 2: Frontend Components (PRIORITAIRE)
|
||||
|
||||
Le frontend a la structure mais manque les composants UI. **C'est la priorité #1.**
|
||||
|
||||
#### 2.1 Composants de base manquants
|
||||
- [ ] `components/SearchBar.tsx`
|
||||
- [ ] `components/FilterPanel.tsx`
|
||||
- [ ] `components/TrackCard.tsx`
|
||||
- [ ] `components/TrackDetails.tsx` (Modal)
|
||||
- [ ] `components/AudioPlayer.tsx`
|
||||
- [ ] `components/WaveformDisplay.tsx`
|
||||
- [ ] `components/BatchScanner.tsx`
|
||||
- [ ] `components/SimilarTracks.tsx`
|
||||
|
||||
#### 2.2 Hooks manquants
|
||||
- [ ] `hooks/useSearch.ts` (recherche avec debounce)
|
||||
- [ ] `hooks/useTracks.ts` (fetch + pagination)
|
||||
- [ ] `hooks/useAudioPlayer.ts` (state audio player)
|
||||
|
||||
#### 2.3 Pages manquantes
|
||||
- [ ] `app/tracks/[id]/page.tsx` (page détail track)
|
||||
|
||||
#### 2.4 Installation shadcn components
|
||||
- [ ] Installer composants shadcn manquants :
|
||||
```bash
|
||||
npx shadcn@latest add button input slider select card dialog badge progress toast dropdown-menu tabs
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Phase 3: Tests & Validation
|
||||
|
||||
#### 3.1 Tests Backend
|
||||
- [ ] Tester analyse d'un fichier audio réel
|
||||
- [ ] Tester scanner CLI sur un dossier
|
||||
- [ ] Vérifier classifications Essentia (genre/mood)
|
||||
- [ ] Tester endpoints API avec curl/Postman
|
||||
- [ ] Vérifier waveform generation
|
||||
|
||||
#### 3.2 Tests Frontend
|
||||
- [ ] Tester affichage liste tracks
|
||||
- [ ] Tester recherche et filtres
|
||||
- [ ] Tester lecture audio
|
||||
- [ ] Tester waveform display
|
||||
- [ ] Tester scanner de dossier
|
||||
- [ ] Tester navigation
|
||||
|
||||
#### 3.3 Tests End-to-End
|
||||
- [ ] Flow complet : Scanner dossier → Voir résultats → Jouer track → Chercher similaires
|
||||
- [ ] Tester avec bibliothèque réelle (>100 fichiers)
|
||||
- [ ] Vérifier performances
|
||||
|
||||
---
|
||||
|
||||
### Phase 4: Optimisations & Polish
|
||||
|
||||
#### 4.1 Performance
|
||||
- [ ] Optimiser temps de build Docker (si nécessaire)
|
||||
- [ ] Cache waveform peaks
|
||||
- [ ] Optimiser requêtes DB (indexes)
|
||||
- [ ] Lazy loading tracks (pagination infinie)
|
||||
|
||||
#### 4.2 UX
|
||||
- [ ] Loading skeletons
|
||||
- [ ] Error boundaries
|
||||
- [ ] Toast notifications
|
||||
- [ ] Keyboard shortcuts (espace = play/pause)
|
||||
- [ ] Dark mode support
|
||||
|
||||
#### 4.3 Backend improvements
|
||||
- [ ] Rate limiting API
|
||||
- [ ] Structured logging
|
||||
- [ ] Error handling middleware
|
||||
- [ ] Health checks détaillés
|
||||
|
||||
---
|
||||
|
||||
### Phase 5: Features additionnelles (Nice-to-have)
|
||||
|
||||
#### 5.1 Features manquantes du plan original
|
||||
- [ ] Batch export (CSV/JSON)
|
||||
- [ ] Playlists
|
||||
- [ ] Duplicate detection
|
||||
- [ ] Tag editing
|
||||
- [ ] Visualisations avancées (spectrogram)
|
||||
|
||||
#### 5.2 Embeddings CLAP (Future)
|
||||
- [ ] Intégration CLAP pour semantic search
|
||||
- [ ] Utiliser pgvector pour similarity search
|
||||
- [ ] API endpoint pour recherche sémantique
|
||||
|
||||
#### 5.3 Multi-user (Future)
|
||||
- [ ] Authentication JWT
|
||||
- [ ] User management
|
||||
- [ ] Permissions
|
||||
|
||||
---
|
||||
|
||||
## 🎯 ROADMAP RECOMMANDÉE
|
||||
|
||||
### Sprint 1 (Cette semaine) - MINIMUM VIABLE PRODUCT
|
||||
1. ✅ ~~Finaliser Docker setup~~
|
||||
2. **Créer composants frontend de base** (SearchBar, TrackCard, AudioPlayer)
|
||||
3. **Créer hooks frontend** (useTracks, useAudioPlayer)
|
||||
4. **Page principale fonctionnelle** avec liste + lecture
|
||||
5. **Tester flow complet** avec fichiers audio réels
|
||||
|
||||
### Sprint 2 (Semaine prochaine) - FEATURES COMPLÈTES
|
||||
1. Composants avancés (FilterPanel, BatchScanner, SimilarTracks)
|
||||
2. Page détail track
|
||||
3. Optimisations performance
|
||||
4. Polish UX (loading states, errors, toasts)
|
||||
|
||||
### Sprint 3 (Après) - POLISH & EXTRAS
|
||||
1. Dark mode
|
||||
2. Keyboard shortcuts
|
||||
3. Export data
|
||||
4. Documentation finale
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notes Importantes
|
||||
|
||||
### Docker Build sur Mac ARM
|
||||
- **Problème actuel** : Build très lent (10+ min) car Essentia nécessite émulation x86_64
|
||||
- **Solution actuelle** : `FROM --platform=linux/amd64 python:3.9-slim` dans Dockerfile
|
||||
- **Performance** : Runtime sera aussi émulé (plus lent mais fonctionnel)
|
||||
- **Alternative** : Compiler Essentia pour ARM64 (complexe, long)
|
||||
|
||||
### Priorités
|
||||
1. **Frontend components** → Rendre l'app utilisable
|
||||
2. **Tests avec vraie data** → Valider que tout fonctionne
|
||||
3. **Polish UX** → Rendre l'app agréable
|
||||
|
||||
### État actuel
|
||||
- ✅ Backend 95% complet et fonctionnel
|
||||
- ⚠️ Frontend 30% complet (structure ok, UI manquante)
|
||||
- ⚠️ Docker 90% (backend build en cours)
|
||||
- ✅ Documentation excellente
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Commandes Utiles
|
||||
|
||||
### Docker
|
||||
```bash
|
||||
# Build (peut prendre 15-20 min sur Mac ARM)
|
||||
docker-compose build
|
||||
|
||||
# Démarrer
|
||||
docker-compose up
|
||||
|
||||
# Logs
|
||||
docker-compose logs -f backend
|
||||
|
||||
# Scanner un dossier
|
||||
docker exec audio_classifier_api python -m src.cli.scanner /music --recursive
|
||||
```
|
||||
|
||||
### Dev Local
|
||||
```bash
|
||||
# Backend
|
||||
cd backend
|
||||
pip install -r requirements.txt
|
||||
uvicorn src.api.main:app --reload
|
||||
|
||||
# Frontend
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ Prochaine étape immédiate
|
||||
|
||||
**CRÉER LES COMPOSANTS FRONTEND** pour avoir une interface utilisable.
|
||||
|
||||
Ordre suggéré :
|
||||
1. TrackCard (afficher les tracks)
|
||||
2. AudioPlayer (jouer les tracks)
|
||||
3. SearchBar + FilterPanel (recherche)
|
||||
4. BatchScanner (scanner des dossiers)
|
||||
5. TrackDetails + SimilarTracks (features avancées)
|
||||
@@ -9,7 +9,9 @@
|
||||
"Bash(bash scripts/download-essentia-models.sh:*)",
|
||||
"Bash(curl:*)",
|
||||
"Bash(docker logs:*)",
|
||||
"Bash(docker exec:*)"
|
||||
"Bash(docker exec:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(docker build:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ POSTGRES_PASSWORD=audio_password
|
||||
POSTGRES_DB=audio_classifier
|
||||
|
||||
# Backend API
|
||||
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
|
||||
# Use "*" to allow all origins (recommended for development/local deployment)
|
||||
# Or specify comma-separated URLs for production: http://yourdomain.com,https://yourdomain.com
|
||||
CORS_ORIGINS=*
|
||||
API_HOST=0.0.0.0
|
||||
API_PORT=8000
|
||||
|
||||
@@ -16,4 +18,7 @@ ESSENTIA_MODELS_PATH=/app/models
|
||||
AUDIO_LIBRARY_PATH=/path/to/your/audio/library
|
||||
|
||||
# Frontend
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
||||
# API URL accessed by the browser (use port 8001 since backend is mapped to 8001)
|
||||
# For production on a remote server, set this to your server's public URL
|
||||
# Example: NEXT_PUBLIC_API_URL=http://yourserver.com:8001
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8001
|
||||
|
||||
@@ -13,60 +13,6 @@ env:
|
||||
IMAGE_FRONTEND: audio-classifier-frontend
|
||||
|
||||
jobs:
|
||||
build-backend:
|
||||
name: Build Backend Image
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Gitea Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ gitea.actor }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
|
||||
- name: Determine version
|
||||
id: version
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "VERSION=dev-$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_BACKEND }}
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=sha,prefix=dev-,format=short,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: Build and push backend
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./backend/Dockerfile
|
||||
push: true
|
||||
build-args: |
|
||||
VERSION=${{ steps.version.outputs.VERSION }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_BACKEND }}:buildcache
|
||||
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ gitea.repository_owner }}/${{ env.IMAGE_BACKEND }}:buildcache,mode=max
|
||||
|
||||
build-frontend:
|
||||
name: Build Frontend Image
|
||||
runs-on: ubuntu-latest
|
||||
@@ -77,6 +23,25 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Download Essentia models (for context)
|
||||
run: |
|
||||
mkdir -p backend/models
|
||||
cd backend/models
|
||||
|
||||
# Download models (needed because frontend build context is root)
|
||||
curl -L -o discogs-effnet-bs64-1.pb \
|
||||
https://essentia.upf.edu/models/feature-extractors/discogs-effnet/discogs-effnet-bs64-1.pb
|
||||
curl -L -o genre_discogs400-discogs-effnet-1.pb \
|
||||
https://essentia.upf.edu/models/classification-heads/genre_discogs400/genre_discogs400-discogs-effnet-1.pb
|
||||
curl -L -o genre_discogs400-discogs-effnet-1.json \
|
||||
https://essentia.upf.edu/models/classification-heads/genre_discogs400/genre_discogs400-discogs-effnet-1.json
|
||||
curl -L -o mtg_jamendo_moodtheme-discogs-effnet-1.pb \
|
||||
https://essentia.upf.edu/models/classification-heads/mtg_jamendo_moodtheme/mtg_jamendo_moodtheme-discogs-effnet-1.pb
|
||||
curl -L -o mtg_jamendo_instrument-discogs-effnet-1.pb \
|
||||
https://essentia.upf.edu/models/classification-heads/mtg_jamendo_instrument/mtg_jamendo_instrument-discogs-effnet-1.pb
|
||||
curl -L -o mtg_jamendo_genre-discogs-effnet-1.pb \
|
||||
https://essentia.upf.edu/models/classification-heads/mtg_jamendo_genre/mtg_jamendo_genre-discogs-effnet-1.pb
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
@@ -90,8 +55,8 @@ jobs:
|
||||
- name: Determine version
|
||||
id: version
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
if [[ "${{ gitea.ref }}" == refs/tags/v* ]]; then
|
||||
echo "VERSION=${GITEA_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "VERSION=dev-$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
@@ -104,9 +69,9 @@ jobs:
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=sha,prefix=dev-,format=short,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
type=raw,value=latest,enable=${{ startsWith(gitea.ref, 'refs/tags/v') }}
|
||||
type=raw,value=dev,enable=${{ gitea.ref == 'refs/heads/main' }}
|
||||
type=sha,prefix=dev-,format=short,enable=${{ gitea.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: Build and push frontend
|
||||
uses: docker/build-push-action@v5
|
||||
|
||||
317
COMMANDES.md
317
COMMANDES.md
@@ -1,317 +0,0 @@
|
||||
# 📝 Commandes Essentielles - Audio Classifier
|
||||
|
||||
## 🚀 Démarrage
|
||||
|
||||
### Lancer tous les services
|
||||
```bash
|
||||
cd "/Users/benoit/Documents/code/Audio Classifier"
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
### Vérifier le statut
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml ps
|
||||
docker-compose -f docker-compose.dev.yml logs -f backend
|
||||
```
|
||||
|
||||
### Lancer le frontend
|
||||
```bash
|
||||
cd frontend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 🔍 Vérifications
|
||||
|
||||
### Health check
|
||||
```bash
|
||||
curl http://localhost:8001/health
|
||||
```
|
||||
|
||||
### Stats base de données
|
||||
```bash
|
||||
curl http://localhost:8001/api/stats | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Liste des pistes
|
||||
```bash
|
||||
curl http://localhost:8001/api/tracks?limit=5 | python3 -m json.tool
|
||||
```
|
||||
|
||||
## 🎵 Analyse audio
|
||||
|
||||
### Analyser un dossier
|
||||
```bash
|
||||
curl -X POST http://localhost:8001/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"path": "/audio",
|
||||
"recursive": true
|
||||
}'
|
||||
```
|
||||
|
||||
Retourne un `job_id`
|
||||
|
||||
### Vérifier la progression
|
||||
```bash
|
||||
# Remplacer JOB_ID par l'ID retourné
|
||||
curl http://localhost:8001/api/analyze/status/JOB_ID | python3 -m json.tool
|
||||
```
|
||||
|
||||
## 🔎 Recherche
|
||||
|
||||
### Recherche textuelle
|
||||
```bash
|
||||
curl "http://localhost:8001/api/search?q=jazz&limit=10" | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Filtrer par BPM
|
||||
```bash
|
||||
curl "http://localhost:8001/api/tracks?bpm_min=120&bpm_max=140&limit=20" | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Filtrer par genre
|
||||
```bash
|
||||
curl "http://localhost:8001/api/tracks?genre=electronic&limit=10" | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Filtrer par énergie
|
||||
```bash
|
||||
curl "http://localhost:8001/api/tracks?energy_min=0.7&limit=10" | python3 -m json.tool
|
||||
```
|
||||
|
||||
## 🎧 Audio
|
||||
|
||||
### Stream (dans navigateur)
|
||||
```bash
|
||||
# Récupérer un track_id d'abord
|
||||
TRACK_ID=$(curl -s "http://localhost:8001/api/tracks?limit=1" | python3 -c "import sys, json; print(json.load(sys.stdin)['tracks'][0]['id'])")
|
||||
|
||||
# Ouvrir dans navigateur
|
||||
open "http://localhost:8001/api/audio/stream/$TRACK_ID"
|
||||
```
|
||||
|
||||
### Download
|
||||
```bash
|
||||
curl -o music.mp3 "http://localhost:8001/api/audio/download/$TRACK_ID"
|
||||
```
|
||||
|
||||
### Waveform data
|
||||
```bash
|
||||
curl "http://localhost:8001/api/audio/waveform/$TRACK_ID" | python3 -m json.tool
|
||||
```
|
||||
|
||||
## 🗄️ Base de données
|
||||
|
||||
### Connexion psql
|
||||
```bash
|
||||
docker exec -it audio_classifier_db psql -U audio_user -d audio_classifier
|
||||
```
|
||||
|
||||
### Queries utiles
|
||||
```sql
|
||||
-- Nombre total de pistes
|
||||
SELECT COUNT(*) FROM audio_tracks;
|
||||
|
||||
-- 10 dernières pistes analysées
|
||||
SELECT filename, tempo_bpm, key, genre_primary, mood_primary, analyzed_at
|
||||
FROM audio_tracks
|
||||
ORDER BY analyzed_at DESC
|
||||
LIMIT 10;
|
||||
|
||||
-- Pistes par genre
|
||||
SELECT genre_primary, COUNT(*)
|
||||
FROM audio_tracks
|
||||
WHERE genre_primary IS NOT NULL
|
||||
GROUP BY genre_primary
|
||||
ORDER BY COUNT(*) DESC;
|
||||
|
||||
-- Pistes rapides (> 140 BPM)
|
||||
SELECT filename, tempo_bpm
|
||||
FROM audio_tracks
|
||||
WHERE tempo_bpm > 140
|
||||
ORDER BY tempo_bpm DESC;
|
||||
```
|
||||
|
||||
### Migrations
|
||||
```bash
|
||||
# Appliquer les migrations
|
||||
docker exec audio_classifier_api alembic upgrade head
|
||||
|
||||
# Vérifier la version
|
||||
docker exec audio_classifier_api alembic current
|
||||
|
||||
# Historique
|
||||
docker exec audio_classifier_api alembic history
|
||||
```
|
||||
|
||||
## 🛠️ Gestion services
|
||||
|
||||
### Arrêter
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml stop
|
||||
```
|
||||
|
||||
### Redémarrer
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml restart
|
||||
```
|
||||
|
||||
### Redémarrer uniquement le backend
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml restart backend
|
||||
```
|
||||
|
||||
### Logs
|
||||
```bash
|
||||
# Tous les services
|
||||
docker-compose -f docker-compose.dev.yml logs -f
|
||||
|
||||
# Backend seulement
|
||||
docker-compose -f docker-compose.dev.yml logs -f backend
|
||||
|
||||
# PostgreSQL
|
||||
docker-compose -f docker-compose.dev.yml logs -f postgres
|
||||
```
|
||||
|
||||
### Rebuild
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml build backend
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
### Supprimer tout (⚠️ perd les données)
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml down -v
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Modifier le dossier audio
|
||||
```bash
|
||||
# Éditer .env
|
||||
nano .env
|
||||
|
||||
# Changer:
|
||||
AUDIO_LIBRARY_PATH=/nouveau/chemin/vers/audio
|
||||
|
||||
# Redémarrer
|
||||
docker-compose -f docker-compose.dev.yml restart backend
|
||||
```
|
||||
|
||||
### Changer le nombre de workers
|
||||
```bash
|
||||
# Éditer .env
|
||||
ANALYSIS_NUM_WORKERS=8
|
||||
|
||||
# Redémarrer
|
||||
docker-compose -f docker-compose.dev.yml restart backend
|
||||
```
|
||||
|
||||
## 📊 Statistiques
|
||||
|
||||
### Stats globales
|
||||
```bash
|
||||
curl http://localhost:8001/api/stats | python3 -m json.tool
|
||||
```
|
||||
|
||||
### Nombre de pistes
|
||||
```bash
|
||||
curl -s http://localhost:8001/api/stats | python3 -c "import sys, json; print(f\"Total tracks: {json.load(sys.stdin)['total_tracks']}\")"
|
||||
```
|
||||
|
||||
## 🧪 Tests
|
||||
|
||||
### Test health check
|
||||
```bash
|
||||
curl -f http://localhost:8001/health && echo "✅ OK" || echo "❌ FAIL"
|
||||
```
|
||||
|
||||
### Test connexion DB
|
||||
```bash
|
||||
docker exec audio_classifier_db pg_isready -U audio_user && echo "✅ DB OK" || echo "❌ DB FAIL"
|
||||
```
|
||||
|
||||
### Test frontend
|
||||
```bash
|
||||
curl -f http://localhost:3000 && echo "✅ Frontend OK" || echo "❌ Frontend FAIL"
|
||||
```
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
### API interactive
|
||||
```bash
|
||||
open http://localhost:8001/docs
|
||||
```
|
||||
|
||||
### Frontend
|
||||
```bash
|
||||
open http://localhost:3000
|
||||
```
|
||||
|
||||
## 🆘 Debug
|
||||
|
||||
### Voir les variables d'environnement
|
||||
```bash
|
||||
docker exec audio_classifier_api env | grep -E "DATABASE_URL|CORS|ANALYSIS"
|
||||
```
|
||||
|
||||
### Vérifier les ports
|
||||
```bash
|
||||
lsof -i :8001 # Backend
|
||||
lsof -i :5433 # PostgreSQL
|
||||
lsof -i :3000 # Frontend
|
||||
```
|
||||
|
||||
### Espace disque Docker
|
||||
```bash
|
||||
docker system df
|
||||
docker system prune # Nettoyer
|
||||
```
|
||||
|
||||
## 🎯 Workflows courants
|
||||
|
||||
### Analyser une nouvelle bibliothèque
|
||||
```bash
|
||||
# 1. Configurer le chemin
|
||||
echo 'AUDIO_LIBRARY_PATH=/path/to/music' >> .env
|
||||
|
||||
# 2. Redémarrer
|
||||
docker-compose -f docker-compose.dev.yml restart backend
|
||||
|
||||
# 3. Lancer l'analyse
|
||||
curl -X POST http://localhost:8001/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"path": "/audio", "recursive": true}'
|
||||
|
||||
# 4. Suivre la progression (récupérer job_id d'abord)
|
||||
watch -n 2 "curl -s http://localhost:8001/api/analyze/status/JOB_ID | python3 -m json.tool"
|
||||
```
|
||||
|
||||
### Rechercher et écouter
|
||||
```bash
|
||||
# 1. Rechercher
|
||||
curl "http://localhost:8001/api/search?q=upbeat" | python3 -m json.tool
|
||||
|
||||
# 2. Copier un track_id
|
||||
|
||||
# 3. Écouter
|
||||
open "http://localhost:8001/api/audio/stream/TRACK_ID"
|
||||
```
|
||||
|
||||
### Export des résultats
|
||||
```bash
|
||||
# Export JSON toutes les pistes
|
||||
curl "http://localhost:8001/api/tracks?limit=10000" > tracks.json
|
||||
|
||||
# Export CSV (simple)
|
||||
curl -s "http://localhost:8001/api/tracks?limit=10000" | \
|
||||
python3 -c "import sys, json, csv; data = json.load(sys.stdin)['tracks']; writer = csv.DictWriter(sys.stdout, fieldnames=['filename', 'tempo_bpm', 'key', 'genre_primary']); writer.writeheader(); [writer.writerow({k: track.get(k) or track['features'].get(k) or track['classification']['genre'].get('primary') for k in ['filename', 'tempo_bpm', 'key', 'genre_primary']}) for track in data]" > tracks.csv
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Rappel des URLs** :
|
||||
- Backend API : http://localhost:8001
|
||||
- API Docs : http://localhost:8001/docs
|
||||
- Frontend : http://localhost:3000
|
||||
- PostgreSQL : localhost:5433
|
||||
137
CORRECTIONS.md
137
CORRECTIONS.md
@@ -1,137 +0,0 @@
|
||||
# 🔧 Corrections Appliquées
|
||||
|
||||
## Problème résolu : Build Docker
|
||||
|
||||
### Problème initial
|
||||
```
|
||||
ERROR: Could not find a version that satisfies the requirement essentia-tensorflow==2.1b6.dev1110
|
||||
ERROR: No matching distribution found for essentia-tensorflow==2.1b6.dev1110
|
||||
```
|
||||
|
||||
### Cause
|
||||
La version `essentia-tensorflow==2.1b6.dev1110` spécifiée dans `requirements.txt` n'existe pas sur PyPI. C'était une version de développement qui n'a jamais été publiée.
|
||||
|
||||
### Solution appliquée
|
||||
|
||||
✅ **Correction du `requirements.txt`** :
|
||||
- Suppression de la ligne `essentia-tensorflow==2.1b6.dev1110`
|
||||
- Ajout de commentaires expliquant comment installer Essentia manuellement si besoin
|
||||
- Le système fonctionne maintenant **sans Essentia** en utilisant uniquement Librosa
|
||||
|
||||
✅ **Mise à jour des ports dans `docker-compose.yml`** :
|
||||
- PostgreSQL : `5433` (au lieu de 5432, conflit avec votre instance existante)
|
||||
- Backend : `8001` (au lieu de 8000, conflit avec autre service)
|
||||
|
||||
✅ **Build Docker fonctionnel** :
|
||||
```bash
|
||||
docker-compose build backend
|
||||
# → Successfully installed!
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
### 1. `backend/requirements.txt`
|
||||
**Avant** :
|
||||
```txt
|
||||
essentia-tensorflow==2.1b6.dev1110
|
||||
```
|
||||
|
||||
**Après** :
|
||||
```txt
|
||||
# Optional: Essentia for genre/mood/instrument classification
|
||||
# Note: essentia-tensorflow not available on PyPI for all platforms
|
||||
# Uncomment if you can install it (Linux x86_64 only):
|
||||
# essentia==2.1b6.dev1110
|
||||
# For manual installation: pip install essentia
|
||||
# Or build from source: https://github.com/MTG/essentia
|
||||
```
|
||||
|
||||
### 2. `docker-compose.yml`
|
||||
**Avant** :
|
||||
```yaml
|
||||
ports:
|
||||
- "5432:5432" # PostgreSQL
|
||||
- "8000:8000" # Backend
|
||||
```
|
||||
|
||||
**Après** :
|
||||
```yaml
|
||||
ports:
|
||||
- "5433:5432" # PostgreSQL (évite conflit)
|
||||
- "8001:8000" # Backend (évite conflit)
|
||||
```
|
||||
|
||||
### 3. Fichier `extra_metadata` dans `schema.py`
|
||||
**Problème** : `metadata` est un nom réservé par SQLAlchemy.
|
||||
|
||||
**Correction** : Renommé en `extra_metadata` dans :
|
||||
- `backend/src/models/schema.py`
|
||||
- `backend/src/models/crud.py`
|
||||
|
||||
## Impact
|
||||
|
||||
### ✅ Ce qui fonctionne maintenant
|
||||
- Build Docker complet sans erreurs
|
||||
- Backend opérationnel sur port 8001
|
||||
- PostgreSQL sur port 5433
|
||||
- Tous les endpoints API fonctionnels
|
||||
- Extraction de features audio (Librosa)
|
||||
|
||||
### ⚠️ Ce qui n'est pas disponible
|
||||
- Classification automatique des genres (Essentia)
|
||||
- Classification des moods/ambiances (Essentia)
|
||||
- Détection des instruments (Essentia)
|
||||
|
||||
**Mais** : Ces fonctionnalités ne sont **pas nécessaires** pour 95% des cas d'usage !
|
||||
|
||||
## Alternatives pour la classification
|
||||
|
||||
Si vous avez vraiment besoin de classification automatique, voir [ESSENTIA.md](ESSENTIA.md) pour :
|
||||
|
||||
1. **CLAP** (Contrastive Language-Audio Pretraining) - Recommandé
|
||||
2. **Panns** (Pre-trained Audio Neural Networks) - Stable
|
||||
3. **Hugging Face Transformers** - Moderne
|
||||
|
||||
Ces solutions sont **plus récentes** et **mieux maintenues** qu'Essentia.
|
||||
|
||||
## Vérification
|
||||
|
||||
### Test du build
|
||||
```bash
|
||||
docker-compose build backend
|
||||
# → ✅ Successfully built
|
||||
```
|
||||
|
||||
### Test du démarrage
|
||||
```bash
|
||||
docker-compose up -d
|
||||
# → ✅ Services started
|
||||
|
||||
curl http://localhost:8001/health
|
||||
# → ✅ {"status":"healthy"}
|
||||
```
|
||||
|
||||
### Test de l'API
|
||||
```bash
|
||||
curl http://localhost:8001/api/stats
|
||||
# → ✅ {"total_tracks":0,"genres":[],...}
|
||||
```
|
||||
|
||||
## Commandes mises à jour
|
||||
|
||||
Toutes les commandes dans la documentation utilisent maintenant les bons ports :
|
||||
|
||||
- **Backend API** : http://localhost:8001 (au lieu de 8000)
|
||||
- **PostgreSQL** : localhost:5433 (au lieu de 5432)
|
||||
- **Frontend** : http://localhost:3000 (inchangé)
|
||||
|
||||
## Conclusion
|
||||
|
||||
Le projet est maintenant **100% fonctionnel** avec :
|
||||
- ✅ Build Docker sans erreurs
|
||||
- ✅ Toutes les dépendances installées
|
||||
- ✅ Services opérationnels
|
||||
- ✅ API complète fonctionnelle
|
||||
- ✅ Extraction audio Librosa
|
||||
|
||||
**Pas besoin d'Essentia** pour utiliser le système efficacement ! 🎵
|
||||
196
DEMARRAGE.md
196
DEMARRAGE.md
@@ -1,196 +0,0 @@
|
||||
# 🚀 Démarrage - Audio Classifier
|
||||
|
||||
## ✅ Statut
|
||||
|
||||
Le projet est configuré et prêt à fonctionner !
|
||||
|
||||
## Configuration actuelle
|
||||
|
||||
- **Backend API** : http://localhost:8001
|
||||
- **Base de données** : PostgreSQL sur port 5433
|
||||
- **Frontend** : À lancer sur port 3000
|
||||
|
||||
## 1. Services Docker (Déjà lancés)
|
||||
|
||||
```bash
|
||||
cd "/Users/benoit/Documents/code/Audio Classifier"
|
||||
|
||||
# Vérifier que les services tournent
|
||||
docker-compose -f docker-compose.dev.yml ps
|
||||
|
||||
# Logs du backend
|
||||
docker-compose -f docker-compose.dev.yml logs -f backend
|
||||
```
|
||||
|
||||
## 2. Tester le backend
|
||||
|
||||
```bash
|
||||
# Health check
|
||||
curl http://localhost:8001/health
|
||||
|
||||
# Documentation interactive
|
||||
open http://localhost:8001/docs
|
||||
```
|
||||
|
||||
## 3. Lancer le frontend
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
|
||||
# Si pas encore fait
|
||||
npm install
|
||||
|
||||
# Créer .env.local
|
||||
cat > .env.local << EOF
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8001
|
||||
EOF
|
||||
|
||||
# Lancer
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Frontend accessible sur : **http://localhost:3000**
|
||||
|
||||
## 4. Analyser votre bibliothèque audio
|
||||
|
||||
### Option A : Via l'API
|
||||
|
||||
```bash
|
||||
# Analyser un dossier
|
||||
curl -X POST http://localhost:8001/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"path": "/audio",
|
||||
"recursive": true
|
||||
}'
|
||||
|
||||
# Note: "/audio" correspond au montage dans le conteneur
|
||||
# Pour analyser vos fichiers, mettre à jour AUDIO_LIBRARY_PATH dans .env
|
||||
```
|
||||
|
||||
### Option B : Depuis votre machine (sans Essentia)
|
||||
|
||||
Le système fonctionne actuellement **sans les modèles Essentia** pour simplifier le déploiement.
|
||||
|
||||
**Fonctionnalités disponibles** :
|
||||
- ✅ Extraction tempo (BPM)
|
||||
- ✅ Détection tonalité
|
||||
- ✅ Features spectrales (energy, danceability, valence)
|
||||
- ✅ Signature rythmique
|
||||
- ❌ Classification genre/mood/instruments (nécessite Essentia)
|
||||
|
||||
**Pour activer Essentia** (optionnel) :
|
||||
|
||||
1. Télécharger les modèles :
|
||||
```bash
|
||||
./scripts/download-essentia-models.sh
|
||||
```
|
||||
|
||||
2. Reconstruire avec Dockerfile complet :
|
||||
```bash
|
||||
# Éditer docker-compose.dev.yml
|
||||
# Changer: dockerfile: Dockerfile.minimal
|
||||
# En: dockerfile: Dockerfile
|
||||
|
||||
docker-compose -f docker-compose.dev.yml build backend
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
## 5. Commandes utiles
|
||||
|
||||
### Gérer les services
|
||||
|
||||
```bash
|
||||
# Arrêter
|
||||
docker-compose -f docker-compose.dev.yml stop
|
||||
|
||||
# Redémarrer
|
||||
docker-compose -f docker-compose.dev.yml restart
|
||||
|
||||
# Tout supprimer (⚠️ perd les données DB)
|
||||
docker-compose -f docker-compose.dev.yml down -v
|
||||
```
|
||||
|
||||
### Requêtes API
|
||||
|
||||
```bash
|
||||
# Lister les pistes
|
||||
curl http://localhost:8001/api/tracks?limit=10
|
||||
|
||||
# Recherche
|
||||
curl "http://localhost:8001/api/search?q=test&limit=10"
|
||||
|
||||
# Stats
|
||||
curl http://localhost:8001/api/stats
|
||||
|
||||
# Stream audio (remplacer TRACK_ID)
|
||||
open http://localhost:8001/api/audio/stream/TRACK_ID
|
||||
|
||||
# Download audio
|
||||
curl -O http://localhost:8001/api/audio/download/TRACK_ID
|
||||
```
|
||||
|
||||
## 6. Configuration avancée
|
||||
|
||||
### Changer le dossier audio à analyser
|
||||
|
||||
Éditer `.env` :
|
||||
|
||||
```env
|
||||
AUDIO_LIBRARY_PATH=/Users/benoit/Music
|
||||
```
|
||||
|
||||
Puis redémarrer :
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml restart backend
|
||||
```
|
||||
|
||||
### Accéder à la base de données
|
||||
|
||||
```bash
|
||||
# Connexion psql
|
||||
docker exec -it audio_classifier_db psql -U audio_user -d audio_classifier
|
||||
|
||||
# Queries utiles
|
||||
\dt -- Liste des tables
|
||||
SELECT COUNT(*) FROM audio_tracks;
|
||||
SELECT filename, tempo_bpm, key FROM audio_tracks LIMIT 5;
|
||||
```
|
||||
|
||||
## 🐛 Problèmes courants
|
||||
|
||||
### Backend ne démarre pas
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml logs backend
|
||||
```
|
||||
|
||||
### Port déjà utilisé
|
||||
|
||||
Les ports ont été changés pour éviter les conflits :
|
||||
- PostgreSQL : **5433** (au lieu de 5432)
|
||||
- Backend : **8001** (au lieu de 8000)
|
||||
|
||||
### Frontend ne se connecte pas
|
||||
|
||||
Vérifier `.env.local` dans le dossier `frontend` :
|
||||
|
||||
```env
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8001
|
||||
```
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- [README.md](README.md) - Vue d'ensemble
|
||||
- [SETUP.md](SETUP.md) - Guide complet
|
||||
- http://localhost:8001/docs - API interactive
|
||||
|
||||
## 🎵 Prochaines étapes
|
||||
|
||||
1. **Analyser vos fichiers** : Utiliser l'API `/api/analyze/folder`
|
||||
2. **Explorer le frontend** : Naviguer dans les pistes
|
||||
3. **Tester la recherche** : Filtrer par BPM, etc.
|
||||
4. **Activer Essentia** (optionnel) : Pour genre/mood/instruments
|
||||
|
||||
Bon classement ! 🎶
|
||||
@@ -14,7 +14,7 @@ Le système est **100% autonome** - aucune action manuelle requise ! Les modèle
|
||||
|
||||
1. **Cloner le projet** :
|
||||
```bash
|
||||
git clone <votre-repo>
|
||||
git clone https://git.benoitsz.com/benoit/Audio-Classifier.git
|
||||
cd Audio-Classifier
|
||||
```
|
||||
|
||||
@@ -36,6 +36,8 @@ docker-compose up -d
|
||||
|
||||
C'est tout ! 🎉
|
||||
|
||||
**Note** : Les images Docker sont automatiquement téléchargées depuis git.benoitsz.com. Aucun build nécessaire !
|
||||
|
||||
### Premier Scan
|
||||
|
||||
1. Ouvrir http://localhost:3000
|
||||
@@ -202,13 +204,20 @@ cd Audio-Classifier
|
||||
# Chemin vers musique
|
||||
AUDIO_LIBRARY_PATH=/mnt/musique
|
||||
|
||||
# Domaine public
|
||||
CORS_ORIGINS=http://votre-domaine.com,https://votre-domaine.com
|
||||
# URL publique de l'API (IMPORTANT pour le frontend)
|
||||
# Cette URL est utilisée par le navigateur pour accéder à l'API
|
||||
# Remplacer par votre domaine ou IP publique + port 8001
|
||||
NEXT_PUBLIC_API_URL=https://votre-serveur.com:8001
|
||||
|
||||
# Domaine public pour CORS (doit inclure l'URL du frontend)
|
||||
CORS_ORIGINS=https://votre-domaine.com,https://votre-domaine.com:3000
|
||||
|
||||
# Credentials BDD (sécurisés !)
|
||||
POSTGRES_PASSWORD=motdepasse_fort_aleatoire
|
||||
```
|
||||
|
||||
**Important :** Le frontend utilise maintenant une configuration **runtime**, ce qui signifie que vous pouvez changer `NEXT_PUBLIC_API_URL` dans le fichier `.env` et redémarrer les containers sans avoir à rebuilder les images.
|
||||
|
||||
4. **Démarrer** :
|
||||
```bash
|
||||
docker-compose up -d
|
||||
|
||||
176
DOCKER.md
176
DOCKER.md
@@ -1,176 +0,0 @@
|
||||
# Dockerisation du projet Audio Classifier
|
||||
|
||||
## 🐳 Architecture Docker
|
||||
|
||||
Le projet est entièrement dockerisé avec deux configurations distinctes :
|
||||
|
||||
1. **Production** (`docker-compose.yml`) - Version optimisée pour le déploiement
|
||||
2. **Développement** (`docker-compose.dev.yml`) - Version avec hot-reload pour le développement
|
||||
|
||||
## 📁 Structure des Services
|
||||
|
||||
```yaml
|
||||
services:
|
||||
postgres: # Base de données PostgreSQL avec pgvector
|
||||
backend: # API FastAPI (Python 3.11)
|
||||
frontend: # Interface Next.js (Node.js 20)
|
||||
```
|
||||
|
||||
## 🚀 Commandes de déploiement
|
||||
|
||||
### Mode Production
|
||||
|
||||
```bash
|
||||
# Démarrer tous les services
|
||||
docker-compose up -d
|
||||
|
||||
# Arrêter tous les services
|
||||
docker-compose down
|
||||
|
||||
# Voir les logs
|
||||
docker-compose logs
|
||||
```
|
||||
|
||||
### Mode Développement
|
||||
|
||||
```bash
|
||||
# Démarrer tous les services en mode dev
|
||||
docker-compose -f docker-compose.dev.yml up -d
|
||||
|
||||
# Arrêter tous les services
|
||||
docker-compose -f docker-compose.dev.yml down
|
||||
|
||||
# Voir les logs
|
||||
docker-compose -f docker-compose.dev.yml logs
|
||||
```
|
||||
|
||||
## 🏗 Construction des images
|
||||
|
||||
### Backend (Production)
|
||||
- **Base** : `python:3.9-slim` (pour compatibilité Essentia)
|
||||
- **Dépendances système** : ffmpeg, libsndfile, etc.
|
||||
- **Dépendances Python** : Toutes les dépendances du fichier `requirements.txt`
|
||||
- **Optimisation** : Multi-stage build pour réduire la taille
|
||||
|
||||
### Backend (Développement)
|
||||
- **Base** : `python:3.11-slim`
|
||||
- **Dépendances** : Version minimale sans Essentia
|
||||
- **Hot-reload** : Montage du code source pour développement
|
||||
|
||||
### Frontend (Production)
|
||||
- **Base** : `node:20-alpine`
|
||||
- **Build** : Application Next.js compilée
|
||||
- **Optimisation** : Image légère Alpine Linux
|
||||
|
||||
### Frontend (Développement)
|
||||
- **Base** : `node:20-alpine`
|
||||
- **Hot-reload** : Montage du code source
|
||||
- **Dépendances** : Installation des modules Node
|
||||
|
||||
## ⚙️ Configuration des environnements
|
||||
|
||||
### Variables d'environnement
|
||||
|
||||
Les variables sont définies dans les fichiers `.env` et peuvent être surchargées :
|
||||
|
||||
**Base de données :**
|
||||
- `POSTGRES_USER` - Utilisateur PostgreSQL
|
||||
- `POSTGRES_PASSWORD` - Mot de passe PostgreSQL
|
||||
- `POSTGRES_DB` - Nom de la base de données
|
||||
- `DATABASE_URL` - URL de connexion complète
|
||||
|
||||
**Backend :**
|
||||
- `CORS_ORIGINS` - Origines autorisées pour CORS
|
||||
- `ANALYSIS_USE_CLAP` - Activation des embeddings CLAP
|
||||
- `ANALYSIS_NUM_WORKERS` - Nombre de workers d'analyse
|
||||
- `ESSENTIA_MODELS_PATH` - Chemin vers les modèles Essentia
|
||||
|
||||
**Frontend :**
|
||||
- `NEXT_PUBLIC_API_URL` - URL de l'API backend
|
||||
|
||||
### Volumes Docker
|
||||
|
||||
**Base de données :**
|
||||
- `postgres_data` - Persistance des données PostgreSQL
|
||||
|
||||
**Backend :**
|
||||
- `${AUDIO_LIBRARY_PATH}:/audio:ro` - Montage de la bibliothèque audio (lecture seule)
|
||||
- `./backend/models:/app/models` - Montage des modèles Essentia
|
||||
|
||||
**Frontend :**
|
||||
- `./frontend:/app` (dev) - Montage du code source
|
||||
- `/app/node_modules` (dev) - Persistance des modules Node
|
||||
|
||||
## 🔄 Flux de développement
|
||||
|
||||
1. **Développement backend :**
|
||||
- Modifier le code dans `backend/src/`
|
||||
- Hot-reload automatique avec `docker-compose.dev.yml`
|
||||
|
||||
2. **Développement frontend :**
|
||||
- Modifier le code dans `frontend/`
|
||||
- Hot-reload automatique avec Next.js
|
||||
|
||||
3. **Déploiement :**
|
||||
- Construire les images avec `docker-compose build`
|
||||
- Démarrer les services avec `docker-compose up -d`
|
||||
|
||||
## 🔧 Maintenance et debugging
|
||||
|
||||
### Accéder au conteneur backend
|
||||
```bash
|
||||
docker exec -it audio_classifier_api sh
|
||||
```
|
||||
|
||||
### Accéder au conteneur frontend
|
||||
```bash
|
||||
docker exec -it audio_classifier_ui sh
|
||||
```
|
||||
|
||||
### Accéder à la base de données
|
||||
```bash
|
||||
docker exec -it audio_classifier_db psql -U audio_user -d audio_classifier
|
||||
```
|
||||
|
||||
### Réinitialiser la base de données
|
||||
```bash
|
||||
docker-compose down -v
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## 📈 Performance et optimisation
|
||||
|
||||
### Backend
|
||||
- Utilisation de `--platform=linux/amd64` pour compatibilité Essentia
|
||||
- Installation des dépendances Python par étapes pour meilleur cache
|
||||
- Montage des modèles Essentia pour persistance
|
||||
|
||||
### Frontend
|
||||
- Utilisation d'Alpine Linux pour image légère
|
||||
- Installation des dépendances avant copie du code
|
||||
- Exclusion de `node_modules` du contexte de build
|
||||
|
||||
## 🔒 Sécurité
|
||||
|
||||
- Conteneurs non-root par défaut
|
||||
- Montage lecture-seule de la bibliothèque audio
|
||||
- Mise à jour régulière des images de base
|
||||
- Utilisation de versions spécifiques des dépendances
|
||||
|
||||
## 🆘 Problèmes courants
|
||||
|
||||
### Essentia non disponible sur ARM
|
||||
Solution : Utiliser `--platform=linux/amd64` dans le Dockerfile
|
||||
|
||||
### Permissions de fichiers
|
||||
Solution : Vérifier les permissions du dossier audio monté
|
||||
|
||||
### CORS errors
|
||||
Solution : Vérifier la configuration `CORS_ORIGINS`
|
||||
|
||||
## 📚 Références
|
||||
|
||||
- [Docker Documentation](https://docs.docker.com/)
|
||||
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
||||
- [PostgreSQL avec pgvector](https://github.com/pgvector/pgvector)
|
||||
- [Next.js Dockerisation](https://nextjs.org/docs/deployment)
|
||||
203
ESSENTIA.md
203
ESSENTIA.md
@@ -1,203 +0,0 @@
|
||||
# 🎼 Classification avec Essentia (Optionnel)
|
||||
|
||||
## État actuel
|
||||
|
||||
Le système fonctionne **sans Essentia** en utilisant uniquement Librosa pour l'extraction de features audio.
|
||||
|
||||
**Fonctionnel actuellement** :
|
||||
- ✅ Tempo (BPM)
|
||||
- ✅ Tonalité (key)
|
||||
- ✅ Signature rythmique
|
||||
- ✅ Energy
|
||||
- ✅ Danceability
|
||||
- ✅ Valence
|
||||
- ✅ Features spectrales
|
||||
|
||||
**Non disponible sans Essentia** :
|
||||
- ❌ Classification automatique des genres (50 genres)
|
||||
- ❌ Classification des ambiances/moods (56 moods)
|
||||
- ❌ Détection des instruments (40 instruments)
|
||||
|
||||
## Pourquoi Essentia n'est pas activé par défaut ?
|
||||
|
||||
La version `essentia-tensorflow==2.1b6.dev1110` spécifiée n'existe pas sur PyPI. C'était une version de développement qui n'a jamais été publiée officiellement.
|
||||
|
||||
## Options pour activer la classification IA
|
||||
|
||||
### Option 1 : Utiliser la version stable d'Essentia (Recommandé pour Linux)
|
||||
|
||||
**Note** : Essentia fonctionne principalement sur Linux. Sur macOS ARM64, il peut y avoir des problèmes de compatibilité.
|
||||
|
||||
```bash
|
||||
# Modifier requirements.txt
|
||||
# Remplacer:
|
||||
essentia-tensorflow==2.1b6.dev1110
|
||||
|
||||
# Par:
|
||||
essentia==2.1b6.dev1110 # Version sans TensorFlow
|
||||
# OU
|
||||
essentia-tensorflow # Version la plus récente disponible
|
||||
```
|
||||
|
||||
**Limitations** : Les modèles TensorFlow pré-entraînés peuvent ne pas fonctionner avec les versions stables.
|
||||
|
||||
### Option 2 : Compiler Essentia depuis les sources (Avancé)
|
||||
|
||||
Pour les utilisateurs avancés qui veulent la version complète :
|
||||
|
||||
```bash
|
||||
# Dans le Dockerfile
|
||||
RUN apt-get install -y build-essential libyaml-dev libfftw3-dev \
|
||||
libavcodec-dev libavformat-dev libavutil-dev libavresample-dev \
|
||||
libsamplerate0-dev libtag1-dev libchromaprint-dev python3-dev
|
||||
|
||||
RUN git clone https://github.com/MTG/essentia.git && \
|
||||
cd essentia && \
|
||||
./waf configure --mode=release --build-static --with-python && \
|
||||
./waf && \
|
||||
./waf install
|
||||
```
|
||||
|
||||
**Attention** : Build très long (30+ minutes), augmente considérablement la taille de l'image.
|
||||
|
||||
### Option 3 : Utiliser un modèle alternatif (Recommandé pour production)
|
||||
|
||||
Au lieu d'Essentia, utiliser des modèles plus modernes et maintenus :
|
||||
|
||||
#### A. **Hugging Face Transformers**
|
||||
|
||||
```python
|
||||
# Dans requirements-minimal.txt, ajouter:
|
||||
transformers==4.36.0
|
||||
torch==2.1.2 # CPU version
|
||||
|
||||
# Code pour classification:
|
||||
from transformers import pipeline
|
||||
|
||||
# Genre classification
|
||||
classifier = pipeline("audio-classification",
|
||||
model="facebook/wav2vec2-base-960h")
|
||||
result = classifier("audio.wav")
|
||||
```
|
||||
|
||||
#### B. **CLAP (Contrastive Language-Audio Pretraining)**
|
||||
|
||||
```python
|
||||
# Ajouter:
|
||||
laion-clap==1.1.4
|
||||
|
||||
# Code:
|
||||
import laion_clap
|
||||
model = laion_clap.CLAP_Module(enable_fusion=False)
|
||||
model.load_ckpt()
|
||||
|
||||
# Classification par description textuelle
|
||||
audio_embed = model.get_audio_embedding_from_filelist(["audio.wav"])
|
||||
text_candidates = ["rock music", "jazz", "electronic", "classical"]
|
||||
text_embed = model.get_text_embedding(text_candidates)
|
||||
similarity = audio_embed @ text_embed.T
|
||||
```
|
||||
|
||||
#### C. **Panns (Pre-trained Audio Neural Networks)**
|
||||
|
||||
```python
|
||||
# Ajouter:
|
||||
panns-inference==0.1.0
|
||||
|
||||
# Code:
|
||||
from panns_inference import AudioTagging
|
||||
at = AudioTagging(checkpoint_path=None, device='cpu')
|
||||
tags, probabilities = at.inference("audio.wav")
|
||||
```
|
||||
|
||||
## Solution actuelle (Fallback)
|
||||
|
||||
Le code actuel dans `backend/src/core/essentia_classifier.py` gère gracieusement l'absence d'Essentia :
|
||||
|
||||
```python
|
||||
try:
|
||||
from essentia.standard import MonoLoader, TensorflowPredictEffnetDiscogs
|
||||
ESSENTIA_AVAILABLE = True
|
||||
except ImportError:
|
||||
ESSENTIA_AVAILABLE = False
|
||||
|
||||
# Si Essentia n'est pas disponible, retourne des valeurs par défaut
|
||||
if not ESSENTIA_AVAILABLE:
|
||||
return self._fallback_genre()
|
||||
```
|
||||
|
||||
**Résultat** : Le système fonctionne sans erreur, mais sans classification automatique.
|
||||
|
||||
## Recommandation
|
||||
|
||||
Pour la **plupart des cas d'usage**, les features Librosa (tempo, énergie, tonalité) sont **suffisantes** pour :
|
||||
- Organiser une bibliothèque musicale
|
||||
- Créer des playlists par BPM
|
||||
- Filtrer par énergie/valence
|
||||
- Rechercher par tempo
|
||||
|
||||
Pour la **classification avancée**, je recommande :
|
||||
|
||||
1. **Court terme** : Utiliser le système actuel (Librosa only)
|
||||
2. **Moyen terme** : Implémenter CLAP ou Panns (plus récent, mieux maintenu)
|
||||
3. **Long terme** : Fine-tuner un modèle personnalisé sur votre bibliothèque
|
||||
|
||||
## Migration vers CLAP (Exemple)
|
||||
|
||||
Si vous voulez vraiment la classification, voici comment migrer vers CLAP :
|
||||
|
||||
### 1. Modifier requirements-minimal.txt
|
||||
|
||||
```txt
|
||||
# Ajouter
|
||||
laion-clap==1.1.4
|
||||
torch==2.1.2 # CPU version
|
||||
```
|
||||
|
||||
### 2. Créer clap_classifier.py
|
||||
|
||||
```python
|
||||
"""Classification using CLAP."""
|
||||
import laion_clap
|
||||
|
||||
class CLAPClassifier:
|
||||
def __init__(self):
|
||||
self.model = laion_clap.CLAP_Module(enable_fusion=False)
|
||||
self.model.load_ckpt()
|
||||
|
||||
self.genre_labels = ["rock", "jazz", "electronic", "classical",
|
||||
"hip-hop", "pop", "metal", "folk"]
|
||||
self.mood_labels = ["energetic", "calm", "happy", "sad",
|
||||
"aggressive", "peaceful", "dark", "uplifting"]
|
||||
|
||||
def predict_genre(self, audio_path: str):
|
||||
audio_embed = self.model.get_audio_embedding_from_filelist([audio_path])
|
||||
text_embed = self.model.get_text_embedding(self.genre_labels)
|
||||
|
||||
similarity = (audio_embed @ text_embed.T)[0]
|
||||
top_idx = similarity.argmax()
|
||||
|
||||
return {
|
||||
"primary": self.genre_labels[top_idx],
|
||||
"confidence": float(similarity[top_idx]),
|
||||
"secondary": [self.genre_labels[i] for i in similarity.argsort()[-3:-1][::-1]]
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Intégrer dans analyzer.py
|
||||
|
||||
```python
|
||||
from .clap_classifier import CLAPClassifier
|
||||
|
||||
class AudioAnalyzer:
|
||||
def __init__(self):
|
||||
self.classifier = CLAPClassifier() # Au lieu d'EssentiaClassifier
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
**Pour l'instant** : Le système fonctionne très bien avec Librosa seul.
|
||||
|
||||
**Si vous avez vraiment besoin de classification** : CLAP ou Panns sont de meilleurs choix qu'Essentia en 2025.
|
||||
|
||||
**Ne vous bloquez pas** : Les features audio de base (BPM, tonalité, energy) sont déjà très puissantes pour la plupart des usages !
|
||||
193
QUICKSTART.md
193
QUICKSTART.md
@@ -1,193 +0,0 @@
|
||||
# 🚀 Démarrage Rapide - Audio Classifier
|
||||
|
||||
## En 5 minutes
|
||||
|
||||
### 1. Configuration initiale
|
||||
|
||||
```bash
|
||||
cd "/Users/benoit/Documents/code/Audio Classifier"
|
||||
|
||||
# Copier les variables d'environnement
|
||||
cp .env.example .env
|
||||
|
||||
# IMPORTANT : Éditer .env et définir votre chemin audio
|
||||
# AUDIO_LIBRARY_PATH=/Users/benoit/Music
|
||||
nano .env
|
||||
```
|
||||
|
||||
### 2. Télécharger les modèles d'IA
|
||||
|
||||
```bash
|
||||
./scripts/download-essentia-models.sh
|
||||
```
|
||||
|
||||
Cela télécharge ~300 MB de modèles Essentia pour la classification.
|
||||
|
||||
### 3. Lancer le backend
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Vérifier : http://localhost:8000/health
|
||||
|
||||
### 4. Analyser votre bibliothèque
|
||||
|
||||
```bash
|
||||
# Analyser un dossier (remplacer par votre chemin)
|
||||
curl -X POST http://localhost:8000/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"path": "/audio", "recursive": true}'
|
||||
|
||||
# Note: "/audio" correspond à AUDIO_LIBRARY_PATH dans le conteneur
|
||||
```
|
||||
|
||||
Vous recevrez un `job_id`. Suivre la progression :
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/api/analyze/status/VOTRE_JOB_ID
|
||||
```
|
||||
|
||||
### 5. Lancer le frontend
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
cp .env.local.example .env.local
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Ouvrir : http://localhost:3000
|
||||
|
||||
## 📊 Exemples d'utilisation
|
||||
|
||||
### Rechercher des pistes
|
||||
|
||||
```bash
|
||||
# Par texte
|
||||
curl "http://localhost:8000/api/search?q=jazz"
|
||||
|
||||
# Par genre
|
||||
curl "http://localhost:8000/api/tracks?genre=electronic&limit=10"
|
||||
|
||||
# Par BPM
|
||||
curl "http://localhost:8000/api/tracks?bpm_min=120&bpm_max=140"
|
||||
|
||||
# Par ambiance
|
||||
curl "http://localhost:8000/api/tracks?mood=energetic"
|
||||
```
|
||||
|
||||
### Trouver des pistes similaires
|
||||
|
||||
```bash
|
||||
# 1. Récupérer un track_id
|
||||
curl "http://localhost:8000/api/tracks?limit=1"
|
||||
|
||||
# 2. Trouver des similaires
|
||||
curl "http://localhost:8000/api/tracks/TRACK_ID/similar?limit=10"
|
||||
```
|
||||
|
||||
### Statistiques
|
||||
|
||||
```bash
|
||||
curl "http://localhost:8000/api/stats"
|
||||
```
|
||||
|
||||
### Écouter / Télécharger
|
||||
|
||||
- Stream : http://localhost:8000/api/audio/stream/TRACK_ID
|
||||
- Download : http://localhost:8000/api/audio/download/TRACK_ID
|
||||
|
||||
## 🎯 Ce qui est analysé
|
||||
|
||||
Pour chaque fichier audio :
|
||||
|
||||
✅ **Tempo** (BPM)
|
||||
✅ **Tonalité** (C major, D minor, etc.)
|
||||
✅ **Genre** (50 genres : electronic, jazz, rock, etc.)
|
||||
✅ **Ambiance** (56 moods : energetic, calm, dark, etc.)
|
||||
✅ **Instruments** (40 instruments : piano, guitar, drums, etc.)
|
||||
✅ **Énergie** (score 0-1)
|
||||
✅ **Danceability** (score 0-1)
|
||||
✅ **Valence** (positivité émotionnelle)
|
||||
✅ **Features spectrales** (centroid, zero-crossing, etc.)
|
||||
|
||||
## ⚡ Performance
|
||||
|
||||
**Sur CPU moderne (4 cores)** :
|
||||
|
||||
- ~2-3 secondes par fichier
|
||||
- Analyse parallèle (4 workers par défaut)
|
||||
- 1000 fichiers ≈ 40-50 minutes
|
||||
|
||||
**Pour accélérer** : Ajuster `ANALYSIS_NUM_WORKERS` dans `.env`
|
||||
|
||||
## 📁 Structure
|
||||
|
||||
```
|
||||
Audio Classifier/
|
||||
├── backend/ # API Python + analyse audio
|
||||
├── frontend/ # Interface Next.js
|
||||
├── scripts/ # Scripts utilitaires
|
||||
├── .env # Configuration
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
## 🔍 Endpoints Principaux
|
||||
|
||||
| Endpoint | Méthode | Description |
|
||||
|----------|---------|-------------|
|
||||
| `/api/tracks` | GET | Liste des pistes |
|
||||
| `/api/tracks/{id}` | GET | Détails piste |
|
||||
| `/api/search` | GET | Recherche textuelle |
|
||||
| `/api/tracks/{id}/similar` | GET | Pistes similaires |
|
||||
| `/api/analyze/folder` | POST | Lancer analyse |
|
||||
| `/api/audio/stream/{id}` | GET | Streaming audio |
|
||||
| `/api/audio/download/{id}` | GET | Télécharger |
|
||||
| `/api/stats` | GET | Statistiques |
|
||||
|
||||
Documentation complète : http://localhost:8000/docs
|
||||
|
||||
## 🐛 Problèmes Courants
|
||||
|
||||
**"Connection refused"**
|
||||
```bash
|
||||
docker-compose ps # Vérifier que les services sont up
|
||||
docker-compose logs backend # Voir les erreurs
|
||||
```
|
||||
|
||||
**"Model file not found"**
|
||||
```bash
|
||||
./scripts/download-essentia-models.sh
|
||||
ls backend/models/*.pb # Vérifier présence
|
||||
```
|
||||
|
||||
**Frontend ne charge pas**
|
||||
```bash
|
||||
cd frontend
|
||||
cat .env.local # Vérifier NEXT_PUBLIC_API_URL
|
||||
npm install # Réinstaller dépendances
|
||||
```
|
||||
|
||||
## 📚 Documentation Complète
|
||||
|
||||
- **[README.md](README.md)** - Vue d'ensemble du projet
|
||||
- **[SETUP.md](SETUP.md)** - Guide détaillé d'installation et configuration
|
||||
- **[.claude-todo.md](.claude-todo.md)** - Détails techniques d'implémentation
|
||||
|
||||
## 🎵 Formats Supportés
|
||||
|
||||
✅ MP3
|
||||
✅ WAV
|
||||
✅ FLAC
|
||||
✅ M4A
|
||||
✅ OGG
|
||||
|
||||
## 💡 Prochaines Étapes
|
||||
|
||||
1. **Analyser votre bibliothèque** : Lancer l'analyse sur vos fichiers
|
||||
2. **Explorer l'interface** : Naviguer dans les pistes analysées
|
||||
3. **Tester la recherche** : Filtrer par genre, BPM, mood
|
||||
4. **Découvrir les similaires** : Trouver des recommandations
|
||||
|
||||
Enjoy! 🎶
|
||||
262
README-FINAL.md
262
README-FINAL.md
@@ -1,262 +0,0 @@
|
||||
# 🎵 Audio Classifier - Système Complet
|
||||
|
||||
## ✅ Statut : **Opérationnel**
|
||||
|
||||
Système de classification et indexation audio **100% fonctionnel** avec extraction de features musicales.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Démarrage Rapide
|
||||
|
||||
### Services déjà lancés
|
||||
```bash
|
||||
# Vérifier
|
||||
docker-compose -f docker-compose.dev.yml ps
|
||||
|
||||
# Backend API
|
||||
curl http://localhost:8001/health
|
||||
# → {"status":"healthy"}
|
||||
```
|
||||
|
||||
### Lancer le frontend
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
# → http://localhost:3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Ce qui fonctionne
|
||||
|
||||
### Extraction Audio (Librosa) - **100%**
|
||||
- ✅ **Tempo** : BPM précis avec beat tracking
|
||||
- ✅ **Tonalité** : Détection clé musicale (C major, D minor, etc.)
|
||||
- ✅ **Signature rythmique** : 4/4, 3/4, etc.
|
||||
- ✅ **Energy** : Intensité sonore (0-1)
|
||||
- ✅ **Danceability** : Score de dansabilité (0-1)
|
||||
- ✅ **Valence** : Positivité émotionnelle (0-1)
|
||||
- ✅ **Features spectrales** : Centroid, rolloff, bandwidth, zero-crossing
|
||||
|
||||
### API REST - **100%**
|
||||
- ✅ `GET /api/tracks` - Liste + filtres (genre, BPM, energy, etc.)
|
||||
- ✅ `GET /api/tracks/{id}` - Détails complets
|
||||
- ✅ `GET /api/search?q=...` - Recherche textuelle
|
||||
- ✅ `POST /api/analyze/folder` - Lancer analyse batch
|
||||
- ✅ `GET /api/analyze/status/{id}` - Progression en temps réel
|
||||
- ✅ `GET /api/audio/stream/{id}` - **Streaming audio**
|
||||
- ✅ `GET /api/audio/download/{id}` - **Téléchargement**
|
||||
- ✅ `GET /api/audio/waveform/{id}` - Données visualisation
|
||||
- ✅ `GET /api/stats` - Statistiques globales
|
||||
|
||||
### Base de données - **100%**
|
||||
- ✅ PostgreSQL 16 avec pgvector
|
||||
- ✅ Migrations Alembic
|
||||
- ✅ Indexation optimisée (genre, mood, BPM)
|
||||
- ✅ Prêt pour embeddings vectoriels (CLAP/autres)
|
||||
|
||||
### Frontend - **MVP Fonctionnel**
|
||||
- ✅ Interface Next.js moderne
|
||||
- ✅ Liste des pistes avec pagination
|
||||
- ✅ Statistiques globales
|
||||
- ✅ Boutons Play & Download directs
|
||||
- ✅ React Query pour cache
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Classification IA (Essentia)
|
||||
|
||||
**Statut** : ❌ Non disponible
|
||||
|
||||
**Raison** : La version `essentia-tensorflow==2.1b6.dev1110` n'existe pas sur PyPI.
|
||||
|
||||
**Impact** :
|
||||
- ❌ Pas de classification automatique genres/moods/instruments
|
||||
- ✅ **Toutes les autres features fonctionnent parfaitement**
|
||||
|
||||
**Alternatives modernes** (voir [ESSENTIA.md](ESSENTIA.md)) :
|
||||
- **CLAP** - Classification par description textuelle
|
||||
- **Panns** - Réseaux pré-entraînés audio
|
||||
- **Continuer avec Librosa** - Suffisant pour la plupart des usages
|
||||
|
||||
**Notre recommandation** : Librosa seul est **largement suffisant** pour :
|
||||
- Organiser votre bibliothèque par BPM
|
||||
- Créer des playlists par énergie/valence
|
||||
- Filtrer par tonalité
|
||||
- Rechercher par tempo
|
||||
|
||||
---
|
||||
|
||||
## 📊 Performance
|
||||
|
||||
**Analyse (Librosa seul)** :
|
||||
- ~0.5-1s par fichier
|
||||
- Parallélisation : 4 workers
|
||||
- 1000 fichiers ≈ **10-15 minutes**
|
||||
|
||||
**Formats supportés** :
|
||||
- MP3, WAV, FLAC, M4A, OGG
|
||||
|
||||
---
|
||||
|
||||
## 🔗 URLs
|
||||
|
||||
- **Backend API** : http://localhost:8001
|
||||
- **API Docs** : http://localhost:8001/docs (Swagger interactif)
|
||||
- **Frontend** : http://localhost:3000
|
||||
- **PostgreSQL** : localhost:5433
|
||||
|
||||
---
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
| Fichier | Description |
|
||||
|---------|-------------|
|
||||
| **[DEMARRAGE.md](DEMARRAGE.md)** | Guide de démarrage immédiat |
|
||||
| **[COMMANDES.md](COMMANDES.md)** | Référence complète des commandes |
|
||||
| **[STATUS.md](STATUS.md)** | État détaillé du projet |
|
||||
| **[ESSENTIA.md](ESSENTIA.md)** | Explications sur Essentia + alternatives |
|
||||
| **[SETUP.md](SETUP.md)** | Guide complet + troubleshooting |
|
||||
| **[QUICKSTART.md](QUICKSTART.md)** | Démarrage en 5 min |
|
||||
|
||||
---
|
||||
|
||||
## 🎵 Exemples d'utilisation
|
||||
|
||||
### Analyser votre bibliothèque
|
||||
```bash
|
||||
curl -X POST http://localhost:8001/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"path": "/audio",
|
||||
"recursive": true
|
||||
}'
|
||||
```
|
||||
|
||||
### Rechercher des pistes rapides (> 140 BPM)
|
||||
```bash
|
||||
curl "http://localhost:8001/api/tracks?bpm_min=140&limit=20"
|
||||
```
|
||||
|
||||
### Filtrer par énergie élevée
|
||||
```bash
|
||||
curl "http://localhost:8001/api/tracks?energy_min=0.7"
|
||||
```
|
||||
|
||||
### Écouter une piste
|
||||
```bash
|
||||
open "http://localhost:8001/api/audio/stream/TRACK_ID"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Commandes essentielles
|
||||
|
||||
```bash
|
||||
# Vérifier les services
|
||||
docker-compose -f docker-compose.dev.yml ps
|
||||
|
||||
# Logs backend
|
||||
docker-compose -f docker-compose.dev.yml logs -f backend
|
||||
|
||||
# Redémarrer
|
||||
docker-compose -f docker-compose.dev.yml restart
|
||||
|
||||
# Arrêter tout
|
||||
docker-compose -f docker-compose.dev.yml stop
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Cas d'usage réels
|
||||
|
||||
✅ **DJ / Producteur** : Organiser sets par BPM et énergie
|
||||
✅ **Bibliothèque musicale** : Indexer et rechercher rapidement
|
||||
✅ **Playlist automation** : Filtrer par valence/danceability
|
||||
✅ **Analyse musicale** : Étudier la structure harmonique
|
||||
✅ **Découverte musicale** : Recherche par similarité
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Architecture
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌──────────────┐
|
||||
│ Frontend │─────▶│ FastAPI │─────▶│ PostgreSQL │
|
||||
│ Next.js │ │ Backend │ │ + pgvector │
|
||||
│ (Port 3000)│ │ (Port 8001)│ │ (Port 5433) │
|
||||
└─────────────┘ └─────────────┘ └──────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ Librosa │
|
||||
│ Analysis │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ Points forts
|
||||
|
||||
- 🚀 **Rapide** : ~1s par fichier
|
||||
- 💻 **CPU-only** : Pas besoin de GPU
|
||||
- 🏠 **100% local** : Aucun service cloud
|
||||
- 🎯 **Précis** : Librosa = référence industrie
|
||||
- 📦 **Simple** : Docker Compose tout-en-un
|
||||
- 📚 **Documenté** : 6 guides complets
|
||||
- 🔓 **Open source** : Modifiable à souhait
|
||||
|
||||
---
|
||||
|
||||
## 🎓 Technologies utilisées
|
||||
|
||||
**Backend** :
|
||||
- Python 3.11
|
||||
- FastAPI (API REST)
|
||||
- Librosa (Analyse audio)
|
||||
- SQLAlchemy (ORM)
|
||||
- Alembic (Migrations)
|
||||
- PostgreSQL + pgvector
|
||||
|
||||
**Frontend** :
|
||||
- Next.js 14
|
||||
- TypeScript
|
||||
- TailwindCSS
|
||||
- React Query
|
||||
- Axios
|
||||
|
||||
**Infrastructure** :
|
||||
- Docker & Docker Compose
|
||||
- Bash scripts
|
||||
|
||||
---
|
||||
|
||||
## 📝 Licence
|
||||
|
||||
MIT
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Support
|
||||
|
||||
**Documentation** : Voir les 6 fichiers MD dans le projet
|
||||
**API Docs** : http://localhost:8001/docs
|
||||
**Issues** : Problèmes documentés dans SETUP.md
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Conclusion
|
||||
|
||||
Le système est **prêt à l'emploi** avec :
|
||||
- ✅ Extraction complète de features audio
|
||||
- ✅ API REST fonctionnelle
|
||||
- ✅ Interface web basique
|
||||
- ✅ Base de données opérationnelle
|
||||
- ✅ Streaming et téléchargement audio
|
||||
|
||||
**Pas besoin d'Essentia pour 95% des cas d'usage !**
|
||||
|
||||
Les features Librosa (tempo, tonalité, energy, valence) sont **amplement suffisantes** pour organiser et explorer une bibliothèque musicale.
|
||||
|
||||
**Bon classement ! 🎵**
|
||||
21
README.md
21
README.md
@@ -41,8 +41,8 @@ Outil de classification audio automatique capable d'indexer et analyser des bibl
|
||||
|
||||
```bash
|
||||
# 1. Cloner le projet
|
||||
git clone <repo>
|
||||
cd audio-classifier
|
||||
git clone https://git.benoitsz.com/benoit/Audio-Classifier.git
|
||||
cd Audio-Classifier
|
||||
|
||||
# 2. Configurer le chemin audio (optionnel)
|
||||
echo "AUDIO_LIBRARY_PATH=/chemin/vers/votre/musique" > .env
|
||||
@@ -53,6 +53,8 @@ docker-compose up -d
|
||||
|
||||
**C'est tout !** 🎉
|
||||
|
||||
Les images Docker sont automatiquement téléchargées depuis le registry Gitea.
|
||||
|
||||
- Frontend : http://localhost:3000
|
||||
- API : http://localhost:8001
|
||||
- API Docs : http://localhost:8001/docs
|
||||
@@ -66,13 +68,26 @@ docker-compose up -d
|
||||
|
||||
### ✨ Particularités
|
||||
|
||||
- **Aucun téléchargement manuel** : Les modèles Essentia (28 MB) sont inclus dans l'image Docker
|
||||
- **Images pré-construites** : Téléchargées automatiquement depuis git.benoitsz.com
|
||||
- **Modèles inclus** : Les modèles Essentia (28 MB) sont intégrés dans l'image
|
||||
- **Aucune configuration** : Tout fonctionne out-of-the-box
|
||||
- **Transcodage automatique** : MP3 128kbps créés pour streaming rapide
|
||||
- **Waveforms pré-calculées** : Chargement instantané
|
||||
|
||||
📖 **Documentation complète** : Voir [DEPLOYMENT.md](DEPLOYMENT.md)
|
||||
|
||||
### 🛠 Build local (développement)
|
||||
|
||||
Si vous voulez builder les images localement, les modèles Essentia doivent être présents dans `backend/models/` (28 MB).
|
||||
|
||||
```bash
|
||||
# Build avec docker-compose
|
||||
docker-compose -f docker-compose.build.yml build
|
||||
docker-compose -f docker-compose.build.yml up -d
|
||||
```
|
||||
|
||||
**Note** : Les modèles Essentia (`.pb`, 28 MB) ne sont pas versionnés dans Git. Le workflow CI/CD les télécharge automatiquement depuis essentia.upf.edu pendant le build.
|
||||
|
||||
## 📖 Utilisation
|
||||
|
||||
### Scanner un dossier
|
||||
|
||||
260
RESUME.md
260
RESUME.md
@@ -1,260 +0,0 @@
|
||||
# 📝 Résumé - Audio Classifier
|
||||
|
||||
## ✅ Projet Complété
|
||||
|
||||
**Date** : 27 novembre 2025
|
||||
**Statut** : **100% Opérationnel**
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Ce qui a été livré
|
||||
|
||||
### Backend complet (Python/FastAPI)
|
||||
- ✅ Extraction de features audio avec **Librosa**
|
||||
- Tempo (BPM), Tonalité, Signature rythmique
|
||||
- Energy, Danceability, Valence
|
||||
- Features spectrales complètes
|
||||
- ✅ **12 endpoints API REST** fonctionnels
|
||||
- ✅ Base PostgreSQL + pgvector
|
||||
- ✅ Streaming et téléchargement audio
|
||||
- ✅ Analyse parallèle de dossiers (4 workers)
|
||||
- ✅ Génération waveform pour visualisation
|
||||
- ✅ Migrations Alembic appliquées
|
||||
|
||||
### Frontend MVP (Next.js/TypeScript)
|
||||
- ✅ Interface moderne TailwindCSS
|
||||
- ✅ Liste des pistes avec pagination
|
||||
- ✅ Statistiques globales
|
||||
- ✅ Boutons Play & Download directs
|
||||
- ✅ Client API TypeScript complet
|
||||
- ✅ React Query pour cache
|
||||
|
||||
### Infrastructure
|
||||
- ✅ Docker Compose opérationnel
|
||||
- ✅ Ports configurés (8001, 5433, 3000)
|
||||
- ✅ Scripts automatisés
|
||||
- ✅ Migrations DB appliquées
|
||||
|
||||
### Documentation
|
||||
- ✅ **8 fichiers** de documentation complète
|
||||
- ✅ Guides de démarrage
|
||||
- ✅ Référence des commandes
|
||||
- ✅ Troubleshooting
|
||||
- ✅ Explications techniques
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Services actifs
|
||||
|
||||
| Service | URL | Statut |
|
||||
|---------|-----|--------|
|
||||
| **Backend API** | http://localhost:8001 | ✅ Running |
|
||||
| **PostgreSQL** | localhost:5433 | ✅ Healthy |
|
||||
| **Frontend** | http://localhost:3000 | 📋 À lancer |
|
||||
| **API Docs** | http://localhost:8001/docs | ✅ Accessible |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Fonctionnalités
|
||||
|
||||
### Extraction Audio (Librosa)
|
||||
- ✅ Tempo automatique (BPM)
|
||||
- ✅ Détection de tonalité (C major, D minor, etc.)
|
||||
- ✅ Signature rythmique (4/4, 3/4, etc.)
|
||||
- ✅ Energy (0-1)
|
||||
- ✅ Danceability (0-1)
|
||||
- ✅ Valence émotionnelle (0-1)
|
||||
- ✅ Spectral centroid, rolloff, bandwidth
|
||||
- ✅ Zero-crossing rate
|
||||
|
||||
### API REST
|
||||
- `GET /api/tracks` - Liste + filtres
|
||||
- `GET /api/tracks/{id}` - Détails
|
||||
- `GET /api/search` - Recherche textuelle
|
||||
- `GET /api/audio/stream/{id}` - **Streaming**
|
||||
- `GET /api/audio/download/{id}` - **Téléchargement**
|
||||
- `GET /api/audio/waveform/{id}` - Waveform
|
||||
- `POST /api/analyze/folder` - Analyse batch
|
||||
- `GET /api/analyze/status/{id}` - Progression
|
||||
- `GET /api/tracks/{id}/similar` - Similaires
|
||||
- `GET /api/stats` - Statistiques
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Note : Classification IA (Essentia)
|
||||
|
||||
**Statut** : Non disponible (dépendance PyPI inexistante)
|
||||
|
||||
**Impact** :
|
||||
- ❌ Pas de classification automatique genre/mood/instruments
|
||||
- ✅ **Toutes les autres features fonctionnent parfaitement**
|
||||
|
||||
**Alternatives documentées** :
|
||||
- CLAP (Contrastive Language-Audio Pretraining)
|
||||
- Panns (Pre-trained Audio Neural Networks)
|
||||
- Continuer avec Librosa seul (recommandé)
|
||||
|
||||
Voir [ESSENTIA.md](ESSENTIA.md) et [CORRECTIONS.md](CORRECTIONS.md)
|
||||
|
||||
---
|
||||
|
||||
## 📁 Documentation
|
||||
|
||||
| Fichier | Description |
|
||||
|---------|-------------|
|
||||
| **[README-FINAL.md](README-FINAL.md)** | Vue d'ensemble complète |
|
||||
| **[DEMARRAGE.md](DEMARRAGE.md)** | Guide de démarrage immédiat |
|
||||
| **[COMMANDES.md](COMMANDES.md)** | Référence toutes commandes |
|
||||
| **[STATUS.md](STATUS.md)** | État détaillé du projet |
|
||||
| **[CORRECTIONS.md](CORRECTIONS.md)** | Corrections appliquées |
|
||||
| **[ESSENTIA.md](ESSENTIA.md)** | Classification IA alternatives |
|
||||
| **[SETUP.md](SETUP.md)** | Guide complet + troubleshooting |
|
||||
| **[QUICKSTART.md](QUICKSTART.md)** | Démarrage 5 minutes |
|
||||
|
||||
---
|
||||
|
||||
## 🎵 Utilisation rapide
|
||||
|
||||
### 1. Vérifier les services
|
||||
```bash
|
||||
docker-compose ps
|
||||
curl http://localhost:8001/health
|
||||
```
|
||||
|
||||
### 2. Lancer le frontend
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
# → http://localhost:3000
|
||||
```
|
||||
|
||||
### 3. Analyser des fichiers
|
||||
```bash
|
||||
curl -X POST http://localhost:8001/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"path": "/audio", "recursive": true}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Performance
|
||||
|
||||
- **~1 seconde** par fichier (Librosa)
|
||||
- **Parallélisation** : 4 workers CPU
|
||||
- **1000 fichiers** ≈ 15-20 minutes
|
||||
- **Formats** : MP3, WAV, FLAC, M4A, OGG
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
||||
│ Next.js │─────▶│ FastAPI │─────▶│ PostgreSQL │
|
||||
│ Frontend │ │ Backend │ │ + pgvector │
|
||||
│ Port 3000 │ │ Port 8001 │ │ Port 5433 │
|
||||
└──────────────┘ └──────────────┘ └──────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────┐
|
||||
│ Librosa │
|
||||
│ Analysis │
|
||||
└──────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Problèmes résolus
|
||||
|
||||
### ✅ Build Docker
|
||||
- **Problème** : `essentia-tensorflow==2.1b6.dev1110` inexistant
|
||||
- **Solution** : Supprimé, commenté avec alternatives
|
||||
|
||||
### ✅ Conflits de ports
|
||||
- **Problème** : Ports 5432 et 8000 occupés
|
||||
- **Solution** : Changé en 5433 et 8001
|
||||
|
||||
### ✅ Nom réservé SQLAlchemy
|
||||
- **Problème** : Colonne `metadata` réservée
|
||||
- **Solution** : Renommé en `extra_metadata`
|
||||
|
||||
---
|
||||
|
||||
## ✨ Points forts
|
||||
|
||||
- 🚀 **Rapide** : 1s par fichier
|
||||
- 💻 **CPU-only** : Pas de GPU nécessaire
|
||||
- 🏠 **100% local** : Zéro dépendance cloud
|
||||
- 🎯 **Précis** : Librosa = standard industrie
|
||||
- 📦 **Simple** : Docker Compose tout-en-un
|
||||
- 📚 **Documenté** : 8 guides complets
|
||||
- 🔓 **Open source** : Code modifiable
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Cas d'usage
|
||||
|
||||
✅ DJ / Producteur musical
|
||||
✅ Organisation bibliothèque audio
|
||||
✅ Création playlists intelligentes
|
||||
✅ Analyse musicologique
|
||||
✅ Recherche par similarité
|
||||
✅ Filtrage par tempo/énergie
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Commandes essentielles
|
||||
|
||||
```bash
|
||||
# Santé du système
|
||||
curl http://localhost:8001/health
|
||||
|
||||
# Statistiques
|
||||
curl http://localhost:8001/api/stats
|
||||
|
||||
# Recherche par BPM
|
||||
curl "http://localhost:8001/api/tracks?bpm_min=120&bpm_max=140"
|
||||
|
||||
# Logs
|
||||
docker-compose logs -f backend
|
||||
|
||||
# Redémarrer
|
||||
docker-compose restart
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📈 État du projet
|
||||
|
||||
| Composant | Complétude | Statut |
|
||||
|-----------|------------|--------|
|
||||
| Backend API | 100% | ✅ Opérationnel |
|
||||
| Base de données | 100% | ✅ Configurée |
|
||||
| Extraction audio | 100% | ✅ Fonctionnel |
|
||||
| Frontend MVP | 80% | ✅ Basique |
|
||||
| Documentation | 100% | ✅ Complète |
|
||||
| Classification IA | 0% | ⚠️ Optionnel |
|
||||
|
||||
**Score global** : **95%** 🎉
|
||||
|
||||
---
|
||||
|
||||
## 🎉 Conclusion
|
||||
|
||||
Le système est **prêt à l'emploi** avec :
|
||||
- ✅ Extraction complète de features musicales
|
||||
- ✅ API REST puissante et documentée
|
||||
- ✅ Interface web fonctionnelle
|
||||
- ✅ Base de données performante
|
||||
- ✅ Streaming et téléchargement audio
|
||||
|
||||
**Librosa seul suffit pour 95% des besoins !**
|
||||
|
||||
Les features extraites (tempo, tonalité, energy, valence) permettent déjà :
|
||||
- Organisation de bibliothèque musicale
|
||||
- Création de playlists par BPM
|
||||
- Filtrage par énergie/humeur
|
||||
- Recherche et découverte musicale
|
||||
|
||||
**Le projet est un succès ! 🎵**
|
||||
403
SETUP.md
403
SETUP.md
@@ -1,403 +0,0 @@
|
||||
# Audio Classifier - Guide de Déploiement
|
||||
|
||||
## 📋 Prérequis
|
||||
|
||||
- **Docker** & Docker Compose
|
||||
- **Node.js** 20+ (pour le frontend en mode dev)
|
||||
- **Python** 3.11+ (optionnel, si vous voulez tester le backend sans Docker)
|
||||
- **FFmpeg** (installé automatiquement dans le conteneur Docker)
|
||||
|
||||
## 🚀 Installation Rapide
|
||||
|
||||
### 1. Cloner le projet
|
||||
|
||||
```bash
|
||||
cd "/Users/benoit/Documents/code/Audio Classifier"
|
||||
```
|
||||
|
||||
### 2. Configurer les variables d'environnement
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Éditer `.env` et définir :
|
||||
|
||||
```env
|
||||
# Chemin vers votre bibliothèque audio (IMPORTANT)
|
||||
AUDIO_LIBRARY_PATH=/chemin/absolu/vers/vos/fichiers/audio
|
||||
|
||||
# Exemple macOS:
|
||||
# AUDIO_LIBRARY_PATH=/Users/benoit/Music
|
||||
|
||||
# Le reste peut rester par défaut
|
||||
DATABASE_URL=postgresql://audio_user:audio_password@localhost:5432/audio_classifier
|
||||
```
|
||||
|
||||
### 3. Télécharger les modèles Essentia
|
||||
|
||||
Les modèles de classification sont nécessaires pour analyser les fichiers audio.
|
||||
|
||||
```bash
|
||||
./scripts/download-essentia-models.sh
|
||||
```
|
||||
|
||||
Cela télécharge (~300 MB) :
|
||||
- `mtg_jamendo_genre` : Classification de 50 genres musicaux
|
||||
- `mtg_jamendo_moodtheme` : Classification de 56 ambiances/moods
|
||||
- `mtg_jamendo_instrument` : Détection de 40 instruments
|
||||
|
||||
### 4. Lancer le backend avec Docker
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Cela démarre :
|
||||
- **PostgreSQL** avec l'extension pgvector (port 5432)
|
||||
- **Backend FastAPI** (port 8000)
|
||||
|
||||
Vérifier que tout fonctionne :
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
# Devrait retourner: {"status":"healthy",...}
|
||||
```
|
||||
|
||||
Documentation API interactive : **http://localhost:8000/docs**
|
||||
|
||||
### 5. Lancer le frontend (mode développement)
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
cp .env.local.example .env.local
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Frontend accessible sur : **http://localhost:3000**
|
||||
|
||||
## 📊 Utiliser l'Application
|
||||
|
||||
### Analyser votre bibliothèque audio
|
||||
|
||||
**Option 1 : Via l'API (recommandé pour première analyse)**
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8000/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"path": "/audio",
|
||||
"recursive": true
|
||||
}'
|
||||
```
|
||||
|
||||
**Note** : Le chemin `/audio` correspond au montage Docker de `AUDIO_LIBRARY_PATH`.
|
||||
|
||||
Vous recevrez un `job_id`. Vérifier la progression :
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/api/analyze/status/JOB_ID
|
||||
```
|
||||
|
||||
**Option 2 : Via Python (backend local)**
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
python -m venv venv
|
||||
source venv/bin/activate # Windows: venv\Scripts\activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Analyser un fichier
|
||||
python -c "
|
||||
from src.core.analyzer import AudioAnalyzer
|
||||
analyzer = AudioAnalyzer()
|
||||
result = analyzer.analyze_file('/path/to/audio.mp3')
|
||||
print(result)
|
||||
"
|
||||
```
|
||||
|
||||
### Rechercher des pistes
|
||||
|
||||
**Par texte :**
|
||||
|
||||
```bash
|
||||
curl "http://localhost:8000/api/search?q=jazz&limit=10"
|
||||
```
|
||||
|
||||
**Avec filtres :**
|
||||
|
||||
```bash
|
||||
curl "http://localhost:8000/api/tracks?genre=electronic&bpm_min=120&bpm_max=140&limit=20"
|
||||
```
|
||||
|
||||
**Pistes similaires :**
|
||||
|
||||
```bash
|
||||
curl "http://localhost:8000/api/tracks/TRACK_ID/similar?limit=10"
|
||||
```
|
||||
|
||||
### Télécharger / Écouter
|
||||
|
||||
- **Stream** : `http://localhost:8000/api/audio/stream/TRACK_ID`
|
||||
- **Download** : `http://localhost:8000/api/audio/download/TRACK_ID`
|
||||
- **Waveform** : `http://localhost:8000/api/audio/waveform/TRACK_ID`
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
```
|
||||
audio-classifier/
|
||||
├── backend/ # API Python FastAPI
|
||||
│ ├── src/
|
||||
│ │ ├── core/ # Audio processing
|
||||
│ │ │ ├── audio_processor.py # Librosa features
|
||||
│ │ │ ├── essentia_classifier.py # Genre/Mood/Instruments
|
||||
│ │ │ ├── waveform_generator.py # Peaks pour UI
|
||||
│ │ │ ├── file_scanner.py # Scan dossiers
|
||||
│ │ │ └── analyzer.py # Orchestrateur
|
||||
│ │ ├── models/ # Database
|
||||
│ │ │ ├── schema.py # SQLAlchemy models
|
||||
│ │ │ └── crud.py # CRUD operations
|
||||
│ │ ├── api/ # FastAPI routes
|
||||
│ │ │ └── routes/
|
||||
│ │ │ ├── tracks.py # GET/DELETE tracks
|
||||
│ │ │ ├── search.py # Recherche
|
||||
│ │ │ ├── audio.py # Stream/Download
|
||||
│ │ │ ├── analyze.py # Jobs d'analyse
|
||||
│ │ │ ├── similar.py # Recommandations
|
||||
│ │ │ └── stats.py # Statistiques
|
||||
│ │ └── utils/ # Config, logging, validators
|
||||
│ ├── models/ # Essentia .pb files
|
||||
│ └── requirements.txt
|
||||
│
|
||||
├── frontend/ # UI Next.js
|
||||
│ ├── app/
|
||||
│ │ ├── page.tsx # Page principale
|
||||
│ │ └── layout.tsx
|
||||
│ ├── components/
|
||||
│ │ └── providers/
|
||||
│ ├── lib/
|
||||
│ │ ├── api.ts # Client API
|
||||
│ │ ├── types.ts # TypeScript types
|
||||
│ │ └── utils.ts # Helpers
|
||||
│ └── package.json
|
||||
│
|
||||
├── scripts/
|
||||
│ └── download-essentia-models.sh
|
||||
│
|
||||
└── docker-compose.yml
|
||||
```
|
||||
|
||||
## 🔧 Configuration Avancée
|
||||
|
||||
### Performance CPU
|
||||
|
||||
Le système est optimisé pour CPU-only. Sur un CPU moderne (4 cores) :
|
||||
|
||||
- **Librosa features** : ~0.5-1s par fichier
|
||||
- **Essentia classification** : ~1-2s par fichier
|
||||
- **Total** : ~2-3s par fichier
|
||||
|
||||
Ajuster le parallélisme dans `.env` :
|
||||
|
||||
```env
|
||||
ANALYSIS_NUM_WORKERS=4 # Nombre de threads parallèles
|
||||
```
|
||||
|
||||
### Activer les embeddings CLAP (optionnel)
|
||||
|
||||
Pour la recherche sémantique avancée ("calm piano for working") :
|
||||
|
||||
```env
|
||||
ANALYSIS_USE_CLAP=true
|
||||
```
|
||||
|
||||
**Attention** : Augmente significativement le temps d'analyse (~5-10s supplémentaires par fichier).
|
||||
|
||||
### Base de données
|
||||
|
||||
Par défaut, PostgreSQL tourne dans Docker. Pour utiliser une DB externe :
|
||||
|
||||
```env
|
||||
DATABASE_URL=postgresql://user:pass@external-host:5432/dbname
|
||||
```
|
||||
|
||||
Appliquer les migrations :
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
## 📊 Données Extraites
|
||||
|
||||
### Features Audio (Librosa)
|
||||
- **Tempo** : BPM détecté automatiquement
|
||||
- **Tonalité** : Clé musicale (C major, D minor, etc.)
|
||||
- **Signature rythmique** : 4/4, 3/4, etc.
|
||||
- **Énergie** : Intensité sonore (0-1)
|
||||
- **Danceability** : Score de dansabilité (0-1)
|
||||
- **Valence** : Positivité/négativité émotionnelle (0-1)
|
||||
- **Features spectrales** : Centroid, rolloff, bandwidth
|
||||
|
||||
### Classification (Essentia)
|
||||
- **Genre** : 50 genres possibles (rock, electronic, jazz, etc.)
|
||||
- **Mood** : 56 ambiances (energetic, calm, dark, happy, etc.)
|
||||
- **Instruments** : 40 instruments détectables (piano, guitar, drums, etc.)
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Le backend ne démarre pas
|
||||
|
||||
```bash
|
||||
docker-compose logs backend
|
||||
```
|
||||
|
||||
Vérifier que :
|
||||
- PostgreSQL est bien démarré (`docker-compose ps`)
|
||||
- Les modèles Essentia sont téléchargés (`ls backend/models/*.pb`)
|
||||
- Le port 8000 n'est pas déjà utilisé
|
||||
|
||||
### "Model file not found"
|
||||
|
||||
```bash
|
||||
./scripts/download-essentia-models.sh
|
||||
```
|
||||
|
||||
### Frontend ne se connecte pas au backend
|
||||
|
||||
Vérifier `.env.local` :
|
||||
|
||||
```env
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
||||
```
|
||||
|
||||
### Analyse très lente
|
||||
|
||||
- Réduire `ANALYSIS_NUM_WORKERS` si CPU surchargé
|
||||
- Désactiver `ANALYSIS_USE_CLAP` si activé
|
||||
- Vérifier que les fichiers audio sont accessibles rapidement (éviter NAS lents)
|
||||
|
||||
### Erreur FFmpeg
|
||||
|
||||
FFmpeg est installé automatiquement dans le conteneur Docker. Si vous lancez le backend en local :
|
||||
|
||||
```bash
|
||||
# macOS
|
||||
brew install ffmpeg
|
||||
|
||||
# Ubuntu/Debian
|
||||
sudo apt-get install ffmpeg libsndfile1
|
||||
```
|
||||
|
||||
## 📦 Production
|
||||
|
||||
### Build frontend
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run build
|
||||
npm start # Port 3000
|
||||
```
|
||||
|
||||
### Backend en production
|
||||
|
||||
Utiliser Gunicorn avec Uvicorn workers :
|
||||
|
||||
```bash
|
||||
pip install gunicorn
|
||||
gunicorn src.api.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
|
||||
```
|
||||
|
||||
### Reverse proxy (Nginx)
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name your-domain.com;
|
||||
|
||||
location /api {
|
||||
proxy_pass http://localhost:8000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 🔒 Sécurité
|
||||
|
||||
**IMPORTANT** : Le système actuel n'a PAS d'authentification.
|
||||
|
||||
Pour la production :
|
||||
- Ajouter authentication JWT
|
||||
- Limiter l'accès aux endpoints d'analyse
|
||||
- Valider tous les chemins de fichiers (déjà fait côté backend)
|
||||
- Utiliser HTTPS
|
||||
- Restreindre CORS aux domaines autorisés
|
||||
|
||||
## 📝 Développement
|
||||
|
||||
### Ajouter un nouveau genre/mood
|
||||
|
||||
Éditer `backend/src/core/essentia_classifier.py` :
|
||||
|
||||
```python
|
||||
self.class_labels["genre"] = [
|
||||
# ... genres existants
|
||||
"nouveau_genre",
|
||||
]
|
||||
```
|
||||
|
||||
### Modifier les features extraites
|
||||
|
||||
Éditer `backend/src/core/audio_processor.py` et ajouter votre fonction :
|
||||
|
||||
```python
|
||||
def extract_new_feature(y, sr) -> float:
|
||||
# Votre logique
|
||||
return feature_value
|
||||
```
|
||||
|
||||
Puis mettre à jour `extract_all_features()`.
|
||||
|
||||
### Ajouter une route API
|
||||
|
||||
1. Créer `backend/src/api/routes/nouvelle_route.py`
|
||||
2. Ajouter le router dans `backend/src/api/main.py`
|
||||
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd backend
|
||||
pytest
|
||||
|
||||
# Frontend
|
||||
cd frontend
|
||||
npm test
|
||||
```
|
||||
|
||||
## 📈 Améliorations Futures
|
||||
|
||||
- [ ] Interface de scan dans le frontend (actuellement via API seulement)
|
||||
- [ ] Player audio intégré avec waveform interactive
|
||||
- [ ] Filtres avancés (multi-genre, range sliders)
|
||||
- [ ] Export playlists (M3U, CSV, JSON)
|
||||
- [ ] Détection de doublons (audio fingerprinting)
|
||||
- [ ] Édition de tags ID3
|
||||
- [ ] Recherche sémantique avec CLAP
|
||||
- [ ] Authentication multi-utilisateurs
|
||||
- [ ] WebSocket pour progression temps réel
|
||||
|
||||
## 🆘 Support
|
||||
|
||||
Pour toute question :
|
||||
1. Vérifier les logs : `docker-compose logs -f backend`
|
||||
2. Consulter la doc API : http://localhost:8000/docs
|
||||
3. Ouvrir une issue GitHub
|
||||
|
||||
Bon classement ! 🎵
|
||||
202
STATUS.md
202
STATUS.md
@@ -1,202 +0,0 @@
|
||||
# ✅ Audio Classifier - État du Projet
|
||||
|
||||
**Date** : 27 novembre 2025
|
||||
**Statut** : ✅ **Opérationnel**
|
||||
|
||||
## 🎯 Ce qui fonctionne
|
||||
|
||||
### Backend (100%)
|
||||
- ✅ API FastAPI sur http://localhost:8001
|
||||
- ✅ Base de données PostgreSQL + pgvector (port 5433)
|
||||
- ✅ Extraction de features audio (Librosa)
|
||||
- Tempo (BPM)
|
||||
- Tonalité (key)
|
||||
- Signature rythmique
|
||||
- Energy, Danceability, Valence
|
||||
- Features spectrales
|
||||
- ✅ Génération waveform pour visualisation
|
||||
- ✅ Scanner de dossiers
|
||||
- ✅ API complète :
|
||||
- GET /api/tracks (liste + filtres)
|
||||
- GET /api/tracks/{id} (détails)
|
||||
- GET /api/search (recherche textuelle)
|
||||
- GET /api/audio/stream/{id} (streaming)
|
||||
- GET /api/audio/download/{id} (téléchargement)
|
||||
- GET /api/audio/waveform/{id} (données waveform)
|
||||
- POST /api/analyze/folder (lancer analyse)
|
||||
- GET /api/analyze/status/{id} (progression)
|
||||
- GET /api/stats (statistiques)
|
||||
|
||||
### Frontend (MVP)
|
||||
- ✅ Interface Next.js configurée
|
||||
- ✅ Client API TypeScript
|
||||
- ✅ Page principale avec :
|
||||
- Statistiques globales
|
||||
- Liste des pistes
|
||||
- Pagination
|
||||
- Boutons Play & Download
|
||||
- ✅ React Query pour cache
|
||||
- ✅ TailwindCSS
|
||||
|
||||
### Infrastructure
|
||||
- ✅ Docker Compose fonctionnel
|
||||
- ✅ Migrations Alembic
|
||||
- ✅ Documentation complète
|
||||
|
||||
## ⚠️ Limitations actuelles
|
||||
|
||||
### Classification IA (Essentia)
|
||||
**Statut** : ❌ Désactivée (optionnelle)
|
||||
|
||||
Le système fonctionne **sans les modèles Essentia** pour simplifier le déploiement.
|
||||
|
||||
**Impact** :
|
||||
- ❌ Pas de classification automatique genre/mood/instruments
|
||||
- ✅ Toutes les autres features fonctionnent (tempo, tonalité, energy, etc.)
|
||||
|
||||
**Pour activer** :
|
||||
1. Télécharger modèles : `./scripts/download-essentia-models.sh`
|
||||
2. Modifier `docker-compose.dev.yml` : `dockerfile: Dockerfile` (au lieu de `Dockerfile.minimal`)
|
||||
3. Rebuild : `docker-compose -f docker-compose.dev.yml build backend`
|
||||
|
||||
### Frontend avancé
|
||||
**Statut** : 🚧 MVP seulement
|
||||
|
||||
**Manquant** (non-critique) :
|
||||
- Player audio intégré avec contrôles
|
||||
- Visualisation waveform interactive
|
||||
- Filtres avancés (sliders BPM, energy)
|
||||
- Interface de scan de dossiers
|
||||
- Page détails piste
|
||||
- Pistes similaires UI
|
||||
|
||||
**Pourquoi** : MVP fonctionnel prioritaire, extensions possibles plus tard
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Ports
|
||||
- **Backend** : 8001 (modifié pour éviter conflit avec port 8000)
|
||||
- **PostgreSQL** : 5433 (modifié pour éviter conflit avec port 5432)
|
||||
- **Frontend** : 3000
|
||||
|
||||
### Variables d'environnement
|
||||
Fichier `.env` configuré avec :
|
||||
- Database PostgreSQL
|
||||
- CORS
|
||||
- Workers parallèles
|
||||
- AUDIO_LIBRARY_PATH (à personnaliser)
|
||||
|
||||
### Migration DB
|
||||
✅ Exécutée avec succès :
|
||||
```bash
|
||||
docker exec audio_classifier_api alembic upgrade head
|
||||
```
|
||||
|
||||
## 📊 Performance
|
||||
|
||||
**Analyse audio (sans Essentia)** :
|
||||
- ~0.5-1s par fichier
|
||||
- Parallélisation : 4 workers
|
||||
- 1000 fichiers ≈ 10-15 minutes
|
||||
|
||||
**Avec Essentia** (si activé) :
|
||||
- ~2-3s par fichier
|
||||
- 1000 fichiers ≈ 40-50 minutes
|
||||
|
||||
## 🚀 Utilisation
|
||||
|
||||
### 1. Services démarrés
|
||||
```bash
|
||||
docker-compose -f docker-compose.dev.yml ps
|
||||
```
|
||||
|
||||
### 2. Tester l'API
|
||||
```bash
|
||||
curl http://localhost:8001/health
|
||||
curl http://localhost:8001/api/stats
|
||||
```
|
||||
|
||||
### 3. Lancer le frontend
|
||||
```bash
|
||||
cd frontend
|
||||
npm install # Si pas déjà fait
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 4. Analyser des fichiers
|
||||
```bash
|
||||
curl -X POST http://localhost:8001/api/analyze/folder \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"path": "/audio", "recursive": true}'
|
||||
```
|
||||
|
||||
## 📁 Structure projet
|
||||
|
||||
```
|
||||
Audio Classifier/
|
||||
├── backend/ ✅ Complet
|
||||
│ ├── src/core/ ✅ Audio processing
|
||||
│ ├── src/models/ ✅ Database
|
||||
│ ├── src/api/ ✅ FastAPI routes
|
||||
│ ├── Dockerfile.minimal ✅ Build sans Essentia
|
||||
│ └── requirements-minimal.txt ✅ Dépendances
|
||||
├── frontend/ ✅ MVP
|
||||
│ ├── app/ ✅ Next.js pages
|
||||
│ ├── lib/ ✅ API client
|
||||
│ └── components/ 🚧 Basique
|
||||
├── scripts/ ✅
|
||||
│ └── download-essentia-models.sh
|
||||
├── docker-compose.dev.yml ✅ Config actuelle
|
||||
└── Documentation/ ✅ Complète
|
||||
├── README.md
|
||||
├── SETUP.md
|
||||
├── QUICKSTART.md
|
||||
├── DEMARRAGE.md
|
||||
└── STATUS.md (ce fichier)
|
||||
```
|
||||
|
||||
## 🎯 Prochaines étapes suggérées
|
||||
|
||||
### Court terme
|
||||
1. **Analyser votre bibliothèque** : Tester avec vos fichiers audio
|
||||
2. **Explorer le frontend** : Vérifier l'affichage des pistes
|
||||
3. **Tester la recherche** : Filtrer les résultats
|
||||
|
||||
### Moyen terme
|
||||
1. **Activer Essentia** (optionnel) : Pour classification genre/mood
|
||||
2. **Améliorer le frontend** :
|
||||
- Player audio intégré
|
||||
- Filtres avancés
|
||||
- Waveform interactive
|
||||
|
||||
### Long terme
|
||||
1. **CLAP embeddings** : Recherche sémantique avancée
|
||||
2. **Export playlists** : M3U, CSV, JSON
|
||||
3. **Authentication** : Multi-utilisateurs
|
||||
4. **Duplicate detection** : Audio fingerprinting
|
||||
|
||||
## 🐛 Bugs connus
|
||||
|
||||
Aucun bug critique identifié.
|
||||
|
||||
## 📚 Documentation
|
||||
|
||||
- **[DEMARRAGE.md](DEMARRAGE.md)** : Guide de démarrage immédiat
|
||||
- **[QUICKSTART.md](QUICKSTART.md)** : Démarrage en 5 minutes
|
||||
- **[SETUP.md](SETUP.md)** : Guide complet + troubleshooting
|
||||
- **[README.md](README.md)** : Vue d'ensemble
|
||||
- **API Docs** : http://localhost:8001/docs
|
||||
|
||||
## ✨ Conclusion
|
||||
|
||||
Le système est **100% fonctionnel** pour :
|
||||
- ✅ Extraction de features audio
|
||||
- ✅ Stockage en base de données
|
||||
- ✅ API REST complète
|
||||
- ✅ Streaming et téléchargement audio
|
||||
- ✅ Recherche et filtres
|
||||
- ✅ Interface web basique
|
||||
|
||||
**Classification IA optionnelle** (Essentia) peut être ajoutée facilement si besoin.
|
||||
|
||||
Le projet est prêt à être utilisé ! 🎵
|
||||
@@ -1,13 +0,0 @@
|
||||
# Database
|
||||
DATABASE_URL=postgresql://audio_user:audio_password@localhost:5432/audio_classifier
|
||||
|
||||
# API Configuration
|
||||
CORS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000
|
||||
|
||||
# Audio Analysis
|
||||
ANALYSIS_USE_CLAP=false
|
||||
ANALYSIS_NUM_WORKERS=4
|
||||
ESSENTIA_MODELS_PATH=./models
|
||||
|
||||
# Audio Library
|
||||
AUDIO_LIBRARY_PATH=/path/to/your/audio/library
|
||||
@@ -32,7 +32,7 @@ WORKDIR /app
|
||||
RUN pip install --no-cache-dir --upgrade pip setuptools wheel
|
||||
|
||||
# Copy requirements
|
||||
COPY requirements.txt .
|
||||
COPY backend/requirements.txt .
|
||||
|
||||
# Install Python dependencies in stages for better caching
|
||||
# Using versions compatible with Python 3.9
|
||||
@@ -45,10 +45,11 @@ RUN pip install --no-cache-dir essentia-tensorflow
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Copy application code
|
||||
COPY src/ ./src/
|
||||
COPY alembic.ini .
|
||||
COPY backend/src/ ./src/
|
||||
COPY backend/alembic.ini .
|
||||
|
||||
COPY src/models/ ./models/
|
||||
# Copy Essentia models into image (28 MB total)
|
||||
COPY backend/models/ ./models/
|
||||
RUN ls -lh /app/models
|
||||
|
||||
# Expose port
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y \
|
||||
ffmpeg \
|
||||
libsndfile1 \
|
||||
gcc \
|
||||
g++ \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Upgrade pip
|
||||
RUN pip install --no-cache-dir --upgrade pip setuptools wheel
|
||||
|
||||
# Copy minimal requirements
|
||||
COPY requirements-minimal.txt .
|
||||
|
||||
# Install dependencies
|
||||
RUN pip install --no-cache-dir -r requirements-minimal.txt
|
||||
|
||||
# Copy application code
|
||||
COPY src/ ./src/
|
||||
COPY alembic.ini .
|
||||
|
||||
# Create models directory
|
||||
RUN mkdir -p /app/models
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Run server (skip migrations for now)
|
||||
CMD uvicorn src.api.main:app --host 0.0.0.0 --port 8000
|
||||
52
backend/models/README.md
Normal file
52
backend/models/README.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Essentia Models
|
||||
|
||||
Ce dossier contient les modèles pré-entraînés Essentia-TensorFlow pour la classification audio (28 MB total).
|
||||
|
||||
## Modèles requis
|
||||
|
||||
Les fichiers suivants sont nécessaires pour le fonctionnement de l'application :
|
||||
|
||||
1. **discogs-effnet-bs64-1.pb** (18 MB) - Embedding model
|
||||
2. **genre_discogs400-discogs-effnet-1.pb** (2 MB) - Genre classifier
|
||||
3. **genre_discogs400-discogs-effnet-1.json** (15 KB) - Genre metadata
|
||||
4. **mtg_jamendo_moodtheme-discogs-effnet-1.pb** (2.7 MB) - Mood classifier
|
||||
5. **mtg_jamendo_instrument-discogs-effnet-1.pb** (2.6 MB) - Instrument classifier
|
||||
6. **mtg_jamendo_genre-discogs-effnet-1.pb** (2.7 MB) - Alternative genre classifier
|
||||
|
||||
## Téléchargement automatique
|
||||
|
||||
**Pour les utilisateurs** : Les modèles sont déjà inclus dans les images Docker depuis le registry `git.benoitsz.com`. Aucune action nécessaire.
|
||||
|
||||
**Pour le CI/CD** : Les modèles sont téléchargés automatiquement depuis essentia.upf.edu pendant le build (voir `.gitea/workflows/docker.yml`).
|
||||
|
||||
**Pour le développement local** : Si vous avez besoin de builder localement, vous devez avoir les modèles dans ce dossier. Ils ne sont pas versionnés dans Git car ils pèsent 28 MB.
|
||||
|
||||
### Téléchargement manuel (si nécessaire)
|
||||
|
||||
```bash
|
||||
cd backend/models
|
||||
|
||||
# Embedding model (18 MB)
|
||||
curl -L -O https://essentia.upf.edu/models/feature-extractors/discogs-effnet/discogs-effnet-bs64-1.pb
|
||||
|
||||
# Genre classifier (2 MB)
|
||||
curl -L -O https://essentia.upf.edu/models/classification-heads/genre_discogs400/genre_discogs400-discogs-effnet-1.pb
|
||||
curl -L -O https://essentia.upf.edu/models/classification-heads/genre_discogs400/genre_discogs400-discogs-effnet-1.json
|
||||
|
||||
# Mood classifier (2.7 MB)
|
||||
curl -L -O https://essentia.upf.edu/models/classification-heads/mtg_jamendo_moodtheme/mtg_jamendo_moodtheme-discogs-effnet-1.pb
|
||||
|
||||
# Instrument classifier (2.6 MB)
|
||||
curl -L -O https://essentia.upf.edu/models/classification-heads/mtg_jamendo_instrument/mtg_jamendo_instrument-discogs-effnet-1.pb
|
||||
|
||||
# Alternative genre classifier (2.7 MB)
|
||||
curl -L -O https://essentia.upf.edu/models/classification-heads/mtg_jamendo_genre/mtg_jamendo_genre-discogs-effnet-1.pb
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
Tous les modèles proviennent du projet Essentia : https://essentia.upf.edu/models/
|
||||
|
||||
## Licence
|
||||
|
||||
Ces modèles sont fournis par le Music Technology Group de l'Universitat Pompeu Fabra sous licence permissive pour usage académique et commercial.
|
||||
@@ -1,31 +0,0 @@
|
||||
# Minimal requirements (without Essentia for faster build)
|
||||
|
||||
# Web Framework
|
||||
fastapi==0.109.0
|
||||
uvicorn[standard]==0.27.0
|
||||
python-multipart==0.0.6
|
||||
|
||||
# Database
|
||||
sqlalchemy==2.0.25
|
||||
psycopg2-binary==2.9.9
|
||||
pgvector==0.2.4
|
||||
alembic==1.13.1
|
||||
|
||||
# Audio Processing (without Essentia)
|
||||
librosa==0.10.1
|
||||
soundfile==0.12.1
|
||||
audioread==3.0.1
|
||||
mutagen==1.47.0
|
||||
|
||||
# Scientific Computing
|
||||
numpy==1.24.3
|
||||
scipy==1.11.4
|
||||
|
||||
# Configuration & Validation
|
||||
pydantic==2.5.3
|
||||
pydantic-settings==2.1.0
|
||||
python-dotenv==1.0.0
|
||||
|
||||
# Utilities
|
||||
aiofiles==23.2.1
|
||||
httpx==0.26.0
|
||||
@@ -10,7 +10,8 @@ class Settings(BaseSettings):
|
||||
DATABASE_URL: str = "postgresql://audio_user:audio_password@localhost:5432/audio_classifier"
|
||||
|
||||
# API Configuration
|
||||
CORS_ORIGINS: str = "http://localhost:3000,http://127.0.0.1:3000"
|
||||
# Comma-separated list of allowed origins, or use "*" to allow all
|
||||
CORS_ORIGINS: str = "*"
|
||||
API_HOST: str = "0.0.0.0"
|
||||
API_PORT: int = 8000
|
||||
|
||||
@@ -33,7 +34,13 @@ class Settings(BaseSettings):
|
||||
|
||||
@property
|
||||
def cors_origins_list(self) -> List[str]:
|
||||
"""Parse CORS origins string to list."""
|
||||
"""Parse CORS origins string to list.
|
||||
|
||||
If CORS_ORIGINS is "*", allow all origins.
|
||||
Otherwise, parse comma-separated list.
|
||||
"""
|
||||
if self.CORS_ORIGINS.strip() == "*":
|
||||
return ["*"]
|
||||
return [origin.strip() for origin in self.CORS_ORIGINS.split(",")]
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
version: '3.8'
|
||||
# Docker Compose pour build local (développement)
|
||||
# Usage: docker-compose -f docker-compose.build.yml build
|
||||
|
||||
services:
|
||||
postgres:
|
||||
@@ -20,43 +21,40 @@ services:
|
||||
retries: 5
|
||||
restart: unless-stopped
|
||||
|
||||
# Backend with minimal dependencies (no Essentia)
|
||||
backend:
|
||||
build:
|
||||
context: ./backend
|
||||
dockerfile: Dockerfile.minimal
|
||||
context: .
|
||||
dockerfile: backend/Dockerfile
|
||||
container_name: audio_classifier_api
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER:-audio_user}:${POSTGRES_PASSWORD:-audio_password}@postgres:5432/${POSTGRES_DB:-audio_classifier}
|
||||
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000}
|
||||
ANALYSIS_USE_CLAP: "false"
|
||||
CORS_ORIGINS: ${CORS_ORIGINS:-*}
|
||||
ANALYSIS_USE_CLAP: ${ANALYSIS_USE_CLAP:-false}
|
||||
ANALYSIS_NUM_WORKERS: ${ANALYSIS_NUM_WORKERS:-4}
|
||||
ESSENTIA_MODELS_PATH: /app/models
|
||||
ports:
|
||||
- "8001:8000"
|
||||
volumes:
|
||||
# Mount your audio library (read-only)
|
||||
- ${AUDIO_LIBRARY_PATH:-./audio_samples}:/audio:ro
|
||||
# Development: mount source for hot reload
|
||||
- ./backend/src:/app/src
|
||||
# Mount your audio library (read-write for transcoding and waveforms)
|
||||
- ${AUDIO_LIBRARY_PATH:-./audio_samples}:/audio
|
||||
restart: unless-stopped
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile.dev
|
||||
container_name: audio_classifier_ui_dev
|
||||
context: .
|
||||
dockerfile: frontend/Dockerfile
|
||||
args:
|
||||
NEXT_PUBLIC_API_URL: http://localhost:8001
|
||||
container_name: audio_classifier_ui
|
||||
environment:
|
||||
NEXT_PUBLIC_API_URL: http://backend:8000
|
||||
NODE_ENV: development
|
||||
# Use localhost:8001 because the browser (client-side) needs to access the API
|
||||
# The backend is mapped to port 8001 on the host machine
|
||||
NEXT_PUBLIC_API_URL: http://localhost:8001
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
- /app/node_modules
|
||||
depends_on:
|
||||
- backend
|
||||
restart: unless-stopped
|
||||
@@ -19,14 +19,14 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
backend:
|
||||
build: ./backend
|
||||
image: git.benoitsz.com/benoit/audio-classifier-backend:dev
|
||||
container_name: audio_classifier_api
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DATABASE_URL: postgresql://${POSTGRES_USER:-audio_user}:${POSTGRES_PASSWORD:-audio_password}@postgres:5432/${POSTGRES_DB:-audio_classifier}
|
||||
CORS_ORIGINS: ${CORS_ORIGINS:-http://localhost:3000}
|
||||
CORS_ORIGINS: ${CORS_ORIGINS:-*}
|
||||
ANALYSIS_USE_CLAP: ${ANALYSIS_USE_CLAP:-false}
|
||||
ANALYSIS_NUM_WORKERS: ${ANALYSIS_NUM_WORKERS:-4}
|
||||
ESSENTIA_MODELS_PATH: /app/models
|
||||
@@ -38,15 +38,12 @@ services:
|
||||
restart: unless-stopped
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ./frontend
|
||||
args:
|
||||
NEXT_PUBLIC_API_URL: http://localhost:8001
|
||||
image: git.benoitsz.com/benoit/audio-classifier-frontend:dev
|
||||
container_name: audio_classifier_ui
|
||||
environment:
|
||||
# Use localhost:8001 because the browser (client-side) needs to access the API
|
||||
# The backend is mapped to port 8001 on the host machine
|
||||
NEXT_PUBLIC_API_URL: http://localhost:8001
|
||||
# In production, set NEXT_PUBLIC_API_URL to your server's public URL
|
||||
# Example: NEXT_PUBLIC_API_URL=https://yourserver.com:8001
|
||||
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8001}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
|
||||
@@ -1 +1 @@
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8000
|
||||
NEXT_PUBLIC_API_URL=http://localhost:8001
|
||||
|
||||
@@ -4,26 +4,27 @@ FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
COPY frontend/package*.json ./
|
||||
|
||||
# Debug: List files and Node.js version
|
||||
RUN ls -la && node --version && npm --version
|
||||
|
||||
# Install dependencies with more verbose output
|
||||
RUN npm install --verbose
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Copy application code
|
||||
COPY . .
|
||||
COPY frontend/ .
|
||||
|
||||
# Build argument for API URL
|
||||
# Build argument for API URL (used for default build)
|
||||
ARG NEXT_PUBLIC_API_URL=http://localhost:8001
|
||||
ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL}
|
||||
|
||||
# Build the application
|
||||
RUN npm run build
|
||||
|
||||
# Copy runtime config generation script
|
||||
COPY frontend/generate-config.sh /app/generate-config.sh
|
||||
RUN chmod +x /app/generate-config.sh
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000
|
||||
|
||||
# Start the application
|
||||
CMD ["npm", "start"]
|
||||
# Generate runtime config and start the application
|
||||
CMD ["/bin/sh", "-c", "/app/generate-config.sh && npm start"]
|
||||
|
||||
93
frontend/README.md
Normal file
93
frontend/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Frontend - Audio Classifier
|
||||
|
||||
Frontend Next.js pour Audio Classifier avec configuration runtime.
|
||||
|
||||
## Configuration Runtime
|
||||
|
||||
Le frontend utilise un système de **configuration runtime** qui permet de changer l'URL de l'API sans rebuilder l'image Docker.
|
||||
|
||||
### Comment ça fonctionne
|
||||
|
||||
1. Au démarrage du container, le script `generate-config.sh` génère un fichier `/app/public/config.js`
|
||||
2. Ce fichier contient l'URL de l'API basée sur la variable `NEXT_PUBLIC_API_URL`
|
||||
3. Le fichier est chargé dans le navigateur via `<Script src="/config.js">`
|
||||
4. Le code API lit la configuration depuis `window.__RUNTIME_CONFIG__.API_URL`
|
||||
|
||||
### Développement Local
|
||||
|
||||
```bash
|
||||
# Installer les dépendances
|
||||
npm install
|
||||
|
||||
# Créer un fichier .env.local
|
||||
echo "NEXT_PUBLIC_API_URL=http://localhost:8001" > .env.local
|
||||
|
||||
# Lancer en mode dev
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### Production avec Docker
|
||||
|
||||
```bash
|
||||
# Build l'image
|
||||
docker build -t audio-classifier-frontend -f frontend/Dockerfile .
|
||||
|
||||
# Lancer avec une URL personnalisée
|
||||
docker run -p 3000:3000 \
|
||||
-e NEXT_PUBLIC_API_URL=https://mon-serveur.com:8001 \
|
||||
audio-classifier-frontend
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
frontend:
|
||||
image: audio-classifier-frontend
|
||||
environment:
|
||||
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8001}
|
||||
ports:
|
||||
- "3000:3000"
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
frontend/
|
||||
├── app/ # Pages Next.js (App Router)
|
||||
│ ├── layout.tsx # Layout principal (charge config.js)
|
||||
│ └── page.tsx # Page d'accueil
|
||||
├── components/ # Composants React
|
||||
├── lib/ # Utilitaires
|
||||
│ ├── api.ts # Client API (lit la config runtime)
|
||||
│ └── types.ts # Types TypeScript
|
||||
├── public/ # Fichiers statiques
|
||||
│ └── config.js # Configuration runtime (généré au démarrage)
|
||||
├── generate-config.sh # Script de génération de config
|
||||
└── Dockerfile # Image Docker de production
|
||||
```
|
||||
|
||||
## Variables d'Environnement
|
||||
|
||||
- `NEXT_PUBLIC_API_URL` : URL de l'API backend (ex: `https://api.example.com:8001`)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### L'API n'est pas accessible
|
||||
|
||||
Vérifiez que :
|
||||
1. La variable `NEXT_PUBLIC_API_URL` est correctement définie
|
||||
2. Le fichier `/app/public/config.js` existe dans le container
|
||||
3. Le navigateur peut accéder à l'URL de l'API (pas de CORS, firewall, etc.)
|
||||
|
||||
### Voir la configuration active
|
||||
|
||||
Ouvrez la console du navigateur et tapez :
|
||||
```javascript
|
||||
console.log(window.__RUNTIME_CONFIG__)
|
||||
```
|
||||
|
||||
### Vérifier la config dans le container
|
||||
|
||||
```bash
|
||||
docker exec audio_classifier_ui cat /app/public/config.js
|
||||
```
|
||||
@@ -2,6 +2,7 @@ import type { Metadata } from "next"
|
||||
import { Inter } from "next/font/google"
|
||||
import "./globals.css"
|
||||
import { QueryProvider } from "@/components/providers/QueryProvider"
|
||||
import Script from "next/script"
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] })
|
||||
|
||||
@@ -17,6 +18,9 @@ export default function RootLayout({
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<Script src="/config.js" strategy="beforeInteractive" />
|
||||
</head>
|
||||
<body className={inter.className}>
|
||||
<QueryProvider>
|
||||
{children}
|
||||
|
||||
@@ -52,6 +52,7 @@ export default function Home() {
|
||||
const [filters, setFilters] = useState<FilterParams>({})
|
||||
const [page, setPage] = useState(0)
|
||||
const [currentTrack, setCurrentTrack] = useState<Track | null>(null)
|
||||
const [isPlaying, setIsPlaying] = useState(false)
|
||||
const [searchQuery, setSearchQuery] = useState("")
|
||||
const [isScanning, setIsScanning] = useState(false)
|
||||
const [scanStatus, setScanStatus] = useState<string>("")
|
||||
@@ -233,10 +234,19 @@ export default function Home() {
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Play button */}
|
||||
<button
|
||||
onClick={() => setCurrentTrack(track)}
|
||||
onClick={() => {
|
||||
if (currentTrack?.id === track.id) {
|
||||
// Toggle play/pause for current track
|
||||
setIsPlaying(!isPlaying)
|
||||
} else {
|
||||
// Switch to new track and start playing
|
||||
setCurrentTrack(track)
|
||||
setIsPlaying(true)
|
||||
}
|
||||
}}
|
||||
className="flex-shrink-0 w-12 h-12 flex items-center justify-center bg-orange-500 hover:bg-orange-600 rounded-full transition-colors shadow-sm"
|
||||
>
|
||||
{currentTrack?.id === track.id ? (
|
||||
{currentTrack?.id === track.id && isPlaying ? (
|
||||
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/>
|
||||
</svg>
|
||||
@@ -347,7 +357,11 @@ export default function Home() {
|
||||
|
||||
{/* Fixed Audio Player at bottom */}
|
||||
<div className="fixed bottom-0 left-0 right-0 z-50">
|
||||
<AudioPlayer track={currentTrack} />
|
||||
<AudioPlayer
|
||||
track={currentTrack}
|
||||
isPlaying={isPlaying}
|
||||
onPlayingChange={setIsPlaying}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,10 +5,11 @@ import type { Track } from "@/lib/types"
|
||||
|
||||
interface AudioPlayerProps {
|
||||
track: Track | null
|
||||
isPlaying: boolean
|
||||
onPlayingChange: (playing: boolean) => void
|
||||
}
|
||||
|
||||
export default function AudioPlayer({ track }: AudioPlayerProps) {
|
||||
const [isPlaying, setIsPlaying] = useState(false)
|
||||
export default function AudioPlayer({ track, isPlaying, onPlayingChange }: AudioPlayerProps) {
|
||||
const [currentTime, setCurrentTime] = useState(0)
|
||||
const [duration, setDuration] = useState(0)
|
||||
const [volume, setVolume] = useState(1)
|
||||
@@ -22,7 +23,7 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
|
||||
// Load audio and waveform when track changes
|
||||
useEffect(() => {
|
||||
if (!track) {
|
||||
setIsPlaying(false)
|
||||
onPlayingChange(false)
|
||||
setCurrentTime(0)
|
||||
setWaveformPeaks([])
|
||||
return
|
||||
@@ -33,13 +34,13 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
|
||||
|
||||
if (audioRef.current) {
|
||||
audioRef.current.load()
|
||||
// Autoplay when track loads
|
||||
audioRef.current.play().then(() => {
|
||||
setIsPlaying(true)
|
||||
}).catch((error: unknown) => {
|
||||
console.error("Autoplay failed:", error)
|
||||
setIsPlaying(false)
|
||||
})
|
||||
// Autoplay when track loads if isPlaying is true
|
||||
if (isPlaying) {
|
||||
audioRef.current.play().catch((error: unknown) => {
|
||||
console.error("Autoplay failed:", error)
|
||||
onPlayingChange(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [track?.id])
|
||||
|
||||
@@ -54,7 +55,7 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
|
||||
setDuration(audio.duration)
|
||||
}
|
||||
}
|
||||
const handleEnded = () => setIsPlaying(false)
|
||||
const handleEnded = () => onPlayingChange(false)
|
||||
|
||||
audio.addEventListener("timeupdate", updateTime)
|
||||
audio.addEventListener("loadedmetadata", updateDuration)
|
||||
@@ -91,15 +92,24 @@ export default function AudioPlayer({ track }: AudioPlayerProps) {
|
||||
}
|
||||
}
|
||||
|
||||
const togglePlay = () => {
|
||||
if (!audioRef.current || !track) return
|
||||
// Sync playing state with audio element
|
||||
useEffect(() => {
|
||||
const audio = audioRef.current
|
||||
if (!audio) return
|
||||
|
||||
if (isPlaying) {
|
||||
audioRef.current.pause()
|
||||
audio.play().catch((error: unknown) => {
|
||||
console.error("Play failed:", error)
|
||||
onPlayingChange(false)
|
||||
})
|
||||
} else {
|
||||
audioRef.current.play()
|
||||
audio.pause()
|
||||
}
|
||||
setIsPlaying(!isPlaying)
|
||||
}, [isPlaying, onPlayingChange])
|
||||
|
||||
const togglePlay = () => {
|
||||
if (!audioRef.current || !track) return
|
||||
onPlayingChange(!isPlaying)
|
||||
}
|
||||
|
||||
const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
||||
15
frontend/generate-config.sh
Normal file
15
frontend/generate-config.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Generate runtime configuration file
|
||||
|
||||
echo "Generating runtime configuration..."
|
||||
echo "API URL: ${NEXT_PUBLIC_API_URL:-http://localhost:8001}"
|
||||
|
||||
cat > /app/public/config.js << EOF
|
||||
// Runtime configuration generated at container startup
|
||||
window.__RUNTIME_CONFIG__ = {
|
||||
API_URL: '${NEXT_PUBLIC_API_URL:-http://localhost:8001}'
|
||||
};
|
||||
EOF
|
||||
|
||||
echo "Configuration generated successfully!"
|
||||
cat /app/public/config.js
|
||||
@@ -14,7 +14,15 @@ import type {
|
||||
FilterParams,
|
||||
} from './types'
|
||||
|
||||
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'
|
||||
// Get API URL from runtime config (injected at container startup) or fallback to env var
|
||||
function getApiUrl(): string {
|
||||
if (typeof window !== 'undefined' && (window as any).__RUNTIME_CONFIG__) {
|
||||
return (window as any).__RUNTIME_CONFIG__.API_URL
|
||||
}
|
||||
return process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8000'
|
||||
}
|
||||
|
||||
const API_BASE_URL = getApiUrl()
|
||||
|
||||
const apiClient = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
|
||||
4
frontend/public/config.js
Normal file
4
frontend/public/config.js
Normal file
@@ -0,0 +1,4 @@
|
||||
// This file will be overwritten at container startup
|
||||
window.__RUNTIME_CONFIG__ = {
|
||||
API_URL: 'http://localhost:8001'
|
||||
};
|
||||
@@ -1,73 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Download Essentia models for audio classification
|
||||
# Models from: https://essentia.upf.edu/models.html
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
MODELS_DIR="backend/models"
|
||||
CLASS_HEADS_URL="https://essentia.upf.edu/models/classification-heads"
|
||||
EMBEDDINGS_URL="https://essentia.upf.edu/models/feature-extractors/discogs-effnet"
|
||||
|
||||
echo "📦 Downloading Essentia models..."
|
||||
echo "Models directory: $MODELS_DIR"
|
||||
|
||||
# Create models directory if it doesn't exist
|
||||
mkdir -p "$MODELS_DIR"
|
||||
|
||||
# Download function
|
||||
download_model() {
|
||||
local model_file="$1"
|
||||
local url="$2"
|
||||
local output_path="$MODELS_DIR/$model_file"
|
||||
|
||||
if [ -f "$output_path" ]; then
|
||||
echo "✓ $model_file already exists, skipping..."
|
||||
else
|
||||
echo "⬇️ Downloading $model_file..."
|
||||
# Use -k flag to ignore SSL certificate issues with essentia.upf.edu
|
||||
curl -k -L -o "$output_path" "$url"
|
||||
|
||||
if [ -f "$output_path" ] && [ -s "$output_path" ]; then
|
||||
echo "✓ Downloaded $model_file ($(du -h "$output_path" | cut -f1))"
|
||||
else
|
||||
echo "✗ Failed to download $model_file"
|
||||
rm -f "$output_path" # Remove empty/failed file
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Download embedding model first (required for all classification heads)
|
||||
echo ""
|
||||
echo "Downloading embedding model..."
|
||||
download_model "discogs-effnet-bs64-1.pb" \
|
||||
"$EMBEDDINGS_URL/discogs-effnet-bs64-1.pb"
|
||||
|
||||
# Download classification heads
|
||||
echo ""
|
||||
echo "Downloading classification heads..."
|
||||
|
||||
# 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"
|
||||
|
||||
download_model "mtg_jamendo_instrument-discogs-effnet-1.pb" \
|
||||
"$CLASS_HEADS_URL/mtg_jamendo_instrument/mtg_jamendo_instrument-discogs-effnet-1.pb"
|
||||
|
||||
echo ""
|
||||
echo "✅ All models downloaded successfully!"
|
||||
echo ""
|
||||
echo "Models available:"
|
||||
ls -lh "$MODELS_DIR"/*.pb 2>/dev/null || echo "No .pb files found"
|
||||
|
||||
echo ""
|
||||
echo "Note: Class labels are defined in backend/src/core/essentia_classifier.py"
|
||||
echo "You can now start the backend with: docker-compose up"
|
||||
Reference in New Issue
Block a user