Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
ad30ba9
Add multi-provider support and local file media provider
claude Feb 4, 2026
79c8970
Add provider-aware API helpers with backward compatibility
claude Feb 4, 2026
6d575fc
Add split deployment support for remote workers
claude Feb 4, 2026
9b2d821
Clarify unified compose files for CPU and NVIDIA in setup wizard
claude Feb 4, 2026
9287f36
Add dedicated Settings page for configuration management
claude Feb 4, 2026
ab3b39a
Add multi-provider playlist creation with provider selector dropdown
claude Feb 4, 2026
0c3fbaa
Merge branch 'NeptuneHub:main' into claude/multi-provider-local-files…
rendyhd Feb 4, 2026
5a70ece
Merge feature/album-artist-support into multi-provider branch
claude Feb 4, 2026
ef30d3a
Merge branch 'claude/multi-provider-local-files-zseAX' of http://127.…
claude Feb 4, 2026
9987a83
Implement track linking mechanism for multi-provider support
claude Feb 4, 2026
f64bff9
Improve file path normalization for cross-provider matching
claude Feb 4, 2026
7f3fbcc
Add provider-specific music_path_prefix for path normalization
claude Feb 4, 2026
83014e3
Add music_path_prefix configuration field to all providers
claude Feb 4, 2026
c07762d
Add auto-detection of music_path_prefix during provider setup
claude Feb 4, 2026
90a15a8
Fix cross-provider analysis reuse to prevent duplicate track processing
claude Feb 4, 2026
c0c91f9
Many bug fixes
rendyhd Feb 4, 2026
0342a9d
Add comprehensive testing and comparison suite for dual-instance comp…
claude Feb 5, 2026
f42fe8f
Add .gitignore for testing suite report output directory
claude Feb 5, 2026
bfaa3f0
Add comprehensive README guide for the testing and comparison suite
claude Feb 5, 2026
1446375
bug fixes and hardware selection on setup
rendyhd Feb 5, 2026
ea4c0aa
Merge pull request #2 from rendyhd/multi-provider-setup-gui
rendyhd Feb 5, 2026
e22c985
bug fixes
rendyhd Feb 5, 2026
eb7fa56
Merge pull request #3 from rendyhd/multi-provider-testing-suite
rendyhd Feb 5, 2026
f6b4cbf
Prompt tests
rendyhd Feb 6, 2026
f33ed9c
Merge pull request #4 from rendyhd/multi-provider-testing-suite
rendyhd Feb 6, 2026
da5f563
- Added library selection in the setup
rendyhd Feb 6, 2026
495b2f8
Branch review fixes: security, bugs, thread safety, XSS, MPD removal,…
rendyhd Feb 8, 2026
2c78454
bug fixes and test expansion. Ready for testing
rendyhd Feb 9, 2026
2a4a844
clean compose
rendyhd Feb 9, 2026
e680b89
Merge pull request #5 from rendyhd/multi-provider-v2
rendyhd Feb 11, 2026
03add7a
Ongoing tests, initial minor bugs
rendyhd Feb 11, 2026
163dab5
Bufixes
rendyhd Feb 11, 2026
a7a5007
Prevent track duplication across providers with metadata-based fallback
rendyhd Feb 27, 2026
4c00f26
Multi-provider setup improvements: auto-config, sync endpoint, path w…
rendyhd Feb 27, 2026
5019b50
Add AI API key fields to Settings UI with Fernet encryption
rendyhd Feb 28, 2026
adfd4cd
Fix song number truncation at 100 in instant playlist
rendyhd Feb 28, 2026
ae376af
Add duplicate detection, provider health checks, and path validation
rendyhd Feb 28, 2026
32ca183
Add album support to AI instant playlist tools and search_database
rendyhd Mar 1, 2026
b2eb812
Merge main into multi-provider-setup-gui: sync with v0.9.2
rendyhd Mar 14, 2026
5a68f78
Fix test failures: patch config module and mock context managers
rendyhd Mar 14, 2026
236f3b7
Remove unnecessary complexity: encryption layer, dead columns, deprec…
rendyhd Mar 14, 2026
48789b8
feat: foolproof file/track matching with blocking validation, rehash …
claude Mar 14, 2026
bfc4679
Merge pull request #7 from rendyhd/claude/file-matching-research-CPNEV
rendyhd Mar 15, 2026
2a87704
Fix 40 bugs across 4 review rounds for multi-provider branch
rendyhd Mar 17, 2026
fcff689
Fix 23 bugs from comprehensive multi-provider branch review
rendyhd Mar 17, 2026
74cac27
Expose file_path in track APIs and add path-based lookup endpoints
rendyhd Mar 17, 2026
851b205
Fix 7 bugs from code review: config leak, Voyager dedup, infinite loo…
rendyhd Mar 18, 2026
b11865f
Add unified compose files for local builds and seamless provider upgrade
rendyhd Mar 22, 2026
f681f63
Fix provider validation, warnings, and UI across multi-provider setup
rendyhd Mar 22, 2026
f6a3a99
Add cross-provider track linking during analysis with legacy backfill
rendyhd Mar 22, 2026
215902f
Add scroll to sidebar menu when items overflow viewport
rendyhd Mar 22, 2026
5420988
Fix multi-provider playlist creation and backfill normalization
rendyhd Mar 22, 2026
cc0bf0e
Add cross-provider item_id resolution to all API endpoints
rendyhd Mar 22, 2026
5751846
Add cross-provider artist_id resolution for similar_artists API
rendyhd Mar 22, 2026
5d10be1
Redesign data architecture: canonical track_id replaces provider-spec…
rendyhd Mar 22, 2026
5717483
Merge pull request #9 from rendyhd/feature/track-id-canonical-archite…
rendyhd Mar 22, 2026
f175a62
Auto-run canonical track_id migration at startup in init_db
rendyhd Mar 22, 2026
932a342
Remove dev artifacts, dead code, and unnecessary test bloat to reduce…
rendyhd Mar 22, 2026
36f8b59
Fix 6 issues from code review: rehash bug, dead code, README, duplica…
rendyhd Mar 22, 2026
004ecf2
Merge remote-tracking branch 'origin/main' into multi-provider-setup-gui
rendyhd Mar 22, 2026
b54a32b
Fix settings UI, GPU detection, compose env vars, and duplicate check
rendyhd Mar 23, 2026
9c9db8b
Fix cross-provider hash matching and DB resilience
rendyhd Mar 23, 2026
3b2eeaa
Fix artist mapping storage and analysis provider resolution
rendyhd Mar 23, 2026
1d5b0f5
Fix artist ID truncation test index after multi-provider refactor
rendyhd Mar 23, 2026
31b1cb7
Fix 7 API regressions from track_id migration
rendyhd Mar 23, 2026
3db421c
Route play history through primary provider instead of legacy MEDIASE…
rendyhd Mar 23, 2026
9e204c1
Fix 12 code review issues and 5 CI test failures
rendyhd Mar 23, 2026
429a8d3
Fix test_cleanup_onnx_sessions_on_success missing file_path in mock data
rendyhd Mar 23, 2026
a42b4ca
Fix primary_provider_id, make deployment cards read-only, improve son…
rendyhd Mar 24, 2026
2fbf7c0
Seed AI settings from env vars on startup, make analysis page AI sect…
rendyhd Mar 24, 2026
8610cb0
Add delta scan with mtime cache for LocalFiles provider
rendyhd Mar 25, 2026
fdc21fb
Fix sonic fingerprint provider ID crash, add clustering playlist targ…
rendyhd Mar 25, 2026
e151d6e
Remove sync feature from CLAUDE.md, fix dark mode link contrast on an…
rendyhd Mar 25, 2026
52d0aa2
Fix Navidrome User-Agent and prefix detection confidence bug
rendyhd Mar 25, 2026
9601eae
Fix LocalFiles delta scan cache and Navidrome rating backfill
rendyhd Mar 25, 2026
20f0a7a
Fix AI config display, m3u playlist paths, make chat AI section read-…
rendyhd Mar 25, 2026
2ea0c7f
Fix sonic fingerprint tests for resolve_track_id mock
rendyhd Mar 25, 2026
7206059
Fix MEDIASERVER_TYPE="" auto-creating unwanted LocalFiles provider, s…
rendyhd Mar 25, 2026
a34ff7f
Resolve provider type from DB in mediaserver dispatcher, fix Lyrion p…
rendyhd Mar 26, 2026
4c5054f
Pass DB provider credentials through to all mediaserver functions
rendyhd Mar 26, 2026
7c6d956
Fix LocalFiles get_tracks_from_album skipping unanalyzed albums
rendyhd Mar 26, 2026
289ad4b
Fix single-provider path warnings, improve rescan/rehash UX
rendyhd Mar 26, 2026
a207f22
Apply DB settings to workers, fix GPU clustering toggle, improve sett…
rendyhd Mar 26, 2026
6869dd5
Fix test_clustering_helper mock target for USE_GPU_CLUSTERING
rendyhd Mar 26, 2026
eb68e78
Auto-complete setup when migration creates providers with linked tracks
rendyhd Mar 26, 2026
877a619
Fix clustering to read AI settings from Settings page instead of env …
rendyhd Mar 27, 2026
16b80ae
Merge remote-tracking branch 'origin/main' into multi-provider-setup-gui
rendyhd Apr 4, 2026
1984b93
Fix 8 issues from merge review: missing table, stale task blocking, X…
rendyhd Apr 4, 2026
8686579
Update tests to expect cleanup before active-task check
rendyhd Apr 4, 2026
c10f3ed
Merge origin/main: mood centroids, anchor search, sunburst chart
rendyhd Apr 5, 2026
2e25115
fix sonic fingerprint Navidrome config key mismatch in multi-provider…
rendyhd Apr 5, 2026
d0f2a8a
Merge origin/main: backup/restore, submenu UI, sunburst improvements
rendyhd Apr 6, 2026
f42a9bd
fix migration crash on duplicate file paths and harden startup
rendyhd Apr 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@ env/
.pytest_cache/
htmlcov/
nul
testing_suite/reports/

# Testing suite configs (contain API keys / DB passwords)
testing_suite/instant_playlist_test_config.yaml
testing_suite/ai_naming_test_config.yaml
testing_suite/comparison_config.yaml

# Deployment secrets
deployment/main.env

# Large model files in query folder
/query/*.pt
Expand Down
109 changes: 109 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

AudioMuse-AI is a Dockerized music analysis and playlist generation platform. It analyzes audio files from self-hosted media servers (Jellyfin, Navidrome, Lyrion, Emby, LocalFiles) using Librosa and ONNX ML models, then generates playlists through clustering, similarity search, and AI-powered natural language requests.

**Current version:** v0.9.3

## Architecture

**Distributed 3-container system:**
- **Flask container** (`app.py`): Web UI + REST API on port 8000. Registers 17 blueprints (`app_*.py`).
- **Worker containers** (`rq_worker.py`, `rq_worker_high_priority.py`): RQ workers processing analysis/clustering jobs from Redis. Managed by supervisord.
- **PostgreSQL + Redis**: Data storage and job queue.

**Key architectural patterns:**
- Flask blueprints for feature modules (`app_clustering.py`, `app_alchemy.py`, `app_voyager.py`, etc.)
- Media server abstraction via dispatcher pattern in `tasks/mediaserver.py` → individual providers (`mediaserver_jellyfin.py`, `mediaserver_navidrome.py`, etc.)
- Multi-provider support with JSONB config storage, GUI setup wizard (`app_setup.py`), and cross-provider ID remapping
- Background tasks via Redis Queue (RQ) with two priority levels: `high` and `default`
- Voyager HNSW index (Spotify) for vector similarity search (`tasks/voyager_manager.py`)
- Redis Pub/Sub channel `index-updates` for signaling index reloads between worker and Flask processes
- All configuration via environment variables, centralized in `config.py`

**ML pipeline:**
- Audio analysis: Librosa feature extraction → MusiCNN ONNX models → 200-dim embeddings + 50 mood labels + 6 other features (danceable, aggressive, happy, party, relaxed, sad)
- CLAP: Split ONNX models (audio encoder + text encoder) for text-to-audio search
- MuLan: Alternative text-to-audio search using MuQ-MuLan ONNX models
- Clustering: KMeans/DBSCAN/GMM/Spectral with guided evolutionary optimization over N runs

**Instant Playlist (AI agentic loop):**
- 4 AI providers: Gemini, OpenAI, Mistral, Ollama (`ai_mcp_client.py`)
- 6 MCP tools: `song_similarity`, `text_search`, `artist_similarity`, `song_alchemy`, `ai_brainstorm`, `search_database` (`tasks/mcp_server.py`)
- Max 5 iterations, target 100 songs, proportional sampling from tool results
- System prompt built by `_build_system_prompt()`, library context from `get_library_context()`

**Database schema (main table `score`):**
- Columns: `item_id`, `title`, `author`, `album`, `album_artist`, `tempo`, `key`, `scale`, `mood_vector`, `other_features`, `energy`, `year`, `rating`, `file_path`, `track_id`
- `mood_vector` format: `"rock:0.82,pop:0.45,indie rock:0.31"` (genre:confidence pairs)
- `other_features` format: `"danceable,happy"` (threshold-filtered labels)
- Energy raw range: 0.01–0.15 (normalized to 0–1 for AI tools)

**Multi-provider tables:**
- `track`: Canonical track identity with `file_path_hash` (SHA-256) for cross-provider deduplication
- `provider_track`: Links provider-specific `item_id` to canonical `track_id`
- `provider`: JSONB config registry (type, credentials, path prefix, priority)

## Commands

### Running the application (Docker)
```bash
docker compose -f deployment/docker-compose-unified.yaml up -d
```

### Running tests
```bash
# All tests
pytest tests/

# Single test file
pytest tests/unit/test_mcp_server.py

# Single test function
pytest tests/unit/test_mcp_server.py::test_function_name

# With markers
pytest tests/ -m "not slow"
pytest tests/ -m "unit"
```

Tests use `importlib` bypass loading in `tests/conftest.py` to avoid the `tasks/__init__.py` → pydub → audioop import chain. Session-scoped fixtures provide pre-loaded modules (`mcp_server_mod`, `ai_mcp_client_mod`, `localfiles_mod`). An autouse `config_restore` fixture saves/restores mutated config attributes.

### Building Docker images
```bash
# CPU build
docker build -t audiomuse-ai .

# GPU build (NVIDIA)
docker build --build-arg BASE_IMAGE=nvidia/cuda:12.8.1-cudnn-runtime-ubuntu24.04 -t audiomuse-ai-gpu .
```

### Package management
Uses `uv` (not pip) in Docker builds. Requirements split into `requirements/common.txt`, `requirements/cpu.txt`, `requirements/gpu.txt`.

## Key Conventions

- **Blueprint pattern**: Each feature is a Flask blueprint in `app_<feature>.py` with template in `templates/<feature>.html`. Register in `app.py`.
- **Media server providers**: Must implement the standard function interface (`get_all_songs`, `create_playlist`, `download_track`, etc.) and be registered in `tasks/mediaserver.py` dispatcher.
- **Config variables**: All from environment via `os.environ.get()` in `config.py`. No hardcoded values.
- **ID resolution**: `before_request` middleware in `app.py` resolves provider-specific `item_id` or `id` params to canonical `track_id` via `resolve_track_id()` (checks `provider_track` table). All APIs accept either format.
- **Genre regex matching**: Use `(^|,)\s*rock:` pattern to prevent substring false matches (e.g., "rock" vs "indie rock").
- **Energy normalization**: AI sees 0–1 range, raw values are 0.01–0.15 (`config.ENERGY_MIN/MAX`). Conversion happens in `execute_mcp_tool`.
- **ai_brainstorm matching**: Strict 2-stage (exact then normalized fuzzy) on BOTH title AND artist.
- **Gemini tool calling**: Uses `genai.types.Tool(function_declarations=...)` with ANY mode.
- **Ollama**: Prompt-based JSON output (no native tool calling).

## Pending Feature Migrations (from experimental repo)

These features exist in `AudioMuse-AI-experimental` (v0.7.12-beta) and are planned for migration:

### Playlist Builder (Phase 2)
Interactive playlist builder with weighted centroid calculation, smart filters, and include/exclude workflow.
- Source: `app_extend_playlist.py`, `templates/extend_playlist.html`

### Plex Integration (Phase 3)
Full Plex media server support with library browsing, track downloading, and playlist management.
- Source: `tasks/mediaserver_plex.py`
65 changes: 58 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,20 @@ For the architecture design of AudioMuse-AI, take a look to the [ARCHITECTURE](d
EMBY_TOKEN=your-api-token
```

**For Local Files (No Media Server):**
```env
MEDIASERVER_TYPE=localfiles
LOCALFILES_MUSIC_DIRECTORY=/path/to/your/music
LOCALFILES_PLAYLIST_DIR=/path/to/your/music/playlists
```

3. **Start the services:**
```bash
docker compose -f deployment/docker-compose.yaml up -d
docker compose -f deployment/docker-compose-unified.yaml up -d
```
> Remember to get the correct version for your Music Server.

> docker-compose.yaml is for Jellyfin.
> You also have docker-compose-navidrome.yaml, docker-compose-lyrion.yaml, dokcer-compose-emby.yaml
> For NVIDIA GPU acceleration, use `docker-compose-unified-nvidia.yaml` instead.
> The unified compose file supports all provider types (Jellyfin, Navidrome, Lyrion, Emby, LocalFiles).

> Other example are for advanced deployment.
4. **Access the application:**
Open your browser at `http://localhost:8000`

Expand All @@ -132,9 +136,56 @@ For the architecture design of AudioMuse-AI, take a look to the [ARCHITECTURE](d

**Stopping the services:**
```bash
docker compose -f deployment/docker-compose.yaml down
docker compose -f deployment/docker-compose-unified.yaml down
```

## Multi-Provider Support

AudioMuse-AI supports connecting to multiple media servers simultaneously, allowing you to:
- Share analysis data across providers (analyze once, use everywhere)
- Create playlists on multiple servers at once
- Use a GUI Setup Wizard for easy configuration

### GUI Setup Wizard

Access the Setup Wizard at `http://localhost:8000/setup` to:
1. Add and configure multiple providers
2. Test connections before saving
3. Auto-detect music path prefixes for cross-provider matching
4. Set a primary provider for playlist creation

### Local Files Provider

The Local Files provider scans your music directory directly without requiring a media server:
- Supports MP3, FLAC, OGG, M4A, WAV, WMA, AAC, and OPUS formats
- Extracts metadata from embedded tags (ID3, Vorbis comments, etc.)
- Creates M3U playlists in a configurable directory
- Extracts ratings from POPM, TXXX:RATING, and Vorbis RATING tags

**Configuration:**
```env
MEDIASERVER_TYPE=localfiles
LOCALFILES_MUSIC_DIRECTORY=/music # Path to your music library
LOCALFILES_PLAYLIST_DIR=/music/playlists # Where to save generated playlists
LOCALFILES_FORMATS=.mp3,.flac,.ogg,.m4a,.wav # Supported audio formats
LOCALFILES_SCAN_SUBDIRS=true # Scan subdirectories
```

### Cross-Provider Track Matching

When using multiple providers, tracks are matched across servers using normalized file paths. This allows:
- Analysis data to be reused across providers
- Playlists to be created on any provider using tracks from another
- Automatic ID remapping when creating cross-provider playlists

### Extended Metadata Fields

AudioMuse-AI now stores additional metadata for each track:
- **album_artist**: The album artist (useful for compilations)
- **year**: Release year extracted from various tag formats
- **rating**: User rating on 0-5 scale (from tags or media server)
- **file_path**: Normalized file path for cross-provider linking

> NOTE: by default AudioMuse-AI is deployed WITHOUT authentication layer and its suited only for LOCAL deployment. If you want to configure it have a look to the [AUTHENTICATION](docs/AUTH.md) docs. If you enable the Authentication Layer, you need to be sure that any plugin used support and use the AudioMuse-AI API TOKEN

## **Hardware Requirements**
Expand Down
2 changes: 2 additions & 0 deletions ai_mcp_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ def _call_ollama_with_tools(user_message: str, tools: List[Dict], ai_config: Dic
examples.append('"songs in minor key"\n{{"tool_calls": [{{"name": "search_database", "arguments": {{"scale": "minor", "get_songs": 200}}}}]}}')
examples.append('"sounds like Iron Maiden and Metallica combined"\n{{"tool_calls": [{{"name": "song_alchemy", "arguments": {{"add_items": [{{"type": "artist", "id": "Iron Maiden"}}, {{"type": "artist", "id": "Metallica"}}], "get_songs": 200}}}}]}}')
examples.append('"mix of Daft Punk and Gorillaz"\n{{"tool_calls": [{{"name": "song_alchemy", "arguments": {{"add_items": [{{"type": "artist", "id": "Daft Punk"}}, {{"type": "artist", "id": "Gorillaz"}}], "get_songs": 200}}}}]}}')

examples_text = "\n\n".join(examples)

prompt = f"""{system_prompt}
Expand Down Expand Up @@ -537,6 +538,7 @@ def _call_ollama_with_tools(user_message: str, tools: List[Dict], ai_config: Dic
IMPORTANT: ONLY include parameters the user explicitly asked for. Do NOT invent extra filters (genres, ratings, moods, energy) the user never mentioned.
For a specific year like "2026 songs", set BOTH year_min and year_max to 2026 (NOT year_min=1).


Now analyze this request and return ONLY the JSON:
Request: "{user_message}"
"""
Expand Down
Loading