Blend taste profile with text-embedded mood descriptions (e.g. "chill ambient lo-fi") using pre-blended vector search against the existing HNSW index. New optional `vibe` and `alpha` params on playlist generate and recommendations endpoints. Backward compatible — no vibe = pure taste profile (alpha=1.0). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2.3 KiB
2.3 KiB
haunt-fm
Personal music recommendation service. Captures listening history from Music Assistant, discovers similar tracks via Last.fm, embeds audio with CLAP, and generates playlists.
Quick Start
# On NAS
cd /volume1/homes/antialias/projects/haunt-fm
docker compose up -d
docker compose exec haunt-fm alembic upgrade head
Architecture
- FastAPI app with async SQLAlchemy + asyncpg
- PostgreSQL + pgvector for tracks, embeddings, and vector similarity search
- CLAP model (laion/larger_clap_music) for 512-dim audio embeddings
- Last.fm API for track similarity discovery
- iTunes Search API for 30-second audio previews
- Music Assistant (via Home Assistant REST API) for playback
Key Commands
# Health check
curl http://192.168.86.51:8321/health
# Log a listen event
curl -X POST http://192.168.86.51:8321/api/history/webhook \
-H "Content-Type: application/json" \
-d '{"title":"Song","artist":"Artist"}'
# Run discovery
curl -X POST http://192.168.86.51:8321/api/admin/discover -H "Content-Type: application/json" -d '{}'
# Get recommendations
curl http://192.168.86.51:8321/api/recommendations?limit=20
# Generate and play a playlist
curl -X POST http://192.168.86.51:8321/api/playlists/generate \
-H "Content-Type: application/json" \
-d '{"total_tracks":20,"known_pct":30,"speaker_entity":"media_player.living_room_speaker_2","auto_play":true}'
# Generate a vibe-based playlist (mood/activity matching)
curl -X POST http://192.168.86.51:8321/api/playlists/generate \
-H "Content-Type: application/json" \
-d '{"total_tracks":15,"vibe":"chill ambient lo-fi","speaker_entity":"media_player.living_room_speaker_2","auto_play":true}'
# Vibe with custom blend (alpha: 0=pure vibe, 0.5=blend, 1=pure taste)
curl -X POST http://192.168.86.51:8321/api/playlists/generate \
-H "Content-Type: application/json" \
-d '{"total_tracks":15,"vibe":"upbeat party music","alpha":0.3,"auto_play":true,"speaker_entity":"media_player.living_room_speaker_2"}'
Environment Variables
All prefixed with HAUNTFM_. See .env.example for full list.
Database
- Alembic migrations in
alembic/versions/ - Run migrations:
alembic upgrade head - Schema: tracks, listen_events, track_embeddings, similarity_links, taste_profiles, playlists, playlist_tracks