This application is an intelligent music request system that uses the Claude API to handle specific natural language music tasks that arise out of interactions with the Sonos CLI application. The main functions of the use of an LLM in this context is to 1) understand the user's natural language request to play a certain music track and 2) to analyze the results of searching for that track to determine the track that most closely matches the user's request.
This project provides a robust, API-based interface for understanding the user's natural languame request and identifying the Sonos accessible track that best matches that request. It handles complex cases like possessive forms ("Neil Young's Harvest"), version preferences ("live version of..."), and automatically recovers from Sonos search failures by reformulating a search to use an album-based search strategy based on knowledge from its training data set.
Note: This Claude API integration replaces a previous approach that attempted to use built-in Claude Code Task function behavior that turned out to frequently employ mock functions instead of the intended general-purpose agent behavior. All legacy code from that abandoned approach has been removed, leaving only the robust, reliable API-based workflow.
- Possessive parsing: "Ani DiFranco's fixing her hair"
- Version preferences: "live version of Comfortably Numb"
- Casual requests: "some Beatles", "play Harvest by Neil Young"
- Complex grammar: Handles articles, pronouns, and natural speech patterns
- Selecting best match: Considers track title, artist, expressed preferences (i.e., live, acoustic)
- Context-aware: Prefers originals over compilations, studio over live (unless specified)
- Fuzzy matching: Should handle typos, incomplete information and still find best match
- Deal with Sonos bugs/quirks: Works around known Sonos search issues
- Dynamic album lookup: When Sonos API returns bad data, uses Claude API to identify the album
- Precision search: Searches "artist + album" to get targeted results (13 tracks vs 50 random)
- Smart fallback: Multiple search strategies with automatic progression
- No hard-coding: Scalable solution that works for any song, not just special cases
- Direct Claude API: Consistent, reliable LLM parsing and selection
- No Mock Responses: Eliminates "Task completed..." failures completely
- Environment Independent: Same behavior in CLI, headless, or subprocess environments
- Graceful Fallbacks: Automatic regex parsing when API temporarily unavailable
claude_api_client.py # Claude API client (ClaudeAPIClient class) with LLM parsing and selection methods
claude_music_interface.py # Main interface with unified MusicAgent class containing all functionality
music_parsing_prompts.py # Standardized prompts for consistent behavior
ClaudeAPIClient: Direct API client for parsing and track selectionMusicAgent: Unified intelligent agent with both API-powered and programmatic capabilities- Main function:
handle_music_request(request)- simplified, reliable entry point
Architecture: The MusicAgent class now contains all functionality in a single, cohesive unit. When an API client is available, it uses Claude API for parsing and intelligent selection. When the API client is unavailable, it gracefully falls back to programmatic methods. This unified approach eliminates unnecessary inheritance complexity while preserving all capabilities.
- *User request triggers search and best match: "[play] [song/artist]"
- Artist possessive forms: "Neil Young's Harvest", "Ani DiFranco's fixing her hair", "The Beatles' Here Comes the Sun"
- Preference requests: "live version of...", "acoustic version of...", "studio version of..."
- Casual requests: "some [artist]", "something by [artist]", "[song] by [artist]"
Claude API-Powered Agent (Optimal) with fallback to algorithmic parsing and matching if API unavailable
from claude_music_interface import handle_music_request
# OPTIMAL: Single function call with full Claude API workflow (parsing + result selection)
result = handle_music_request(user_request)The music agent requires Claude API access:
- API Key Configuration: Set
ANTHROPIC_API_KEYenvironment variable - Virtual Environment: Activate
.venvwith required dependencies - Dependencies:
anthropicandpython-dotenvpackages
Setup Instructions:
# 1. Set up environment
source .venv/bin/activate
# 2. Configure API key (choose one method):
# Method A: Environment variable
export ANTHROPIC_API_KEY=your_api_key_here
# Method B: .env file
echo "ANTHROPIC_API_KEY=your_api_key_here" > .envExamples of correct usage:
# ✅ CORRECT - Simple, reliable API approach
handle_music_request("play ani difranco's fixing her hair")
# ✅ CORRECT - With verbose output
handle_music_request("neil young's harvest", verbose=True)
# ✅ CORRECT - Complex parsing handled automatically
handle_music_request("I'd like to hear a live version of comfortably numb")- Natural Language Understanding: Perfect parsing of possessives, complex grammar, preferences
- Intelligent Result Selection: Uses music knowledge to choose optimal versions
- Reliable Processing: No mock responses or retry loops
- Music Industry Knowledge: Understands albums, collaborations, version types, authenticity
- Contextual Decision Making: Prefers originals over compilations, authentic over covers
- Smart Search Strategy: Multiple query variations with fallback strategies
- API Error Recovery: Automatically handles known Amazon Music API parsing issues
- Environment Independent: Same behavior in all execution environments
# Complex cases use Claude API intelligence:
handle_music_request("I'd like to hear a live version of Neil Young's Harvest")
# → API parses request AND chooses best live version from search results
handle_music_request("Ani DiFranco's fixing her hair")
# → Perfect possessive parsing, intelligent result selection
handle_music_request("Like a Hurricane by Neil Young")
# → API chooses original studio album over compilations/covers
# Simple cases also benefit from reliable parsing:
handle_music_request("Bohemian Rhapsody by Queen")
# → Consistent, reliable parsing every timeThe music request processing uses Claude API for consistent, reliable behavior:
from claude_music_interface import handle_music_request
# Direct API-based processing - no complex setup required
result = handle_music_request("I'd like to hear a live version of Neil Young's Harvest")
# Returns consistent, reliable results every time
print(result) # "Now playing: Harvest (Live) by Neil Young"🎯 Intelligent Result Selection Examples:
- "Like a Hurricane by Neil Young": Chooses original "American Stars 'N Bars" album over Greatest Hits compilation
- "Harvest Moon live": Finds live recordings from concert albums like "Live at Massey Hall"
- "Unplugged version of...": Understands MTV Unplugged albums are acoustic performances
- Multiple remasters: Prefers original releases over anniversary/deluxe editions when no preference specified
Error: "No API key provided"
# Fix: Set your API key
export ANTHROPIC_API_KEY=your_api_key_here
# Or add to .env file
echo "ANTHROPIC_API_KEY=your_api_key_here" > .envError: "Authentication error"
# Fix: Check your API key is valid
# Get a new key from: https://console.anthropic.com/account/keysError: "Rate limit exceeded"
- Normal behavior during high usage
- The system will automatically retry with backoff
- Requests will complete successfully after brief delay
API Temporarily Unavailable:
- System automatically falls back to regex parsing
- Basic functionality preserved during outages
- Full intelligence returns when API connection restored
Virtual Environment Not Activated:
# Fix: Activate the virtual environment
source .venv/bin/activateMissing Dependencies:
# Fix: Install required packages
pip install anthropic python-dotenvImport Errors:
# Fix: Ensure you're in the correct directory
cd /path/to/claude_music
source .venv/bin/activate
python -c "from claude_music_interface import handle_music_request; print('✅ Setup correct')"Quick Test:
source .venv/bin/activate
python -c "from claude_music_interface import handle_music_request; print(handle_music_request('ani difranco\\'s fixing her hair'))"Expected Output:
Now playing: Fixing Her Hair by Ani DiFranco
Comprehensive Test:
from claude_music_interface import handle_music_request
test_cases = [
"ani difranco's fixing her hair",
"play harvest by neil young",
"I'd like to hear a live version of comfortably numb"
]
for request in test_cases:
print(f"Request: {request}")
result = handle_music_request(request)
print(f"Result: {result}\n")This system provides 100% reliable intelligent music processing without any of the unpredictable behavior that affected the previous implementation.
Do what has been asked; nothing more, nothing less. NEVER create files unless they're absolutely necessary for achieving your goal. ALWAYS prefer editing an existing file to creating a new one. NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.