plexmix 0.2.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. plexmix-0.2.7/PKG-INFO +708 -0
  2. plexmix-0.2.7/README.md +674 -0
  3. plexmix-0.2.7/pyproject.toml +65 -0
  4. plexmix-0.2.7/src/plexmix/__init__.py +22 -0
  5. plexmix-0.2.7/src/plexmix/ai/__init__.py +58 -0
  6. plexmix-0.2.7/src/plexmix/ai/base.py +115 -0
  7. plexmix-0.2.7/src/plexmix/ai/claude_provider.py +50 -0
  8. plexmix-0.2.7/src/plexmix/ai/cohere_provider.py +50 -0
  9. plexmix-0.2.7/src/plexmix/ai/gemini_provider.py +120 -0
  10. plexmix-0.2.7/src/plexmix/ai/openai_provider.py +50 -0
  11. plexmix-0.2.7/src/plexmix/ai/tag_generator.py +305 -0
  12. plexmix-0.2.7/src/plexmix/cli/__init__.py +0 -0
  13. plexmix-0.2.7/src/plexmix/cli/main.py +1282 -0
  14. plexmix-0.2.7/src/plexmix/config/__init__.py +0 -0
  15. plexmix-0.2.7/src/plexmix/config/credentials.py +81 -0
  16. plexmix-0.2.7/src/plexmix/config/settings.py +134 -0
  17. plexmix-0.2.7/src/plexmix/database/__init__.py +0 -0
  18. plexmix-0.2.7/src/plexmix/database/models.py +167 -0
  19. plexmix-0.2.7/src/plexmix/database/recovery.py +145 -0
  20. plexmix-0.2.7/src/plexmix/database/sqlite_manager.py +762 -0
  21. plexmix-0.2.7/src/plexmix/database/vector_index.py +169 -0
  22. plexmix-0.2.7/src/plexmix/playlist/__init__.py +0 -0
  23. plexmix-0.2.7/src/plexmix/playlist/generator.py +250 -0
  24. plexmix-0.2.7/src/plexmix/plex/__init__.py +0 -0
  25. plexmix-0.2.7/src/plexmix/plex/client.py +290 -0
  26. plexmix-0.2.7/src/plexmix/plex/sync.py +631 -0
  27. plexmix-0.2.7/src/plexmix/ui/__init__.py +0 -0
  28. plexmix-0.2.7/src/plexmix/ui/app.py +33 -0
  29. plexmix-0.2.7/src/plexmix/ui/components/__init__.py +0 -0
  30. plexmix-0.2.7/src/plexmix/ui/components/error.py +145 -0
  31. plexmix-0.2.7/src/plexmix/ui/components/loading.py +127 -0
  32. plexmix-0.2.7/src/plexmix/ui/components/navbar.py +77 -0
  33. plexmix-0.2.7/src/plexmix/ui/components/progress_modal.py +31 -0
  34. plexmix-0.2.7/src/plexmix/ui/components/toast.py +35 -0
  35. plexmix-0.2.7/src/plexmix/ui/components/track_table.py +60 -0
  36. plexmix-0.2.7/src/plexmix/ui/pages/__init__.py +0 -0
  37. plexmix-0.2.7/src/plexmix/ui/pages/dashboard.py +114 -0
  38. plexmix-0.2.7/src/plexmix/ui/pages/generator.py +317 -0
  39. plexmix-0.2.7/src/plexmix/ui/pages/history.py +426 -0
  40. plexmix-0.2.7/src/plexmix/ui/pages/index.py +19 -0
  41. plexmix-0.2.7/src/plexmix/ui/pages/library.py +237 -0
  42. plexmix-0.2.7/src/plexmix/ui/pages/settings.py +256 -0
  43. plexmix-0.2.7/src/plexmix/ui/pages/tagging.py +324 -0
  44. plexmix-0.2.7/src/plexmix/ui/states/__init__.py +0 -0
  45. plexmix-0.2.7/src/plexmix/ui/states/app_state.py +123 -0
  46. plexmix-0.2.7/src/plexmix/ui/states/dashboard_state.py +59 -0
  47. plexmix-0.2.7/src/plexmix/ui/states/generator_state.py +316 -0
  48. plexmix-0.2.7/src/plexmix/ui/states/history_state.py +356 -0
  49. plexmix-0.2.7/src/plexmix/ui/states/library_state.py +367 -0
  50. plexmix-0.2.7/src/plexmix/ui/states/settings_state.py +333 -0
  51. plexmix-0.2.7/src/plexmix/ui/states/tagging_state.py +322 -0
  52. plexmix-0.2.7/src/plexmix/ui/utils/__init__.py +0 -0
  53. plexmix-0.2.7/src/plexmix/ui/utils/validation.py +186 -0
  54. plexmix-0.2.7/src/plexmix/utils/__init__.py +0 -0
  55. plexmix-0.2.7/src/plexmix/utils/embeddings.py +345 -0
  56. plexmix-0.2.7/src/plexmix/utils/logging.py +64 -0
plexmix-0.2.7/PKG-INFO ADDED
@@ -0,0 +1,708 @@
1
+ Metadata-Version: 2.4
2
+ Name: plexmix
3
+ Version: 0.2.7
4
+ Summary: AI-powered Plex playlist generator using mood-based queries
5
+ License: MIT
6
+ Author: Anthony Izzo
7
+ Requires-Python: >=3.10,<4.0
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Provides-Extra: ui
16
+ Requires-Dist: anthropic (>=0.8.0,<0.9.0)
17
+ Requires-Dist: click (==8.1.7)
18
+ Requires-Dist: faiss-cpu (>=1.7.4,<2.0.0)
19
+ Requires-Dist: google-generativeai (>=0.3.0,<0.4.0)
20
+ Requires-Dist: keyring (>=24.3.0,<25.0.0)
21
+ Requires-Dist: numpy (>=1.26.0,<2.0.0)
22
+ Requires-Dist: openai (>=1.6.0,<2.0.0)
23
+ Requires-Dist: plexapi (>=4.15.0,<5.0.0)
24
+ Requires-Dist: pydantic (>=2.5.0,<3.0.0)
25
+ Requires-Dist: pydantic-settings (>=2.1.0,<3.0.0)
26
+ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
27
+ Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
28
+ Requires-Dist: reflex (>=0.6.0,<0.7.0) ; extra == "ui"
29
+ Requires-Dist: rich (>=13.7.0,<14.0.0)
30
+ Requires-Dist: sentence-transformers (>=2.2.0,<3.0.0)
31
+ Requires-Dist: typer (>=0.12.0,<0.13.0)
32
+ Description-Content-Type: text/markdown
33
+
34
+ <div align="center">
35
+ <img src="logo.png" alt="PlexMix Logo" width="300"/>
36
+
37
+ # PlexMix
38
+
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
40
+ [![PyPI version](https://badge.fury.io/py/plexmix.svg)](https://badge.fury.io/py/plexmix)
41
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
42
+
43
+ **AI-powered Plex playlist generator using mood-based queries**
44
+ </div>
45
+
46
+ PlexMix syncs your Plex music library to a local SQLite database, generates semantic embeddings for tracks, and uses AI to create personalized playlists based on mood descriptions.
47
+
48
+ ## Features
49
+
50
+ - ✨ **Simple Setup** - Only requires a Google API key to get started
51
+ - 🎵 **Smart Sync** - Syncs Plex music library with incremental updates
52
+ - 🤖 **AI-Powered** - Uses Google Gemini, OpenAI GPT, or Anthropic Claude
53
+ - 🏷️ **AI Tagging** - Automatically generates tags, environments, and instruments for tracks
54
+ - 🔍 **Semantic Search** - FAISS vector similarity search for intelligent track matching
55
+ - 🎨 **Mood-Based** - Generate playlists from natural language descriptions
56
+ - ⚡ **Fast** - Local database with optimized indexes and full-text search
57
+ - 🎯 **Flexible** - Filter by genre, year, rating, artist, environment, and instrument
58
+ - 🛡️ **Resilient** - Automatic database recovery if deleted or corrupted
59
+
60
+ ## Quick Start
61
+
62
+ ### Option 1: Command Line Interface (Recommended)
63
+
64
+ ```bash
65
+ # Install from PyPI
66
+ pip install plexmix
67
+
68
+ # Run setup wizard
69
+ plexmix config init
70
+
71
+ # Sync your Plex library (incremental, generates embeddings automatically)
72
+ plexmix sync
73
+
74
+ # Generate AI tags for tracks (enhances search quality)
75
+ plexmix tags generate
76
+
77
+ # Create a playlist
78
+ plexmix create "upbeat morning energy"
79
+
80
+ # With filters
81
+ plexmix create "chill evening vibes" --genre jazz --year-min 2010 --limit 30
82
+
83
+ # Filter by environment and instrument
84
+ plexmix create "focus music" --environment study --instrument piano
85
+
86
+ # Use alternative AI provider
87
+ plexmix create "workout motivation" --provider openai
88
+
89
+ # If you encounter issues (e.g., "0 candidate tracks")
90
+ plexmix doctor
91
+
92
+ # Regenerate all tags and embeddings from scratch (WARNING: destructive)
93
+ plexmix sync regenerate
94
+ ```
95
+
96
+ ### Option 2: Web User Interface (Alpha)
97
+
98
+ > **Note:** The Web UI is currently in Alpha status. The CLI is the recommended way to interact with PlexMix for production use.
99
+
100
+ ```bash
101
+ # Install with UI extras
102
+ pip install "plexmix[ui]"
103
+
104
+ # Or if using poetry
105
+ poetry install -E ui
106
+
107
+ # Launch the web UI
108
+ plexmix ui
109
+
110
+ # Optional: Specify host and port
111
+ plexmix ui --host 0.0.0.0 --port 8000
112
+ ```
113
+
114
+ Then open your browser to `http://localhost:3000`
115
+
116
+ #### Screenshots
117
+
118
+ <div align="center">
119
+ <img src="docs/screenshots/dashboard-light.png" alt="Dashboard - Light Mode" width="45%"/>
120
+ <img src="docs/screenshots/dashboard-dark.png" alt="Dashboard - Dark Mode" width="45%"/>
121
+ <p><em>Dashboard with configuration status and library statistics</em></p>
122
+ </div>
123
+
124
+ <div align="center">
125
+ <img src="docs/screenshots/generator.png" alt="Playlist Generator" width="90%"/>
126
+ <p><em>AI-powered playlist generator with mood-based queries</em></p>
127
+ </div>
128
+
129
+ <div align="center">
130
+ <img src="docs/screenshots/library.png" alt="Library Manager" width="90%"/>
131
+ <p><em>Browse and manage your music library with advanced filtering</em></p>
132
+ </div>
133
+
134
+ <div align="center">
135
+ <img src="docs/screenshots/settings.png" alt="Settings" width="90%"/>
136
+ <p><em>Configure Plex, AI providers, and embeddings</em></p>
137
+ </div>
138
+
139
+ #### Web UI Features
140
+
141
+ The web interface provides a modern, intuitive way to interact with PlexMix:
142
+
143
+ - **📊 Dashboard** - Overview of library stats, configuration status, and quick actions
144
+ - **⚙️ Settings** - Configure Plex, AI providers, and embeddings with real-time validation
145
+ - **📚 Library Manager** - Browse, search, and sync your music library with live progress tracking
146
+ - **🎵 Playlist Generator** - Create mood-based playlists with advanced filters and instant preview
147
+ - **🏷️ AI Tagging** - Batch generate tags for tracks with progress monitoring
148
+ - **📜 Playlist History** - View, export, and manage all generated playlists
149
+
150
+ #### Key UI Features
151
+
152
+ - **🌓 Dark/Light Mode** - Toggle between themes with automatic logo switching
153
+ - **Real-time Progress** - Live updates for sync, tagging, and generation operations
154
+ - **Form Validation** - Instant feedback on configuration settings
155
+ - **Loading States** - Skeleton screens and spinners for smooth UX
156
+ - **Error Handling** - User-friendly error messages with recovery options
157
+ - **Responsive Design** - Works on desktop and tablet devices
158
+
159
+ ## Installation
160
+
161
+ ### From PyPI (Recommended)
162
+
163
+ ```bash
164
+ pip install plexmix
165
+ ```
166
+
167
+ ### From Source
168
+
169
+ ```bash
170
+ git clone https://github.com/izzoa/plexmix.git
171
+ cd plexmix
172
+ poetry install
173
+ ```
174
+
175
+ ## Configuration
176
+
177
+ PlexMix uses **Google Gemini by default** for both AI playlist generation and embeddings, requiring only a **single API key**!
178
+
179
+ ### Required
180
+
181
+ - **Plex Server**: URL and authentication token
182
+ - **Google API Key**: For Gemini AI and embeddings ([Get one here](https://makersuite.google.com/app/apikey))
183
+
184
+ ### Optional Alternative Providers
185
+
186
+ - **OpenAI API Key**: For GPT models and text-embedding-3-small
187
+ - **Anthropic API Key**: For Claude models (AI only, no embeddings)
188
+ - **Cohere API Key**: For Command R7B and Embed v4 models
189
+ - **Local Embeddings**: sentence-transformers (free, offline, no API key needed)
190
+
191
+ ### Getting a Plex Token
192
+
193
+ 1. Open Plex Web App
194
+ 2. Play any media item
195
+ 3. Click the three dots (...) → Get Info
196
+ 4. View XML
197
+ 5. Copy the `X-Plex-Token` from the URL
198
+
199
+ ## Usage
200
+
201
+ ### Configuration Commands
202
+
203
+ ```bash
204
+ # Interactive setup wizard
205
+ plexmix config init
206
+
207
+ # Test Plex server connection
208
+ plexmix config test
209
+
210
+ # Show current configuration
211
+ plexmix config show
212
+ ```
213
+
214
+ **Troubleshooting Connection Issues:**
215
+
216
+ If you get a "400 Bad Request" error when connecting to Plex:
217
+
218
+ 1. **Check your Plex token** - Make sure there are no extra spaces when copying
219
+ 2. **Try HTTPS** - Use `https://` instead of `http://` if your server requires secure connections
220
+ 3. **Verify the URL** - Ensure the server address and port (default: 32400) are correct
221
+ 4. **Check server settings** - In Plex Server settings, look for network/authentication requirements
222
+ 5. **Test the connection** - Run `plexmix config test` to diagnose the issue
223
+
224
+ **Common Plex Server URLs:**
225
+ - Local: `http://localhost:32400`
226
+ - Remote: `http://192.168.1.X:32400` (replace X with your server's IP)
227
+ - Secure: `https://your-server:32400`
228
+
229
+ ### Sync Commands
230
+
231
+ PlexMix offers three sync modes:
232
+
233
+ ```bash
234
+ # Incremental sync (default) - Only syncs new/changed/deleted tracks
235
+ plexmix sync
236
+
237
+ # Same as above, but explicit
238
+ plexmix sync incremental
239
+
240
+ # Regenerate everything from scratch (WARNING: Deletes ALL tags and embeddings)
241
+ plexmix sync regenerate
242
+
243
+ # Legacy alias for incremental sync
244
+ plexmix sync full
245
+
246
+ # Sync without embeddings (faster, but you'll need to generate them later)
247
+ plexmix sync --no-embeddings
248
+ ```
249
+
250
+ **Sync Mode Comparison:**
251
+
252
+ | Mode | Tracks | Tags | Embeddings | Use Case |
253
+ |------|--------|------|------------|----------|
254
+ | `incremental` (default) | ✅ Syncs changes only | ✅ Preserves existing | ✅ Preserves existing | Regular updates, new tracks added |
255
+ | `full` (alias) | ✅ Syncs changes only | ✅ Preserves existing | ✅ Preserves existing | Same as incremental (kept for compatibility) |
256
+ | `regenerate` | ✅ Syncs everything | ⚠️ **DELETES ALL** | ⚠️ **DELETES ALL** | Starting fresh, fixing corrupt data |
257
+
258
+ **When to use each:**
259
+ - **`plexmix sync`** → Default for daily use, adding new music
260
+ - **`plexmix sync regenerate`** → When you want to completely regenerate all AI data (tags, embeddings)
261
+
262
+ ### Database Health Check
263
+
264
+ ```bash
265
+ # Diagnose and fix database issues
266
+ plexmix doctor
267
+
268
+ # Force regenerate all tags and embeddings (DEPRECATED: use 'plexmix sync regenerate' instead)
269
+ plexmix doctor --force
270
+ ```
271
+
272
+ **What does `plexmix doctor` do?**
273
+ - Detects orphaned embeddings (embeddings that reference deleted tracks)
274
+ - Shows database health status (track count, embeddings, orphans)
275
+ - Interactively removes orphaned data
276
+ - Regenerates missing embeddings
277
+ - Rebuilds vector index
278
+
279
+ **When to use:**
280
+ - After "No tracks found matching criteria" errors
281
+ - When playlist generation finds 0 candidates
282
+ - After database corruption or manual track deletion
283
+ - Periodic maintenance to keep database healthy
284
+
285
+ **Note:** For complete regeneration of all tags and embeddings, use `plexmix sync regenerate` instead of `doctor --force`
286
+
287
+ ### Database Management
288
+
289
+ ```bash
290
+ # Show database information and statistics
291
+ plexmix db info
292
+
293
+ # Reset database and embeddings (with automatic backup)
294
+ plexmix db reset
295
+
296
+ # Reset without backup (not recommended)
297
+ plexmix db reset --no-backup
298
+
299
+ # Skip confirmation prompt
300
+ plexmix db reset --force
301
+ ```
302
+
303
+ **What gets deleted:**
304
+ - SQLite database (`~/.plexmix/plexmix.db`)
305
+ - FAISS embeddings index (`~/.plexmix/embeddings.index`)
306
+ - All synced music metadata
307
+ - User-applied tags (moods, environments, instruments)
308
+ - Playlist history
309
+ - AI-generated embeddings
310
+
311
+ **What gets preserved:**
312
+ - Your music files on Plex server (unchanged)
313
+ - Plex server metadata (unchanged)
314
+ - PlexMix configuration (`.env`, `config.yaml`)
315
+ - API keys
316
+
317
+ **When to use:**
318
+ - Complete fresh start
319
+ - Switching embedding providers
320
+ - Database corruption that `doctor` can't fix
321
+ - Testing or development
322
+
323
+ **After reset:**
324
+ 1. Run `plexmix sync` to re-sync your library
325
+ 2. (Optional) Run `plexmix tags generate` to re-tag tracks
326
+
327
+ By default, a timestamped backup is created in `~/.plexmix/backups/` before deletion.
328
+
329
+ **Database Command Reference:**
330
+
331
+ | Command | Purpose | When to Use |
332
+ |---------|---------|-------------|
333
+ | `plexmix db info` | Show database stats | Check database health, view track/embedding counts |
334
+ | `plexmix db reset` | Delete and reset database | Fresh start, switching providers, unfixable corruption |
335
+ | `plexmix sync` | Incremental sync | Regular updates, new tracks |
336
+ | `plexmix sync regenerate` | Regenerate all data | Regenerate tags/embeddings, fix data quality |
337
+ | `plexmix doctor` | Fix orphaned data | After errors, periodic maintenance |
338
+
339
+ ### Tag Generation
340
+
341
+ ```bash
342
+ # Generate AI tags for all untagged tracks
343
+ plexmix tags generate
344
+
345
+ # Use alternative AI provider
346
+ plexmix tags generate --provider openai
347
+
348
+ # Skip embedding regeneration (faster, but tags won't be in search)
349
+ plexmix tags generate --no-regenerate-embeddings
350
+ ```
351
+
352
+ ### Embedding Generation
353
+
354
+ ```bash
355
+ # Generate embeddings for tracks without them
356
+ plexmix embeddings generate
357
+
358
+ # Regenerate all embeddings from scratch
359
+ plexmix embeddings generate --regenerate
360
+ ```
361
+
362
+ **What are tags?**
363
+ AI-generated metadata (per track) that enhances semantic search:
364
+ - **Tags** (3-5): Mood descriptors like energetic, melancholic, upbeat, chill, intense
365
+ - **Environments** (1-3): Best-fit contexts like work, study, focus, relax, party, workout, sleep, driving, social
366
+ - **Instruments** (1-3): Most prominent instruments like piano, guitar, saxophone, drums, bass, synth, vocals, strings
367
+
368
+ All metadata is automatically included in embeddings for more accurate mood-based playlist generation.
369
+
370
+ ### Playlist Generation
371
+
372
+ ```bash
373
+ # Basic playlist (prompts for track count)
374
+ plexmix create "happy upbeat summer vibes"
375
+
376
+ # Specify track count
377
+ plexmix create "rainy day melancholy" --limit 25
378
+
379
+ # Filter by genre
380
+ plexmix create "energetic workout" --genre rock --limit 40
381
+
382
+ # Filter by year range
383
+ plexmix create "90s nostalgia" --year-min 1990 --year-max 1999
384
+
385
+ # Filter by environment (work, study, focus, relax, party, workout, sleep, driving, social)
386
+ plexmix create "workout energy" --environment workout
387
+
388
+ # Filter by instrument (piano, guitar, saxophone, drums, etc.)
389
+ plexmix create "piano jazz" --instrument piano
390
+
391
+ # Use specific AI provider
392
+ plexmix create "chill study session" --provider claude
393
+
394
+ # Custom playlist name
395
+ plexmix create "morning coffee" --name "Perfect Morning Mix"
396
+
397
+ # Adjust candidate pool multiplier (default: 25x playlist length)
398
+ plexmix create "diverse mix" --limit 20 --pool-multiplier 50
399
+
400
+ # Don't create in Plex (save locally only)
401
+ plexmix create "test playlist" --no-create-in-plex
402
+ ```
403
+
404
+ ## Architecture
405
+
406
+ PlexMix uses a multi-stage pipeline for intelligent playlist generation:
407
+
408
+ 1. **AI Tagging** (One-time setup) → Tracks receive:
409
+ - 3-5 descriptive tags (mood, energy, tempo, emotion)
410
+ - 1-3 environments (work, study, focus, relax, party, workout, sleep, driving, social)
411
+ - 1-3 instruments (piano, guitar, saxophone, drums, bass, synth, vocals, strings, etc.)
412
+
413
+ 2. **Playlist Generation Pipeline**:
414
+ - **SQL Filters** → Apply optional filters (genre, year, rating, artist, environment, instrument)
415
+ - **Candidate Pool** → Search using FAISS vector similarity (default: 25x playlist length)
416
+ - **Diversity Selection** → Apply algorithmic diversity rules:
417
+ - Max 3 tracks per artist
418
+ - Max 2 tracks per album
419
+ - No duplicate track/artist combinations
420
+ - **Final Playlist** → Return curated, diverse track list
421
+
422
+ ### Technology Stack
423
+
424
+ - **Language**: Python 3.10+
425
+ - **CLI**: Typer with Rich console output
426
+ - **Database**: SQLite with FTS5 full-text search
427
+ - **Vector Search**: FAISS (CPU) with cosine similarity
428
+ - **AI Providers**: Google Gemini (default), OpenAI GPT, Anthropic Claude, Cohere
429
+ - **Embeddings**: Google Gemini (3072d), OpenAI (1536d), Local (384-768d)
430
+ - **Plex Integration**: PlexAPI
431
+
432
+ ### Project Structure
433
+
434
+ ```
435
+ plexmix/
436
+ ├── src/plexmix/
437
+ │ ├── ai/ # AI provider implementations
438
+ │ │ ├── base.py # Abstract base class
439
+ │ │ ├── gemini_provider.py
440
+ │ │ ├── openai_provider.py
441
+ │ │ ├── claude_provider.py
442
+ │ │ └── tag_generator.py # AI-based tag generation
443
+ │ ├── cli/ # Command-line interface
444
+ │ │ └── main.py # Typer CLI app
445
+ │ ├── config/ # Configuration management
446
+ │ │ ├── settings.py # Pydantic settings
447
+ │ │ └── credentials.py # Keyring integration
448
+ │ ├── database/ # Database layer
449
+ │ │ ├── models.py # Pydantic models
450
+ │ │ ├── sqlite_manager.py # SQLite CRUD
451
+ │ │ └── vector_index.py # FAISS index
452
+ │ ├── plex/ # Plex integration
453
+ │ │ ├── client.py # PlexAPI wrapper
454
+ │ │ └── sync.py # Sync engine
455
+ │ ├── playlist/ # Playlist generation
456
+ │ │ └── generator.py # Core generation logic
457
+ │ ├── ui/ # Web UI (Reflex)
458
+ │ │ ├── app.py # Main Reflex app
459
+ │ │ ├── pages/ # UI pages
460
+ │ │ ├── states/ # State management
461
+ │ │ ├── components/ # Reusable components
462
+ │ │ └── utils/ # UI utilities
463
+ │ └── utils/ # Utilities
464
+ │ ├── embeddings.py # Embedding providers
465
+ │ └── logging.py # Logging setup
466
+ └── tests/ # Test suite
467
+ └── ui/ # UI tests
468
+ ```
469
+
470
+ ## Database Schema
471
+
472
+ PlexMix stores all music metadata locally:
473
+
474
+ - **artists**: Artist information
475
+ - **albums**: Album details with artist relationships
476
+ - **tracks**: Track metadata with full-text search, AI-generated tags (3-5), environments (1-3), and instruments (1-3)
477
+ - **embeddings**: Vector embeddings for semantic search (includes all AI-generated metadata)
478
+ - **playlists**: Generated playlist metadata
479
+ - **sync_history**: Synchronization audit log
480
+
481
+ ## AI Provider Comparison
482
+
483
+ | Provider | Model | Context Window | Default Temp | Speed | Quality | Cost | Best For |
484
+ |----------|-------|----------------|--------------|-------|---------|------|----------|
485
+ | **Google Gemini** ⭐ | gemini-2.5-flash | 1M tokens | 0.7 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | General use, RAG, large contexts |
486
+ | OpenAI | gpt-5-mini | 400K tokens | 0.7 | ⚡⚡ Moderate | ⭐⭐⭐⭐⭐ Outstanding | 💰💰 Medium | High-quality responses, reasoning |
487
+ | OpenAI | gpt-5-nano | 400K tokens | 0.7 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | Speed-optimized, efficient |
488
+ | Cohere | command-r7b-12-2024 | 128K tokens | 0.3 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | RAG, tool use, agents |
489
+ | Cohere | command-r-plus-08-2024 | 128K tokens | 0.3 | ⚡⚡ Moderate | ⭐⭐⭐⭐⭐ Outstanding | 💰💰 Medium | Multilingual, complex tasks |
490
+ | Cohere | command-r-08-2024 | 128K tokens | 0.3 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | Balanced performance |
491
+ | Anthropic | claude-sonnet-4-5 | 200K tokens | 0.7 | ⚡⚡ Moderate | ⭐⭐⭐⭐⭐ Outstanding | 💰💰💰 High | Advanced reasoning, analysis |
492
+ | Anthropic | claude-3-5-haiku-20241022 | 200K tokens | 0.7 | ⚡⚡⚡ Fast | ⭐⭐⭐⭐ Excellent | 💰 Low | Fast responses, efficiency |
493
+
494
+ **Legend:**
495
+ - ⭐ Default/recommended option
496
+ - Speed: ⚡ Slow, ⚡⚡ Moderate, ⚡⚡⚡ Fast
497
+ - Quality: ⭐ Basic → ⭐⭐⭐⭐⭐ Outstanding
498
+ - Cost: 💰 Low, 💰💰 Medium, 💰💰💰 High
499
+
500
+ ## Embedding Provider Comparison
501
+
502
+ | Provider | Model | Dimensions | Quality | Speed | Cost | API Key | Best For |
503
+ |----------|-------|------------|---------|-------|------|---------|----------|
504
+ | **Google Gemini** ⭐ | gemini-embedding-001 | 3072 | ⭐⭐⭐⭐⭐ Outstanding | ⚡⚡ Moderate | 💰 Low | Required | High-dimensional, accurate semantic search |
505
+ | OpenAI | text-embedding-3-small | 1536 | ⭐⭐⭐⭐ Excellent | ⚡⚡⚡ Fast | 💰💰 Medium | Required | Balanced performance, OpenAI ecosystem |
506
+ | Cohere | embed-v4 | 256/512/1024/1536 | ⭐⭐⭐⭐ Excellent | ⚡⚡⚡ Fast | 💰 Low | Required | Flexible dimensions (Matryoshka), multimodal |
507
+ | Local | all-MiniLM-L6-v2 | 384 | ⭐⭐⭐ Good | ⚡⚡⚡ Fast | 💰 Free | None | Offline use, privacy, no API costs |
508
+
509
+ **Key Features:**
510
+ - **Gemini**: Highest dimensions (3072d) for maximum semantic precision
511
+ - **OpenAI**: Industry standard, excellent ecosystem integration
512
+ - **Cohere**: Configurable dimensions (256/512/1024/1536), supports images with v4
513
+ - **Local**: Completely free, offline, private, no internet required
514
+
515
+ **Dimension Trade-offs:**
516
+ - Higher dimensions = Better semantic understanding but larger storage
517
+ - Lower dimensions = Faster search but slightly less accurate
518
+ - Cohere's Matryoshka embeddings allow dynamic dimension selection
519
+
520
+ ## Development
521
+
522
+ ### Setup Development Environment
523
+
524
+ ```bash
525
+ # Clone repository
526
+ git clone https://github.com/izzoa/plexmix.git
527
+ cd plexmix
528
+
529
+ # Install with development dependencies
530
+ poetry install
531
+
532
+ # Run tests
533
+ poetry run pytest
534
+
535
+ # Format code
536
+ poetry run black src/
537
+
538
+ # Lint
539
+ poetry run ruff src/
540
+
541
+ # Type check
542
+ poetry run mypy src/
543
+ ```
544
+
545
+ ### Running Tests
546
+
547
+ ```bash
548
+ poetry run pytest
549
+ poetry run pytest --cov=plexmix --cov-report=html
550
+ ```
551
+
552
+ ## Troubleshooting
553
+
554
+ ### "No music libraries found"
555
+ - Ensure your Plex server has a music library
556
+ - Verify your Plex token is correct
557
+ - Check server URL is accessible
558
+
559
+ ### "Failed to generate embeddings"
560
+ - Verify API keys are configured correctly
561
+ - Check internet connection
562
+ - Try local embeddings: `--embedding-provider local`
563
+
564
+ ### "No tracks found matching criteria"
565
+ - **First, try:** `plexmix doctor` to check for database issues
566
+ - Ensure library is synced: `plexmix sync`
567
+ - Check filters aren't too restrictive
568
+ - Verify embeddings were generated
569
+
570
+ ### "0 candidate tracks" or "No orphaned embeddings"
571
+ - This usually means embeddings reference old track IDs
572
+ - **Solution:** Run `plexmix doctor` to detect and fix orphaned embeddings
573
+ - The doctor will clean up orphaned data and regenerate embeddings
574
+
575
+ ### Performance Tips
576
+
577
+ - Use local embeddings for faster offline operation
578
+ - Run sync during off-peak hours for large libraries
579
+ - Adjust candidate pool multiplier based on library size (default: 25x playlist length)
580
+ - Smaller libraries: Use lower multiplier (10-15x) for faster generation
581
+ - Larger libraries: Use higher multiplier (30-50x) for better diversity
582
+ - Use filters to narrow search space
583
+
584
+ ## FAQ
585
+
586
+ ### How does PlexMix work?
587
+
588
+ PlexMix syncs your Plex music library to a local SQLite database, generates AI-powered tags (mood, instruments, environments) for each track, creates semantic embeddings, and uses vector similarity search combined with LLM intelligence to generate playlists from natural language mood descriptions.
589
+
590
+ ### Do I need an API key?
591
+
592
+ Yes, but only one! Google Gemini is the default provider for both AI and embeddings. You can get a free API key at [Google AI Studio](https://makersuite.google.com/app/apikey). Alternative providers (OpenAI, Anthropic, local embeddings) are optional.
593
+
594
+ ### How much does it cost to run?
595
+
596
+ **Google Gemini (default)**:
597
+ - Embedding generation: ~$0.10-0.30 for 10,000 tracks (one-time)
598
+ - Tag generation: ~$0.20-0.50 for 10,000 tracks (one-time)
599
+ - Playlist creation: ~$0.01 per playlist (ongoing)
600
+
601
+ **Alternatives**:
602
+ - Local embeddings are completely free (no API key needed)
603
+ - OpenAI and Anthropic have similar costs
604
+
605
+ ### How long does initial sync take?
606
+
607
+ - **Metadata sync**: 5-15 minutes for 10,000 tracks
608
+ - **Tag generation**: 30-60 minutes for 10,000 tracks
609
+ - **Embedding generation**: 15-30 minutes for 10,000 tracks
610
+
611
+ Total: ~1-2 hours for a large library. You can interrupt and resume at any time.
612
+
613
+ ### Can I use this without internet?
614
+
615
+ Partially. After initial sync and tag/embedding generation, you can:
616
+ - ✅ Browse your database offline
617
+ - ✅ Use local embeddings (no API needed)
618
+ - ❌ Generate new playlists (requires AI API)
619
+ - ❌ Generate tags for new tracks (requires AI API)
620
+
621
+ ### What's the difference between tags, environments, and instruments?
622
+
623
+ - **Tags** (3-5): Mood and vibe descriptors like "energetic", "melancholic", "upbeat", "chill"
624
+ - **Environments** (1-3): Best contexts for listening like "work", "study", "workout", "party"
625
+ - **Instruments** (1-3): Most prominent instruments like "piano", "guitar", "saxophone", "drums"
626
+
627
+ All three are automatically generated by AI and improve playlist quality.
628
+
629
+ ### Why am I getting "0 candidate tracks"?
630
+
631
+ This usually means:
632
+ 1. **No embeddings generated**: Run `plexmix embeddings generate`
633
+ 2. **Database out of sync**: Run `plexmix doctor` to fix
634
+ 3. **Filters too restrictive**: Remove some filters and try again
635
+ 4. **Empty library**: Ensure `plexmix sync` completed successfully
636
+
637
+ ### Can I use multiple Plex libraries?
638
+
639
+ Not yet. Currently PlexMix supports one music library at a time. Multi-library support is on the roadmap.
640
+
641
+ ### Does this modify my Plex server?
642
+
643
+ Only when creating playlists. PlexMix:
644
+ - ✅ Reads metadata from Plex (read-only)
645
+ - ✅ Creates playlists in Plex (if enabled with `--create-in-plex`)
646
+ - ❌ Does NOT modify tracks, albums, or artists
647
+ - ❌ Does NOT delete anything from Plex
648
+
649
+ ### What happens if I delete tracks from Plex?
650
+
651
+ Run `plexmix sync` to update your local database. The incremental sync will:
652
+ - Detect deleted tracks from Plex
653
+ - Remove them from the database
654
+ - Clean up orphaned embeddings
655
+ - Update the vector index
656
+
657
+ Or use `plexmix doctor` to clean up orphaned data.
658
+
659
+ ### Can I backup my database?
660
+
661
+ Yes! Your database is stored at `~/.plexmix/plexmix.db`. Simply copy this file and the `~/.plexmix/embeddings.index` file to backup all your data, tags, and embeddings.
662
+
663
+ ### How do I update PlexMix?
664
+
665
+ ```bash
666
+ pip install --upgrade plexmix
667
+ ```
668
+
669
+ After updating, run `plexmix sync --no-embeddings` to apply any database migrations.
670
+
671
+ ### Can I contribute?
672
+
673
+ Absolutely! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. We welcome bug reports, feature requests, and pull requests.
674
+
675
+ ## Roadmap
676
+
677
+ - [ ] Docker support
678
+ - [ ] Multi-library support
679
+ - [ ] Playlist templates
680
+ - [ ] Smart shuffle and ordering
681
+ - [ ] Export/import playlists (M3U, JSON)
682
+ - [ ] Audio feature analysis integration
683
+
684
+ ## Contributing
685
+
686
+ Contributions welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
687
+
688
+ 1. Fork the repository
689
+ 2. Create a feature branch
690
+ 3. Make your changes
691
+ 4. Add tests
692
+ 5. Submit a pull request
693
+
694
+ ## License
695
+
696
+ MIT License - see [LICENSE](LICENSE) for details
697
+
698
+ ## Acknowledgments
699
+
700
+ - Built with [Typer](https://typer.tiangolo.com/) and [Rich](https://rich.readthedocs.io/)
701
+ - Plex integration via [python-plexapi](https://github.com/pkkid/python-plexapi)
702
+ - Vector search powered by [FAISS](https://github.com/facebookresearch/faiss)
703
+ - AI providers: Google, OpenAI, Anthropic, Cohere
704
+
705
+ ---
706
+
707
+ **Made with ❤️ for music lovers**
708
+